8a984d
Rewrite of the following commit but adjusted pre-64-bit time_t
8a984d
conversion. We want to follow the same upstream behaviour and return
8a984d
EINVAL for unknown commands rather than to attempt the command with an
8a984d
argument of {0} which has likely never been tested upstream.
8a984d
8a984d
commit a16d2abd496bd974a88207d5599265aae5ae4880
8a984d
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
8a984d
Date:   Tue Sep 29 14:29:48 2020 -0300
8a984d
8a984d
    sysvipc: Return EINVAL for invalid semctl 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/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
8a984d
index bdf31ca7747fe5a4..03c56c69a5412c82 100644
8a984d
--- a/sysdeps/unix/sysv/linux/semctl.c
8a984d
+++ b/sysdeps/unix/sysv/linux/semctl.c
8a984d
@@ -58,6 +58,15 @@ __new_semctl (int semid, int semnum, int cmd, ...)
8a984d
       arg = va_arg (ap, union semun);
8a984d
       va_end (ap);
8a984d
       break;
8a984d
+    case IPC_RMID:      /* arg ignored.  */
8a984d
+    case GETNCNT:
8a984d
+    case GETPID:
8a984d
+    case GETVAL:
8a984d
+    case GETZCNT:
8a984d
+      break;
8a984d
+    default:
8a984d
+      __set_errno (EINVAL);
8a984d
+      return -1;
8a984d
     }
8a984d
 
8a984d
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
8a984d
diff --git a/sysvipc/test-sysvipc.h b/sysvipc/test-sysvipc.h
8a984d
new file mode 100644
8a984d
index 0000000000000000..d7ed496511c10afb
8a984d
--- /dev/null
8a984d
+++ b/sysvipc/test-sysvipc.h
8a984d
@@ -0,0 +1,85 @@
8a984d
+/* Basic definition for Sysv IPC test functions.
8a984d
+   Copyright (C) 2020 Free Software Foundation, Inc.
8a984d
+   This file is part of the GNU C Library.
8a984d
+
8a984d
+   The GNU C Library is free software; you can redistribute it and/or
8a984d
+   modify it under the terms of the GNU Lesser General Public
8a984d
+   License as published by the Free Software Foundation; either
8a984d
+   version 2.1 of the License, or (at your option) any later version.
8a984d
+
8a984d
+   The GNU C Library is distributed in the hope that it will be useful,
8a984d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
8a984d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
8a984d
+   Lesser General Public License for more details.
8a984d
+
8a984d
+   You should have received a copy of the GNU Lesser General Public
8a984d
+   License along with the GNU C Library; if not, see
8a984d
+   <https://www.gnu.org/licenses/>.  */
8a984d
+
8a984d
+#ifndef _TEST_SYSV_H
8a984d
+#define _TEST_SYSV_H
8a984d
+
8a984d
+#include <sys/ipc.h>
8a984d
+#include <sys/sem.h>
8a984d
+#include <sys/msg.h>
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
+   between message queue, shared memory, and semaphore.  */
8a984d
+static inline int
8a984d
+first_common_invalid_cmd (void)
8a984d
+{
8a984d
+  const int common_cmds[] = {
8a984d
+    IPC_RMID,
8a984d
+    IPC_SET,
8a984d
+    IPC_STAT,
8a984d
+    IPC_INFO,
8a984d
+  };
8a984d
+
8a984d
+  int invalid = 0;
8a984d
+  for (int i = 0; i < array_length (common_cmds); i++)
8a984d
+    {
8a984d
+      if (invalid == common_cmds[i])
8a984d
+	{
8a984d
+	  invalid++;
8a984d
+	  i = 0;
8a984d
+        }
8a984d
+    }
8a984d
+
8a984d
+  return invalid;
8a984d
+}
8a984d
+
8a984d
+/* Return the first invalid command SysV IPC command for semaphore.  */
8a984d
+static inline int
8a984d
+first_sem_invalid_cmd (void)
8a984d
+{
8a984d
+  const int sem_cmds[] = {
8a984d
+    GETPID,
8a984d
+    GETVAL,
8a984d
+    GETALL,
8a984d
+    GETNCNT,
8a984d
+    GETZCNT,
8a984d
+    SETVAL,
8a984d
+    SETALL,
8a984d
+    SEM_STAT,
8a984d
+    SEM_INFO,
8a984d
+#ifdef SEM_STAT_ANY
8a984d
+    SEM_STAT_ANY,
8a984d
+#endif
8a984d
+  };
8a984d
+
8a984d
+  int invalid = first_common_invalid_cmd ();
8a984d
+  for (int i = 0; i < array_length (sem_cmds); i++)
8a984d
+    {
8a984d
+      if (invalid == sem_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-sysvsem.c b/sysvipc/test-sysvsem.c
8a984d
index d197772917a7579d..43a1460ec2b9308f 100644
8a984d
--- a/sysvipc/test-sysvsem.c
8a984d
+++ b/sysvipc/test-sysvsem.c
8a984d
@@ -25,6 +25,8 @@
8a984d
 #include <sys/ipc.h>
8a984d
 #include <sys/sem.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
@@ -80,6 +82,9 @@ do_test (void)
8a984d
       FAIL_EXIT1 ("semget failed (errno=%d)", errno);
8a984d
     }
8a984d
 
8a984d
+  TEST_COMPARE (semctl (semid, 0, first_sem_invalid_cmd (), NULL), -1);
8a984d
+  TEST_COMPARE (errno, EINVAL);
8a984d
+
8a984d
   /* Get semaphore kernel information and do some sanity checks.  */
8a984d
   struct semid_ds seminfo;
8a984d
   if (semctl (semid, 0, IPC_STAT, (union semun) { .buf = &seminfo }) == -1)