Message ID | 87bkphij87.fsf@oldenburg.str.redhat.com |
---|---|
State | New |
Headers | show |
Series | Linux: Support __IPC_64 in sysvctl *ctl command arguments | expand |
* Florian Weimer via Libc-alpha: > 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. > > Tested on i686-linux-gnu, powerpc64le-linux-gnu, x86_64-linux-gnu. > Built with build-many-glibcs.py. I've filed a bug: Restore IPC_64 support in sysvipc *ctl functions <https://sourceware.org/bugzilla/show_bug.cgi?id=29771> I'm going to reference it in the commit message. Thanks, Florian
On 08/11/22 12:00, Florian Weimer via Libc-alpha wrote: > 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. > > Tested on i686-linux-gnu, powerpc64le-linux-gnu, x86_64-linux-gnu. > Built with build-many-glibcs.py. Sigh, another internal interface that bleed to userpace. The fix sounds reasonable to compatibility, just a typo below. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> > > --- > sysdeps/unix/sysv/linux/ipc_priv.h | 6 ++++++ > sysdeps/unix/sysv/linux/msgctl.c | 38 +++++++++++++++++++++++++------------- > sysdeps/unix/sysv/linux/semctl.c | 7 +++++++ > sysdeps/unix/sysv/linux/shmctl.c | 38 +++++++++++++++++++++++++------------- > 4 files changed, 63 insertions(+), 26 deletions(-) > > diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h > index 87893a6757..2f50c31a8e 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 e824ebb095..67b43c0eff 100644 > --- a/sysdeps/unix/sysv/linux/msgctl.c > +++ b/sysdeps/unix/sysv/linux/msgctl.c > @@ -85,11 +85,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. ,sgctl_syscall adds back the __IPC_64 flag for the actual s/,sgctl_syscall/msgctl_syscall > + system call. */ > + cmd &= ~__IPC_64; > > switch (cmd) > { > @@ -101,19 +109,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: > @@ -137,21 +145,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 77a8130c18..3458b018bc 100644 > --- a/sysdeps/unix/sysv/linux/semctl.c > +++ b/sysdeps/unix/sysv/linux/semctl.c > @@ -140,6 +140,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 ea38935497..f00817a6f6 100644 > --- a/sysdeps/unix/sysv/linux/shmctl.c > +++ b/sysdeps/unix/sysv/linux/shmctl.c > @@ -85,11 +85,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) > { > @@ -103,19 +111,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: > @@ -140,21 +148,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) > > base-commit: 19934d629ee22bbd332f04da4320e4f624c9560c >
* Adhemerval Zanella Netto: > On 08/11/22 12:00, Florian Weimer via Libc-alpha wrote: >> 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. >> >> Tested on i686-linux-gnu, powerpc64le-linux-gnu, x86_64-linux-gnu. >> Built with build-many-glibcs.py. > > Sigh, another internal interface that bleed to userpace. The fix sounds > reasonable to compatibility, just a typo below. > > Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Thanks, pushed with the typo fix. Florian
diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h index 87893a6757..2f50c31a8e 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 e824ebb095..67b43c0eff 100644 --- a/sysdeps/unix/sysv/linux/msgctl.c +++ b/sysdeps/unix/sysv/linux/msgctl.c @@ -85,11 +85,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. ,sgctl_syscall adds back the __IPC_64 flag for the actual + system call. */ + cmd &= ~__IPC_64; switch (cmd) { @@ -101,19 +109,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: @@ -137,21 +145,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 77a8130c18..3458b018bc 100644 --- a/sysdeps/unix/sysv/linux/semctl.c +++ b/sysdeps/unix/sysv/linux/semctl.c @@ -140,6 +140,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 ea38935497..f00817a6f6 100644 --- a/sysdeps/unix/sysv/linux/shmctl.c +++ b/sysdeps/unix/sysv/linux/shmctl.c @@ -85,11 +85,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) { @@ -103,19 +111,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: @@ -140,21 +148,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)