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