diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-06-30 14:08:22 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-07-09 12:05:47 -0300 |
commit | ffd178c651b827f24acead02284abbb12f3f723b (patch) | |
tree | 46ffd4d41f6d03a69ba1062db46afab9cebc5d81 /sysdeps/unix/sysv/linux/shmctl.c | |
parent | 7929d779850aaaf9fd2377ed0945fb53f60dee63 (diff) | |
download | glibc-ffd178c651b827f24acead02284abbb12f3f723b.tar glibc-ffd178c651b827f24acead02284abbb12f3f723b.tar.gz glibc-ffd178c651b827f24acead02284abbb12f3f723b.tar.bz2 glibc-ffd178c651b827f24acead02284abbb12f3f723b.zip |
sysv: linux: Add 64-bit time_t variant for shmctl
To provide a y2038 safe interface a new symbol __shmctl64 is added
and __shmctl is change to call it instead (it adds some extra buffer
copying for the 32 bit time_t implementation).
Two new structures are added:
1. kernel_shmid64_ds: used internally only on 32-bit architectures
to issue the syscall. A handful of architectures (hppa, i386,
mips, powerpc32, and sparc32) require specific implementations
due to their kernel ABI.
2. shmid_ds64: this is only for __TIMESIZE != 64 to use along with
the 64-bit shmctl. It is different than the kernel struct because
the exported 64-bit time_t might require different alignment
depending on the architecture ABI.
So the resulting implementation does:
1. For 64-bit architectures it assumes shmid_ds already contains
64-bit time_t fields and will result in just the __shmctl symbol
using the __shmctl64 code. The shmid_ds argument is passed as-is
to the syscall.
2. For 32-bit architectures with default 64-bit time_t (newer ABIs
such riscv32 or arc), it will also result in only one exported
symbol but with the required high/low time handling.
3. Finally for 32-bit architecture with both 32-bit and 64-bit time_t
support we follow the already set way to provide one symbol with
64-bit time_t support and implement the 32-bit time_t support
using of the 64-bit one.
The default 32-bit symbol will allocate and copy the shmid_ds
over multiple buffers, but this should be deprecated in favor
of the __shmctl64 anyway.
Checked on i686-linux-gnu and x86_64-linux-gnu. I also did some sniff
tests on powerpc, powerpc64, mips, mips64, armhf, sparcv9, and
sparc64.
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Tested-by: Alistair Francis <alistair.francis@wdc.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'sysdeps/unix/sysv/linux/shmctl.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/shmctl.c | 181 |
1 files changed, 147 insertions, 34 deletions
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c index f41b359b8b..76d88441f1 100644 --- a/sysdeps/unix/sysv/linux/shmctl.c +++ b/sysdeps/unix/sysv/linux/shmctl.c @@ -24,16 +24,55 @@ #include <errno.h> #include <linux/posix_types.h> /* For __kernel_mode_t. */ -#ifndef DEFAULT_VERSION -# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T -# define DEFAULT_VERSION GLIBC_2_2 -# else -# define DEFAULT_VERSION GLIBC_2_31 -# endif +/* POSIX states ipc_perm mode should have type of mode_t. */ +_Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode) + == sizeof (mode_t), + "sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)"); + +#if __IPC_TIME64 == 0 +typedef struct shmid_ds shmctl_arg_t; +#else +# include <struct_kernel_shmid64_ds.h> + +static void +shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64, + struct kernel_shmid64_ds *kshmid) +{ + kshmid->shm_perm = shmid64->shm_perm; + kshmid->shm_segsz = shmid64->shm_segsz; + kshmid->shm_atime = shmid64->shm_atime; + kshmid->shm_atime_high = shmid64->shm_atime >> 32; + kshmid->shm_dtime = shmid64->shm_dtime; + kshmid->shm_dtime_high = shmid64->shm_dtime >> 32; + kshmid->shm_ctime = shmid64->shm_ctime; + kshmid->shm_ctime_high = shmid64->shm_ctime >> 32; + kshmid->shm_cpid = shmid64->shm_cpid; + kshmid->shm_lpid = shmid64->shm_lpid; + kshmid->shm_nattch = shmid64->shm_nattch; +} + +static void +kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid, + struct __shmid64_ds *shmid64) +{ + shmid64->shm_perm = kshmid->shm_perm; + shmid64->shm_segsz = kshmid->shm_segsz; + shmid64->shm_atime = kshmid->shm_atime + | ((__time64_t) kshmid->shm_atime_high << 32); + shmid64->shm_dtime = kshmid->shm_dtime + | ((__time64_t) kshmid->shm_dtime_high << 32); + shmid64->shm_ctime = kshmid->shm_ctime + | ((__time64_t) kshmid->shm_ctime_high << 32); + shmid64->shm_cpid = kshmid->shm_cpid; + shmid64->shm_lpid = kshmid->shm_lpid; + shmid64->shm_nattch = kshmid->shm_nattch; +} + +typedef struct kernel_shmid64_ds shmctl_arg_t; #endif static int -shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf) +shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf); @@ -45,46 +84,120 @@ shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf) /* Provide operations to control over shared memory segments. */ int -__new_shmctl (int shmid, int cmd, struct shmid_ds *buf) +__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) { - /* POSIX states ipc_perm mode should have type of mode_t. */ - _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode) - == sizeof (mode_t), - "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)"); - -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - struct shmid_ds tmpds; - if (cmd == IPC_SET) +#if __IPC_TIME64 + struct kernel_shmid64_ds kshmid, *arg = NULL; + if (buf != NULL) { - tmpds = *buf; - tmpds.shm_perm.mode *= 0x10000U; - buf = &tmpds; + shmid64_to_kshmid64 (buf, &kshmid); + arg = &kshmid; } +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->shm_perm.mode *= 0x10000U; +# endif +#else + shmctl_arg_t *arg = buf; #endif - int ret = shmctl_syscall (shmid, cmd, buf); + int ret = shmctl_syscall (shmid, cmd, arg); + if (ret < 0) + return ret; - if (ret >= 0) + switch (cmd) { - switch (cmd) - { - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: + case IPC_INFO: + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - buf->shm_perm.mode >>= 16; + arg->shm_perm.mode >>= 16; #else - /* Old Linux kernel versions might not clear the mode padding. */ - if (sizeof ((struct shmid_ds){0}.shm_perm.mode) - != sizeof (__kernel_mode_t)) - buf->shm_perm.mode &= 0xFFFF; + /* 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 + +#if __IPC_TIME64 + kshmid64_to_shmid64 (arg, buf); #endif - } } return ret; } -versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION); +#if __TIMESIZE != 64 +libc_hidden_def (__shmctl64) + +static void +shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm) +{ + shm64->shm_perm = shm->shm_perm; + shm64->shm_segsz = shm->shm_segsz; + shm64->shm_atime = shm->shm_atime + | ((__time64_t) shm->__shm_atime_high << 32); + shm64->shm_dtime = shm->shm_dtime + | ((__time64_t) shm->__shm_dtime_high << 32); + shm64->shm_ctime = shm->shm_ctime + | ((__time64_t) shm->__shm_ctime_high << 32); + shm64->shm_cpid = shm->shm_cpid; + shm64->shm_lpid = shm->shm_lpid; + shm64->shm_nattch = shm->shm_nattch; +} + +static void +shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64) +{ + shm->shm_perm = shm64->shm_perm; + shm->shm_segsz = shm64->shm_segsz; + shm->shm_atime = shm64->shm_atime; + shm->__shm_atime_high = 0; + shm->shm_dtime = shm64->shm_dtime; + shm->__shm_dtime_high = 0; + shm->shm_ctime = shm64->shm_ctime; + shm->__shm_ctime_high = 0; + shm->shm_cpid = shm64->shm_cpid; + shm->shm_lpid = shm64->shm_lpid; + shm->shm_nattch = shm64->shm_nattch; +} + +int +__shmctl (int shmid, int cmd, struct shmid_ds *buf) +{ + struct __shmid64_ds shmid64, *buf64 = NULL; + if (buf != NULL) + { + shmid_to_shmid64 (&shmid64, buf); + buf64 = &shmid64; + } + + int ret = __shmctl64 (shmid, cmd, buf64); + if (ret < 0) + return ret; + + switch (cmd) + { + case IPC_INFO: + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: + shmid64_to_shmid (buf, buf64); + } + + return ret; +} +#endif + +#ifndef DEFAULT_VERSION +# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T +# define DEFAULT_VERSION GLIBC_2_2 +# else +# define DEFAULT_VERSION GLIBC_2_31 +# endif +#endif + +versioned_symbol (libc, __shmctl, shmctl, DEFAULT_VERSION); #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \ && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31) @@ -92,7 +205,7 @@ int attribute_compat_text_section __shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf) { - return shmctl_syscall (shmid, cmd, buf); + return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf); } compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2); #endif |