6ca6e8
commit d57cdc1b5a52b5468b9259c0b9a215e22a1fa1f6
6ca6e8
Author: Florian Weimer <fweimer@redhat.com>
6ca6e8
Date:   Tue Nov 8 14:15:02 2022 +0100
6ca6e8
6ca6e8
    Linux: Support __IPC_64 in sysvctl *ctl command arguments (bug 29771)
6ca6e8
    
6ca6e8
    Old applications pass __IPC_64 as part of the command argument because
6ca6e8
    old glibc did not check for unknown commands, and passed through the
6ca6e8
    arguments directly to the kernel, without adding __IPC_64.
6ca6e8
    Applications need to continue doing that for old glibc compatibility,
6ca6e8
    so this commit enables this approach in current glibc.
6ca6e8
    
6ca6e8
    For msgctl and shmctl, if no translation is required, make
6ca6e8
    direct system calls, as we did before the time64 changes.  If
6ca6e8
    translation is required, mask __IPC_64 from the command argument.
6ca6e8
    
6ca6e8
    For semctl, the union-in-vararg argument handling means that
6ca6e8
    translation is needed on all architectures.
6ca6e8
    
6ca6e8
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
6ca6e8
    (cherry picked from commit 22a46dee24351fd5f4f188ad80554cad79c82524)
6ca6e8
6ca6e8
diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h
6ca6e8
index f9852367a466cea9..d4efb9f3483daa9f 100644
6ca6e8
--- a/sysdeps/unix/sysv/linux/ipc_priv.h
6ca6e8
+++ b/sysdeps/unix/sysv/linux/ipc_priv.h
6ca6e8
@@ -63,4 +63,10 @@ struct __old_ipc_perm
6ca6e8
 # define __IPC_TIME64 0
6ca6e8
 #endif
6ca6e8
 
6ca6e8
+#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
+# define IPC_CTL_NEED_TRANSLATION 1
6ca6e8
+#else
6ca6e8
+# define IPC_CTL_NEED_TRANSLATION 0
6ca6e8
+#endif
6ca6e8
+
6ca6e8
 #include <ipc_ops.h>
6ca6e8
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
6ca6e8
index 9f38c06d53936390..ba7b94c22d17bc7f 100644
6ca6e8
--- a/sysdeps/unix/sysv/linux/msgctl.c
6ca6e8
+++ b/sysdeps/unix/sysv/linux/msgctl.c
6ca6e8
@@ -86,11 +86,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
6ca6e8
 int
6ca6e8
 __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
6ca6e8
 {
6ca6e8
-#if __IPC_TIME64
6ca6e8
+#if IPC_CTL_NEED_TRANSLATION
6ca6e8
+# if __IPC_TIME64
6ca6e8
   struct kernel_msqid64_ds ksemid, *arg = NULL;
6ca6e8
-#else
6ca6e8
+# else
6ca6e8
   msgctl_arg_t *arg;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
+
6ca6e8
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
6ca6e8
+     previously unsupported commands back when there was no EINVAL
6ca6e8
+     error checking in glibc.  Mask the flag for the switch statements
6ca6e8
+     below.  msgctl_syscall adds back the __IPC_64 flag for the actual
6ca6e8
+     system call.  */
6ca6e8
+  cmd &= ~__IPC_64;
6ca6e8
 
6ca6e8
   switch (cmd)
6ca6e8
     {
6ca6e8
@@ -102,19 +110,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
6ca6e8
     case IPC_STAT:
6ca6e8
     case MSG_STAT:
6ca6e8
     case MSG_STAT_ANY:
6ca6e8
-#if __IPC_TIME64
6ca6e8
+# if __IPC_TIME64
6ca6e8
       if (buf != NULL)
6ca6e8
 	{
6ca6e8
 	  msqid64_to_kmsqid64 (buf, &ksemid);
6ca6e8
 	  arg = &ksemid;
6ca6e8
 	}
6ca6e8
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
+#  ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
       if (cmd == IPC_SET)
6ca6e8
 	arg->msg_perm.mode *= 0x10000U;
6ca6e8
-# endif
6ca6e8
-#else
6ca6e8
+#  endif
6ca6e8
+# else
6ca6e8
       arg = buf;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
       break;
6ca6e8
 
6ca6e8
     case IPC_INFO:
6ca6e8
@@ -138,21 +146,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
6ca6e8
     case IPC_STAT:
6ca6e8
     case MSG_STAT:
6ca6e8
     case MSG_STAT_ANY:
6ca6e8
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
       arg->msg_perm.mode >>= 16;
6ca6e8
-#else
6ca6e8
+# else
6ca6e8
       /* Old Linux kernel versions might not clear the mode padding.  */
6ca6e8
       if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
6ca6e8
           != sizeof (__kernel_mode_t))
6ca6e8
 	arg->msg_perm.mode &= 0xFFFF;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
 
6ca6e8
-#if __IPC_TIME64
6ca6e8
+# if __IPC_TIME64
6ca6e8
       kmsqid64_to_msqid64 (arg, buf);
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
     }
6ca6e8
 
6ca6e8
   return ret;
6ca6e8
+
6ca6e8
+#else /* !IPC_CTL_NEED_TRANSLATION */
6ca6e8
+  return msgctl_syscall (msqid, cmd, buf);
6ca6e8
+#endif
6ca6e8
 }
6ca6e8
 #if __TIMESIZE != 64
6ca6e8
 libc_hidden_def (__msgctl64)
6ca6e8
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
6ca6e8
index bb2690d30f80bb22..97fa411547fdd81e 100644
6ca6e8
--- a/sysdeps/unix/sysv/linux/semctl.c
6ca6e8
+++ b/sysdeps/unix/sysv/linux/semctl.c
6ca6e8
@@ -141,6 +141,13 @@ __semctl64 (int semid, int semnum, int cmd, ...)
6ca6e8
   union semun64 arg64 = { 0 };
6ca6e8
   va_list ap;
6ca6e8
 
6ca6e8
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
6ca6e8
+     previously unsupported commands back when there was no EINVAL
6ca6e8
+     error checking in glibc.  Mask the flag for the switch statements
6ca6e8
+     below.  semctl_syscall adds back the __IPC_64 flag for the actual
6ca6e8
+     system call.  */
6ca6e8
+  cmd &= ~__IPC_64;
6ca6e8
+
6ca6e8
   /* Get the argument only if required.  */
6ca6e8
   switch (cmd)
6ca6e8
     {
6ca6e8
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
6ca6e8
index f52018bfae4b3364..c44cbd6e4ac890a5 100644
6ca6e8
--- a/sysdeps/unix/sysv/linux/shmctl.c
6ca6e8
+++ b/sysdeps/unix/sysv/linux/shmctl.c
6ca6e8
@@ -86,11 +86,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
6ca6e8
 int
6ca6e8
 __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
6ca6e8
 {
6ca6e8
-#if __IPC_TIME64
6ca6e8
+#if IPC_CTL_NEED_TRANSLATION
6ca6e8
+# if __IPC_TIME64
6ca6e8
   struct kernel_shmid64_ds kshmid, *arg = NULL;
6ca6e8
-#else
6ca6e8
+# else
6ca6e8
   shmctl_arg_t *arg;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
+
6ca6e8
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
6ca6e8
+     previously unsupported commands back when there was no EINVAL
6ca6e8
+     error checking in glibc.  Mask the flag for the switch statements
6ca6e8
+     below.  shmctl_syscall adds back the __IPC_64 flag for the actual
6ca6e8
+     system call.  */
6ca6e8
+  cmd &= ~__IPC_64;
6ca6e8
 
6ca6e8
   switch (cmd)
6ca6e8
     {
6ca6e8
@@ -104,19 +112,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
6ca6e8
     case IPC_STAT:
6ca6e8
     case SHM_STAT:
6ca6e8
     case SHM_STAT_ANY:
6ca6e8
-#if __IPC_TIME64
6ca6e8
+# if __IPC_TIME64
6ca6e8
       if (buf != NULL)
6ca6e8
 	{
6ca6e8
 	  shmid64_to_kshmid64 (buf, &kshmid);
6ca6e8
 	  arg = &kshmid;
6ca6e8
 	}
6ca6e8
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
+#  ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
       if (cmd == IPC_SET)
6ca6e8
         arg->shm_perm.mode *= 0x10000U;
6ca6e8
-# endif
6ca6e8
-#else
6ca6e8
+#  endif
6ca6e8
+# else
6ca6e8
       arg = buf;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
       break;
6ca6e8
 
6ca6e8
     case IPC_INFO:
6ca6e8
@@ -141,21 +149,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
6ca6e8
       case IPC_STAT:
6ca6e8
       case SHM_STAT:
6ca6e8
       case SHM_STAT_ANY:
6ca6e8
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
6ca6e8
         arg->shm_perm.mode >>= 16;
6ca6e8
-#else
6ca6e8
+# else
6ca6e8
       /* Old Linux kernel versions might not clear the mode padding.  */
6ca6e8
       if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
6ca6e8
 	  != sizeof (__kernel_mode_t))
6ca6e8
 	arg->shm_perm.mode &= 0xFFFF;
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
 
6ca6e8
-#if __IPC_TIME64
6ca6e8
+# if __IPC_TIME64
6ca6e8
       kshmid64_to_shmid64 (arg, buf);
6ca6e8
-#endif
6ca6e8
+# endif
6ca6e8
     }
6ca6e8
 
6ca6e8
   return ret;
6ca6e8
+
6ca6e8
+#else /* !IPC_CTL_NEED_TRANSLATION */
6ca6e8
+  return shmctl_syscall (shmid, cmd, buf);
6ca6e8
+#endif
6ca6e8
 }
6ca6e8
 #if __TIMESIZE != 64
6ca6e8
 libc_hidden_def (__shmctl64)