| Conflicts in sysdeps/unix/sysv/linux/semctl.c were due to 64-bit time_t |
| and RHEL8 has a simpler implementation. |
| |
| Conflicts in sysdeps/unix/sysv/linux/Makefile were due to the usual test |
| case conflicts. |
| |
| commit 574500a108be1d2a6a0dc97a075c9e0a98371aba |
| Author: Dmitry V. Levin <ldv@altlinux.org> |
| Date: Tue Sep 29 14:10:20 2020 -0300 |
| |
| 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> |
| |
| # Conflicts: |
| # sysdeps/unix/sysv/linux/Makefile |
| # sysdeps/unix/sysv/linux/semctl.c |
| |
| diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile |
| index fb4ccd63ddec7eca..c6907796152eb09d 100644 |
| |
| |
| @@ -45,7 +45,8 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \ |
| tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ |
| 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-rlimit-infinity tst-ofdlocks \ |
| + tst-sysvsem-linux |
| tests-internal += tst-ofdlocks-compat |
| |
| |
| diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c |
| index e2925447eba2ee94..bdf31ca7747fe5a4 100644 |
| |
| |
| @@ -51,6 +51,7 @@ __new_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); |
| @@ -90,6 +91,7 @@ __old_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); |
| diff --git a/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c b/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c |
| new file mode 100644 |
| index 0000000000000000..45f19e2d37ed194a |
| |
| |
| @@ -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> |
| diff --git a/sysvipc/test-sysvsem.c b/sysvipc/test-sysvsem.c |
| index a8e9bff000949ff8..d197772917a7579d 100644 |
| |
| |
| @@ -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> |