From 9b139b6b81a5def91bec01f30301acc95fbf0289 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" 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 (cherry picked from commit 574500a108be1d2a6a0dc97a075c9e0a98371aba) From c4aeedea598a1bd80f52ca9ebd07fe447680d491 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella 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 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 + . */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 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 + . */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 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 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 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 #include #include +#include #include #include #include