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