forked from pool/glibc
Andreas Schwab
f1d8923af9
- intl-codeset-suffixes.patch: intl: Handle translation output codesets with suffixes (BZ #26383) - strerrorname-np.patch: string: Fix strerrorname_np return value (BZ #26555) - sysvipc.patch: sysvipc: Fix SEM_STAT_ANY kernel argument pass (BZ #26637, BZ #26639, BZ #26636) OBS-URL: https://build.opensuse.org/request/show/847890 OBS-URL: https://build.opensuse.org/package/show/Base:System/glibc?expand=0&rev=572
797 lines
24 KiB
Diff
797 lines
24 KiB
Diff
From 9b139b6b81a5def91bec01f30301acc95fbf0289 Mon Sep 17 00:00:00 2001
|
|
From: "Dmitry V. Levin" <ldv@altlinux.org>
|
|
Date: Tue, 29 Sep 2020 14:10:20 -0300
|
|
Subject: [PATCH] sysvipc: Fix SEM_STAT_ANY kernel argument pass [BZ #26637]
|
|
|
|
Handle SEM_STAT_ANY the same way as SEM_STAT so that the buffer argument
|
|
of SEM_STAT_ANY is properly passed to the kernel and back.
|
|
|
|
The regression testcase checks for Linux specifix SysV ipc message
|
|
control extension. For IPC_INFO/SEM_INFO it tries to match the values
|
|
against the tunable /proc values and for SEM_STAT/SEM_STAT_ANY it
|
|
check if the create message queue is within the global list returned
|
|
by the kernel.
|
|
|
|
Checked on x86_64-linux-gnu and on i686-linux-gnu (Linux v5.4 and on
|
|
Linux v4.15).
|
|
|
|
Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
|
|
(cherry picked from commit 574500a108be1d2a6a0dc97a075c9e0a98371aba)
|
|
|
|
From c4aeedea598a1bd80f52ca9ebd07fe447680d491 Mon Sep 17 00:00:00 2001
|
|
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
Date: Tue, 29 Sep 2020 14:39:56 -0300
|
|
Subject: [PATCH] sysvipc: Fix IPC_INFO and MSG_INFO handling [BZ #26639]
|
|
|
|
Both commands are Linux extensions where the third argument is a
|
|
'struct msginfo' instead of 'struct msqid_ds' and its information
|
|
does not contain any time related fields (so there is no need to
|
|
extra conversion for __IPC_TIME64.
|
|
|
|
The regression testcase checks for Linux specifix SysV ipc message
|
|
control extension. For IPC_INFO/MSG_INFO it tries to match the values
|
|
against the tunable /proc values and for MSG_STAT/MSG_STAT_ANY it
|
|
check if the create message queue is within the global list returned
|
|
by the kernel.
|
|
|
|
Checked on x86_64-linux-gnu and on i686-linux-gnu (Linux v5.4 and on
|
|
Linux v4.15).
|
|
|
|
(cherry picked from commit 20a00dbefca5695cccaa44846a482db8ccdd85ab)
|
|
|
|
From 0b9460d22e285432d232f42c7442a3226e1bf830 Mon Sep 17 00:00:00 2001
|
|
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
Date: Tue, 29 Sep 2020 14:51:36 -0300
|
|
Subject: [PATCH] sysvipc: Fix IPC_INFO and SHM_INFO handling [BZ #26636]
|
|
|
|
Both commands are Linux extensions where the third argument is either
|
|
a 'struct shminfo' (IPC_INFO) or a 'struct shm_info' (SHM_INFO) instead
|
|
of 'struct shmid_ds'. And their information does not contain any time
|
|
related fields, so there is no need to extra conversion for __IPC_TIME64.
|
|
|
|
The regression testcase checks for Linux specifix SysV ipc message
|
|
control extension. For SHM_INFO it tries to match the values against the
|
|
tunable /proc values and for MSG_STAT/MSG_STAT_ANY it check if the create\
|
|
shared memory is within the global list returned by the kernel.
|
|
|
|
Checked on x86_64-linux-gnu and on i686-linux-gnu (Linux v5.4 and on
|
|
Linux v4.15).
|
|
|
|
(cherry picked from commit a49d7fd4f764e97ccaf922e433046590ae52fce9)
|
|
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/Makefile
|
|
===================================================================
|
|
--- glibc-2.32.orig/sysdeps/unix/sysv/linux/Makefile
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/Makefile
|
|
@@ -100,7 +100,7 @@ tests += tst-clone tst-clone2 tst-clone3
|
|
tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
|
|
test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \
|
|
tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \
|
|
- tst-tgkill
|
|
+ tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux
|
|
tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc
|
|
|
|
CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/msgctl.c
|
|
===================================================================
|
|
--- glibc-2.32.orig/sysdeps/unix/sysv/linux/msgctl.c
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/msgctl.c
|
|
@@ -90,8 +90,15 @@ __msgctl64 (int msqid, int cmd, struct _
|
|
struct kernel_msqid64_ds ksemid, *arg = NULL;
|
|
if (buf != NULL)
|
|
{
|
|
- msqid64_to_kmsqid64 (buf, &ksemid);
|
|
- arg = &ksemid;
|
|
+ /* This is a Linux extension where kernel returns a 'struct msginfo'
|
|
+ instead. */
|
|
+ if (cmd == IPC_INFO || cmd == MSG_INFO)
|
|
+ arg = (struct kernel_msqid64_ds *) buf;
|
|
+ else
|
|
+ {
|
|
+ msqid64_to_kmsqid64 (buf, &ksemid);
|
|
+ arg = &ksemid;
|
|
+ }
|
|
}
|
|
# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
|
if (cmd == IPC_SET)
|
|
@@ -169,8 +176,15 @@ __msgctl (int msqid, int cmd, struct msq
|
|
struct __msqid64_ds msqid64, *buf64 = NULL;
|
|
if (buf != NULL)
|
|
{
|
|
- msqid_to_msqid64 (&msqid64, buf);
|
|
- buf64 = &msqid64;
|
|
+ /* This is a Linux extension where kernel returns a 'struct msginfo'
|
|
+ instead. */
|
|
+ if (cmd == IPC_INFO || cmd == MSG_INFO)
|
|
+ buf64 = (struct __msqid64_ds *) buf;
|
|
+ else
|
|
+ {
|
|
+ msqid_to_msqid64 (&msqid64, buf);
|
|
+ buf64 = &msqid64;
|
|
+ }
|
|
}
|
|
|
|
int ret = __msgctl64 (msqid, cmd, buf64);
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/semctl.c
|
|
===================================================================
|
|
--- glibc-2.32.orig/sysdeps/unix/sysv/linux/semctl.c
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/semctl.c
|
|
@@ -102,6 +102,7 @@ semun64_to_ksemun64 (int cmd, union semu
|
|
r.array = semun64.array;
|
|
break;
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_STAT:
|
|
case IPC_SET:
|
|
r.buf = buf;
|
|
@@ -150,6 +151,7 @@ __semctl64 (int semid, int semnum, int c
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
@@ -238,6 +240,7 @@ semun_to_semun64 (int cmd, union semun s
|
|
r.array = semun.array;
|
|
break;
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_STAT:
|
|
case IPC_SET:
|
|
r.buf = semid64;
|
|
@@ -267,6 +270,7 @@ __semctl (int semid, int semnum, int cmd
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
@@ -321,6 +325,7 @@ __semctl_mode16 (int semid, int semnum,
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
@@ -354,6 +359,7 @@ __old_semctl (int semid, int semnum, int
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
+ case SEM_STAT_ANY:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/shmctl.c
|
|
===================================================================
|
|
--- glibc-2.32.orig/sysdeps/unix/sysv/linux/shmctl.c
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/shmctl.c
|
|
@@ -90,8 +90,15 @@ __shmctl64 (int shmid, int cmd, struct _
|
|
struct kernel_shmid64_ds kshmid, *arg = NULL;
|
|
if (buf != NULL)
|
|
{
|
|
- shmid64_to_kshmid64 (buf, &kshmid);
|
|
- arg = &kshmid;
|
|
+ /* This is a Linux extension where kernel expects either a
|
|
+ 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
|
|
+ if (cmd == IPC_INFO || cmd == SHM_INFO)
|
|
+ arg = (struct kernel_shmid64_ds *) buf;
|
|
+ else
|
|
+ {
|
|
+ shmid64_to_kshmid64 (buf, &kshmid);
|
|
+ arg = &kshmid;
|
|
+ }
|
|
}
|
|
# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
|
if (cmd == IPC_SET)
|
|
@@ -107,7 +114,6 @@ __shmctl64 (int shmid, int cmd, struct _
|
|
|
|
switch (cmd)
|
|
{
|
|
- case IPC_INFO:
|
|
case IPC_STAT:
|
|
case SHM_STAT:
|
|
case SHM_STAT_ANY:
|
|
@@ -168,8 +174,15 @@ __shmctl (int shmid, int cmd, struct shm
|
|
struct __shmid64_ds shmid64, *buf64 = NULL;
|
|
if (buf != NULL)
|
|
{
|
|
- shmid_to_shmid64 (&shmid64, buf);
|
|
- buf64 = &shmid64;
|
|
+ /* This is a Linux extension where kernel expects either a
|
|
+ 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
|
|
+ if (cmd == IPC_INFO || cmd == SHM_INFO)
|
|
+ buf64 = (struct __shmid64_ds *) buf;
|
|
+ else
|
|
+ {
|
|
+ shmid_to_shmid64 (&shmid64, buf);
|
|
+ buf64 = &shmid64;
|
|
+ }
|
|
}
|
|
|
|
int ret = __shmctl64 (shmid, cmd, buf64);
|
|
@@ -178,7 +191,6 @@ __shmctl (int shmid, int cmd, struct shm
|
|
|
|
switch (cmd)
|
|
{
|
|
- case IPC_INFO:
|
|
case IPC_STAT:
|
|
case SHM_STAT:
|
|
case SHM_STAT_ANY:
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c
|
|
@@ -0,0 +1,177 @@
|
|
+/* Basic tests for Linux SYSV message queue extensions.
|
|
+ Copyright (C) 2020 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <sys/ipc.h>
|
|
+#include <sys/msg.h>
|
|
+#include <errno.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/temp_file.h>
|
|
+
|
|
+#define MSGQ_MODE 0644
|
|
+
|
|
+/* These are for the temporary file we generate. */
|
|
+static char *name;
|
|
+static int msqid;
|
|
+
|
|
+static void
|
|
+remove_msq (void)
|
|
+{
|
|
+ /* Enforce message queue removal in case of early test failure.
|
|
+ Ignore error since the msg may already have being removed. */
|
|
+ msgctl (msqid, IPC_RMID, NULL);
|
|
+}
|
|
+
|
|
+static void
|
|
+do_prepare (int argc, char *argv[])
|
|
+{
|
|
+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvmsg.", &name) != -1);
|
|
+}
|
|
+
|
|
+#define PREPARE do_prepare
|
|
+
|
|
+struct test_msginfo
|
|
+{
|
|
+ int msgmax;
|
|
+ int msgmnb;
|
|
+ int msgmni;
|
|
+};
|
|
+
|
|
+/* It tries to obtain some system-wide SysV messsage queue information from
|
|
+ /proc to check against IPC_INFO/MSG_INFO. The /proc only returns the
|
|
+ tunables value of MSGMAX, MSGMNB, and MSGMNI.
|
|
+
|
|
+ The kernel also returns constant value for MSGSSZ, MSGSEG and also MSGMAP,
|
|
+ MSGPOOL, and MSGTQL (for IPC_INFO). The issue to check them is they might
|
|
+ change over kernel releases. */
|
|
+
|
|
+static int
|
|
+read_proc_file (const char *file)
|
|
+{
|
|
+ FILE *f = fopen (file, "r");
|
|
+ if (f == NULL)
|
|
+ FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file);
|
|
+
|
|
+ int v;
|
|
+ int r = fscanf (f, "%d", & v);
|
|
+ TEST_VERIFY_EXIT (r == 1);
|
|
+
|
|
+ fclose (f);
|
|
+ return v;
|
|
+}
|
|
+
|
|
+
|
|
+/* Check if the message queue with IDX (index into the kernel's internal
|
|
+ array) matches the one with KEY. The CMD is either MSG_STAT or
|
|
+ MSG_STAT_ANY. */
|
|
+
|
|
+static bool
|
|
+check_msginfo (int idx, key_t key, int cmd)
|
|
+{
|
|
+ struct msqid_ds msginfo;
|
|
+ int mid = msgctl (idx, cmd, &msginfo);
|
|
+ /* Ignore unused array slot returned by the kernel or information from
|
|
+ unknown message queue. */
|
|
+ if ((mid == -1 && errno == EINVAL) || mid != msqid)
|
|
+ return false;
|
|
+
|
|
+ if (mid == -1)
|
|
+ FAIL_EXIT1 ("msgctl with %s failed: %m",
|
|
+ cmd == MSG_STAT ? "MSG_STAT" : "MSG_STAT_ANY");
|
|
+
|
|
+ TEST_COMPARE (msginfo.msg_perm.__key, key);
|
|
+ TEST_COMPARE (msginfo.msg_perm.mode, MSGQ_MODE);
|
|
+ TEST_COMPARE (msginfo.msg_qnum, 0);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ atexit (remove_msq);
|
|
+
|
|
+ key_t key = ftok (name, 'G');
|
|
+ if (key == -1)
|
|
+ FAIL_EXIT1 ("ftok failed: %m");
|
|
+
|
|
+ msqid = msgget (key, MSGQ_MODE | IPC_CREAT);
|
|
+ if (msqid == -1)
|
|
+ FAIL_EXIT1 ("msgget failed: %m");
|
|
+
|
|
+ struct test_msginfo tipcinfo;
|
|
+ tipcinfo.msgmax = read_proc_file ("/proc/sys/kernel/msgmax");
|
|
+ tipcinfo.msgmnb = read_proc_file ("/proc/sys/kernel/msgmnb");
|
|
+ tipcinfo.msgmni = read_proc_file ("/proc/sys/kernel/msgmni");
|
|
+
|
|
+ int msqidx;
|
|
+
|
|
+ {
|
|
+ struct msginfo ipcinfo;
|
|
+ msqidx = msgctl (msqid, IPC_INFO, (struct msqid_ds *) &ipcinfo);
|
|
+ if (msqidx == -1)
|
|
+ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m");
|
|
+
|
|
+ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax);
|
|
+ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb);
|
|
+ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni);
|
|
+ }
|
|
+
|
|
+ /* Same as before but with MSG_INFO. */
|
|
+ {
|
|
+ struct msginfo ipcinfo;
|
|
+ msqidx = msgctl (msqid, MSG_INFO, (struct msqid_ds *) &ipcinfo);
|
|
+ if (msqidx == -1)
|
|
+ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m");
|
|
+
|
|
+ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax);
|
|
+ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb);
|
|
+ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni);
|
|
+ }
|
|
+
|
|
+ /* We check if the created message queue shows in global list. */
|
|
+ bool found = false;
|
|
+ for (int i = 0; i <= msqidx; i++)
|
|
+ {
|
|
+ /* We can't tell apart if MSG_STAT_ANY is not supported (kernel older
|
|
+ than 4.17) or if the index used is invalid. So it just check if the
|
|
+ value returned from a valid call matches the created message
|
|
+ queue. */
|
|
+ check_msginfo (i, key, MSG_STAT_ANY);
|
|
+
|
|
+ if (check_msginfo (i, key, MSG_STAT))
|
|
+ {
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ FAIL_EXIT1 ("msgctl with MSG_STAT/MSG_STAT_ANY could not find the "
|
|
+ "created message queue");
|
|
+
|
|
+ if (msgctl (msqid, IPC_RMID, NULL) == -1)
|
|
+ FAIL_EXIT1 ("msgctl failed");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c
|
|
@@ -0,0 +1,184 @@
|
|
+/* Basic tests for Linux SYSV semaphore extensions.
|
|
+ Copyright (C) 2020 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <sys/ipc.h>
|
|
+#include <sys/sem.h>
|
|
+#include <errno.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/temp_file.h>
|
|
+
|
|
+/* These are for the temporary file we generate. */
|
|
+static char *name;
|
|
+static int semid;
|
|
+
|
|
+static void
|
|
+remove_sem (void)
|
|
+{
|
|
+ /* Enforce message queue removal in case of early test failure.
|
|
+ Ignore error since the sem may already have being removed. */
|
|
+ semctl (semid, 0, IPC_RMID, 0);
|
|
+}
|
|
+
|
|
+static void
|
|
+do_prepare (int argc, char *argv[])
|
|
+{
|
|
+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvsem.", &name) != -1);
|
|
+}
|
|
+
|
|
+#define PREPARE do_prepare
|
|
+
|
|
+#define SEM_MODE 0644
|
|
+
|
|
+union semun
|
|
+{
|
|
+ int val;
|
|
+ struct semid_ds *buf;
|
|
+ unsigned short *array;
|
|
+ struct seminfo *__buf;
|
|
+};
|
|
+
|
|
+struct test_seminfo
|
|
+{
|
|
+ int semmsl;
|
|
+ int semmns;
|
|
+ int semopm;
|
|
+ int semmni;
|
|
+};
|
|
+
|
|
+/* It tries to obtain some system-wide SysV semaphore information from /proc
|
|
+ to check against IPC_INFO/SEM_INFO. The /proc only returns the tunables
|
|
+ value of SEMMSL, SEMMNS, SEMOPM, and SEMMNI.
|
|
+
|
|
+ The kernel also returns constant value for SEMVMX, SEMMNU, SEMMAP, SEMUME,
|
|
+ and also SEMUSZ and SEMAEM (for IPC_INFO). The issue to check them is they
|
|
+ might change over kernel releases. */
|
|
+
|
|
+static void
|
|
+read_sem_stat (struct test_seminfo *tseminfo)
|
|
+{
|
|
+ FILE *f = fopen ("/proc/sys/kernel/sem", "r");
|
|
+ if (f == NULL)
|
|
+ FAIL_UNSUPPORTED ("/proc is not mounted or /proc/sys/kernel/sem is not "
|
|
+ "available");
|
|
+
|
|
+ int r = fscanf (f, "%d %d %d %d",
|
|
+ &tseminfo->semmsl, &tseminfo->semmns, &tseminfo->semopm,
|
|
+ &tseminfo->semmni);
|
|
+ TEST_VERIFY_EXIT (r == 4);
|
|
+
|
|
+ fclose (f);
|
|
+}
|
|
+
|
|
+
|
|
+/* Check if the semaphore with IDX (index into the kernel's internal array)
|
|
+ matches the one with KEY. The CMD is either SEM_STAT or SEM_STAT_ANY. */
|
|
+
|
|
+static bool
|
|
+check_seminfo (int idx, key_t key, int cmd)
|
|
+{
|
|
+ struct semid_ds seminfo;
|
|
+ int sid = semctl (idx, 0, cmd, (union semun) { .buf = &seminfo });
|
|
+ /* Ignore unused array slot returned by the kernel or information from
|
|
+ unknown semaphores. */
|
|
+ if ((sid == -1 && errno == EINVAL) || sid != semid)
|
|
+ return false;
|
|
+
|
|
+ if (sid == -1)
|
|
+ FAIL_EXIT1 ("semctl with SEM_STAT failed (errno=%d)", errno);
|
|
+
|
|
+ TEST_COMPARE (seminfo.sem_perm.__key, key);
|
|
+ TEST_COMPARE (seminfo.sem_perm.mode, SEM_MODE);
|
|
+ TEST_COMPARE (seminfo.sem_nsems, 1);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ atexit (remove_sem);
|
|
+
|
|
+ key_t key = ftok (name, 'G');
|
|
+ if (key == -1)
|
|
+ FAIL_EXIT1 ("ftok failed: %m");
|
|
+
|
|
+ semid = semget (key, 1, IPC_CREAT | IPC_EXCL | SEM_MODE);
|
|
+ if (semid == -1)
|
|
+ FAIL_EXIT1 ("semget failed: %m");
|
|
+
|
|
+ struct test_seminfo tipcinfo;
|
|
+ read_sem_stat (&tipcinfo);
|
|
+
|
|
+ int semidx;
|
|
+
|
|
+ {
|
|
+ struct seminfo ipcinfo;
|
|
+ semidx = semctl (semid, 0, IPC_INFO, (union semun) { .__buf = &ipcinfo });
|
|
+ if (semidx == -1)
|
|
+ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m");
|
|
+
|
|
+ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl);
|
|
+ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns);
|
|
+ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm);
|
|
+ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni);
|
|
+ }
|
|
+
|
|
+ /* Same as before but with SEM_INFO. */
|
|
+ {
|
|
+ struct seminfo ipcinfo;
|
|
+ semidx = semctl (semid, 0, SEM_INFO, (union semun) { .__buf = &ipcinfo });
|
|
+ if (semidx == -1)
|
|
+ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m");
|
|
+
|
|
+ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl);
|
|
+ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns);
|
|
+ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm);
|
|
+ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni);
|
|
+ }
|
|
+
|
|
+ /* We check if the created semaphore shows in the system-wide status. */
|
|
+ bool found = false;
|
|
+ for (int i = 0; i <= semidx; i++)
|
|
+ {
|
|
+ /* We can't tell apart if SEM_STAT_ANY is not supported (kernel older
|
|
+ than 4.17) or if the index used is invalid. So it just check if
|
|
+ value returned from a valid call matches the created semaphore. */
|
|
+ check_seminfo (i, key, SEM_STAT_ANY);
|
|
+
|
|
+ if (check_seminfo (i, key, SEM_STAT))
|
|
+ {
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ FAIL_EXIT1 ("semctl with SEM_STAT/SEM_STAT_ANY could not find the "
|
|
+ "created semaphore");
|
|
+
|
|
+ if (semctl (semid, 0, IPC_RMID, 0) == -1)
|
|
+ FAIL_EXIT1 ("semctl failed: %m");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
Index: glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ glibc-2.32/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c
|
|
@@ -0,0 +1,185 @@
|
|
+/* Basic tests for Linux SYSV shared memory extensions.
|
|
+ Copyright (C) 2020 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <sys/ipc.h>
|
|
+#include <sys/shm.h>
|
|
+#include <errno.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <inttypes.h>
|
|
+#include <limits.h>
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/temp_file.h>
|
|
+
|
|
+#define SHM_MODE 0644
|
|
+
|
|
+/* These are for the temporary file we generate. */
|
|
+static char *name;
|
|
+static int shmid;
|
|
+static long int pgsz;
|
|
+
|
|
+static void
|
|
+remove_shm (void)
|
|
+{
|
|
+ /* Enforce message queue removal in case of early test failure.
|
|
+ Ignore error since the shm may already have being removed. */
|
|
+ shmctl (shmid, IPC_RMID, NULL);
|
|
+}
|
|
+
|
|
+static void
|
|
+do_prepare (int argc, char *argv[])
|
|
+{
|
|
+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvshm.", &name) != -1);
|
|
+}
|
|
+
|
|
+#define PREPARE do_prepare
|
|
+
|
|
+struct test_shminfo
|
|
+{
|
|
+ unsigned long int shmall;
|
|
+ unsigned long int shmmax;
|
|
+ unsigned long int shmmni;
|
|
+};
|
|
+
|
|
+/* It tries to obtain some system-wide SysV shared memory information from
|
|
+ /proc to check against IPC_INFO/SHM_INFO. The /proc only returns the
|
|
+ tunables value of SHMALL, SHMMAX, and SHMMNI. */
|
|
+
|
|
+static uint64_t
|
|
+read_proc_file (const char *file)
|
|
+{
|
|
+ FILE *f = fopen (file, "r");
|
|
+ if (f == NULL)
|
|
+ FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file);
|
|
+
|
|
+ /* Handle 32-bit binaries running on 64-bit kernels. */
|
|
+ uint64_t v;
|
|
+ int r = fscanf (f, "%" SCNu64, &v);
|
|
+ TEST_VERIFY_EXIT (r == 1);
|
|
+
|
|
+ fclose (f);
|
|
+ return v;
|
|
+}
|
|
+
|
|
+
|
|
+/* Check if the message queue with IDX (index into the kernel's internal
|
|
+ array) matches the one with KEY. The CMD is either SHM_STAT or
|
|
+ SHM_STAT_ANY. */
|
|
+
|
|
+static bool
|
|
+check_shminfo (int idx, key_t key, int cmd)
|
|
+{
|
|
+ struct shmid_ds shminfo;
|
|
+ int sid = shmctl (idx, cmd, &shminfo);
|
|
+ /* Ignore unused array slot returned by the kernel or information from
|
|
+ unknown message queue. */
|
|
+ if ((sid == -1 && errno == EINVAL) || sid != shmid)
|
|
+ return false;
|
|
+
|
|
+ if (sid == -1)
|
|
+ FAIL_EXIT1 ("shmctl with %s failed: %m",
|
|
+ cmd == SHM_STAT ? "SHM_STAT" : "SHM_STAT_ANY");
|
|
+
|
|
+ TEST_COMPARE (shminfo.shm_perm.__key, key);
|
|
+ TEST_COMPARE (shminfo.shm_perm.mode, SHM_MODE);
|
|
+ TEST_COMPARE (shminfo.shm_segsz, pgsz);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ atexit (remove_shm);
|
|
+
|
|
+ pgsz = sysconf (_SC_PAGESIZE);
|
|
+ if (pgsz == -1)
|
|
+ FAIL_EXIT1 ("sysconf (_SC_PAGESIZE) failed: %m");
|
|
+
|
|
+ key_t key = ftok (name, 'G');
|
|
+ if (key == -1)
|
|
+ FAIL_EXIT1 ("ftok failed: %m");
|
|
+
|
|
+ shmid = shmget (key, pgsz, IPC_CREAT | IPC_EXCL | SHM_MODE);
|
|
+ if (shmid == -1)
|
|
+ FAIL_EXIT1 ("shmget failed: %m");
|
|
+
|
|
+ struct test_shminfo tipcinfo;
|
|
+ {
|
|
+ uint64_t v = read_proc_file ("/proc/sys/kernel/shmmax");
|
|
+#if LONG_MAX == INT_MAX
|
|
+ /* Kernel explicit clamp the value for shmmax on compat symbol (32-bit
|
|
+ binaries running on 64-bit kernels). */
|
|
+ if (v > INT_MAX)
|
|
+ v = INT_MAX;
|
|
+#endif
|
|
+ tipcinfo.shmmax = v;
|
|
+ }
|
|
+ tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall");
|
|
+ tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni");
|
|
+
|
|
+ int shmidx;
|
|
+
|
|
+ /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info'.
|
|
+ It is tricky to verify its values since the syscall returns system wide
|
|
+ resources consumed by shared memory. The shmctl implementation handles
|
|
+ SHM_INFO as IPC_INFO, so the IPC_INFO test should validate SHM_INFO as
|
|
+ well. */
|
|
+
|
|
+ {
|
|
+ struct shminfo ipcinfo;
|
|
+ shmidx = shmctl (shmid, IPC_INFO, (struct shmid_ds *) &ipcinfo);
|
|
+ if (shmidx == -1)
|
|
+ FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m");
|
|
+
|
|
+ TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall);
|
|
+ TEST_COMPARE (ipcinfo.shmmax, tipcinfo.shmmax);
|
|
+ TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni);
|
|
+ }
|
|
+
|
|
+ /* We check if the created shared memory shows in the global list. */
|
|
+ bool found = false;
|
|
+ for (int i = 0; i <= shmidx; i++)
|
|
+ {
|
|
+ /* We can't tell apart if SHM_STAT_ANY is not supported (kernel older
|
|
+ than 4.17) or if the index used is invalid. So it just check if
|
|
+ value returned from a valid call matches the created message
|
|
+ queue. */
|
|
+ check_shminfo (i, key, SHM_STAT_ANY);
|
|
+
|
|
+ if (check_shminfo (i, key, SHM_STAT))
|
|
+ {
|
|
+ found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ FAIL_EXIT1 ("shmctl with SHM_STAT/SHM_STAT_ANY could not find the "
|
|
+ "created shared memory");
|
|
+
|
|
+ if (shmctl (shmid, IPC_RMID, NULL) == -1)
|
|
+ FAIL_EXIT1 ("shmctl failed");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
Index: glibc-2.32/sysvipc/test-sysvsem.c
|
|
===================================================================
|
|
--- glibc-2.32.orig/sysvipc/test-sysvsem.c
|
|
+++ glibc-2.32/sysvipc/test-sysvsem.c
|
|
@@ -20,6 +20,7 @@
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
+#include <stdbool.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/sem.h>
|