8a984d
Rewrite of the following commit to support returning EINVAL for unknown
8a984d
commands and therefore match upstream behaviour.
8a984d
8a984d
commit 9ebaabeaac1a96b0d91f52902ce1dbf4f5a562dd
8a984d
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
8a984d
Date:   Tue Sep 29 14:55:02 2020 -0300
8a984d
8a984d
    sysvipc: Return EINVAL for invalid shmctl commands
8a984d
    
8a984d
    It avoids regressions on possible future commands that might require
8a984d
    additional libc support.  The downside is new commands added by newer
8a984d
    kernels will need further glibc support.
8a984d
    
8a984d
    Checked on x86_64-linux-gnu and i686-linux-gnu (Linux v4.15 and v5.4).
8a984d
8a984d
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
8a984d
index 25c5152944a6fcf3..00768bc47614f9aa 100644
8a984d
--- a/sysdeps/unix/sysv/linux/shmctl.c
8a984d
+++ b/sysdeps/unix/sysv/linux/shmctl.c
8a984d
@@ -33,6 +33,22 @@
8a984d
 int
8a984d
 __new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
8a984d
 {
8a984d
+  switch (cmd)
8a984d
+    {
8a984d
+    case IPC_RMID:
8a984d
+    case SHM_LOCK:
8a984d
+    case SHM_UNLOCK:
8a984d
+    case IPC_SET:
8a984d
+    case IPC_STAT:
8a984d
+    case SHM_STAT:
8a984d
+    case SHM_STAT_ANY:
8a984d
+    case IPC_INFO:
8a984d
+    case SHM_INFO:
8a984d
+      break;
8a984d
+    default:
8a984d
+      __set_errno (EINVAL);
8a984d
+      break;
8a984d
+    }
8a984d
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
8a984d
   return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
8a984d
 #else
8a984d
diff --git a/sysvipc/test-sysvipc.h b/sysvipc/test-sysvipc.h
8a984d
index 21ef6c656581519e..d1c8349b45b5ce49 100644
8a984d
--- a/sysvipc/test-sysvipc.h
8a984d
+++ b/sysvipc/test-sysvipc.h
8a984d
@@ -25,7 +25,7 @@
8a984d
 #include <sys/shm.h>
8a984d
 #include <include/array_length.h>
8a984d
 
8a984d
-/* Return the first invalid command SysV IPC command from common shared
8a984d
+/* Return the first invalid SysV IPC command from common shared
8a984d
    between message queue, shared memory, and semaphore.  */
8a984d
 static inline int
8a984d
 first_common_invalid_cmd (void)
8a984d
@@ -50,7 +50,7 @@ first_common_invalid_cmd (void)
8a984d
   return invalid;
8a984d
 }
8a984d
 
8a984d
-/* Return the first invalid command SysV IPC command for semaphore.  */
8a984d
+/* Return the first invalid SysV IPC command for semaphore.  */
8a984d
 static inline int
8a984d
 first_sem_invalid_cmd (void)
8a984d
 {
8a984d
@@ -82,7 +82,7 @@ first_sem_invalid_cmd (void)
8a984d
   return invalid;
8a984d
 }
8a984d
 
8a984d
-/* Return the first invalid command SysV IPC command for message queue.  */
8a984d
+/* Return the first invalid SysV IPC command for message queue.  */
8a984d
 static inline int
8a984d
 first_msg_invalid_cmd (void)
8a984d
 {
8a984d
@@ -107,4 +107,31 @@ first_msg_invalid_cmd (void)
8a984d
   return invalid;
8a984d
 }
8a984d
 
8a984d
+/* Return the first invalid SysV IPC command for shared memory.  */
8a984d
+static inline int
8a984d
+first_shm_invalid_cmd (void)
8a984d
+{
8a984d
+  const int shm_cmds[] = {
8a984d
+    SHM_STAT,
8a984d
+    SHM_INFO,
8a984d
+#ifdef SHM_STAT_ANY
8a984d
+    SHM_STAT_ANY,
8a984d
+#endif
8a984d
+    SHM_LOCK,
8a984d
+    SHM_UNLOCK
8a984d
+  };
8a984d
+
8a984d
+  int invalid = first_common_invalid_cmd ();
8a984d
+  for (int i = 0; i < array_length (shm_cmds); i++)
8a984d
+    {
8a984d
+      if (invalid == shm_cmds[i])
8a984d
+	{
8a984d
+	  invalid++;
8a984d
+	  i = 0;
8a984d
+	}
8a984d
+    }
8a984d
+
8a984d
+  return invalid;
8a984d
+}
8a984d
+
8a984d
 #endif /* _TEST_SYSV_H  */
8a984d
diff --git a/sysvipc/test-sysvshm.c b/sysvipc/test-sysvshm.c
8a984d
index a7c2e0bd4065dbcd..0fdfddf8550413e4 100644
8a984d
--- a/sysvipc/test-sysvshm.c
8a984d
+++ b/sysvipc/test-sysvshm.c
8a984d
@@ -25,6 +25,8 @@
8a984d
 #include <sys/ipc.h>
8a984d
 #include <sys/shm.h>
8a984d
 
8a984d
+#include <test-sysvipc.h>
8a984d
+
8a984d
 #include <support/support.h>
8a984d
 #include <support/check.h>
8a984d
 #include <support/temp_file.h>
8a984d
@@ -81,6 +83,9 @@ do_test (void)
8a984d
       FAIL_EXIT1 ("shmget failed (errno=%d)", errno);
8a984d
     }
8a984d
 
8a984d
+  TEST_COMPARE (shmctl (shmid, first_shm_invalid_cmd (), NULL), -1);
8a984d
+  TEST_COMPARE (errno, EINVAL);
8a984d
+
8a984d
   /* Get shared memory kernel information and do some sanity checks.  */
8a984d
   struct shmid_ds shminfo;
8a984d
   if (shmctl (shmid, IPC_STAT, &shminfo) == -1)