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