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