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