summaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/shmctl.c
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-06-30 14:08:22 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-07-09 12:05:47 -0300
commitffd178c651b827f24acead02284abbb12f3f723b (patch)
tree46ffd4d41f6d03a69ba1062db46afab9cebc5d81 /sysdeps/unix/sysv/linux/shmctl.c
parent7929d779850aaaf9fd2377ed0945fb53f60dee63 (diff)
downloadglibc-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.c181
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