public inbox for libc-stable@sourceware.org
 help / color / mirror / Atom feed
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-stable@sourceware.org
Subject: [COMMITTED 1/3] sysvipc: Fix SEM_STAT_ANY kernel argument pass [BZ #26637]
Date: Thu, 15 Oct 2020 10:59:48 -0300	[thread overview]
Message-ID: <20201015135950.252855-1-adhemerval.zanella@linaro.org> (raw)

From: "Dmitry V. Levin" <ldv@altlinux.org>

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)
---
 NEWS                                        |   2 +
 sysdeps/unix/sysv/linux/Makefile            |   2 +-
 sysdeps/unix/sysv/linux/semctl.c            |   6 +
 sysdeps/unix/sysv/linux/tst-sysvsem-linux.c | 184 ++++++++++++++++++++
 sysvipc/test-sysvsem.c                      |   1 +
 5 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 sysdeps/unix/sysv/linux/tst-sysvsem-linux.c

diff --git a/NEWS b/NEWS
index 3aad30baee..fb3a9e4f7d 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ The following bugs are resolved with this release:
   [26534] libm.so 2.32 SIGILL in pow() due to FMA4 instruction on non-FMA4
     system
   [26555] string: strerrorname_np does not return the documented value
+  [26637] libc: semctl SEM_STAT_ANY fails to pass the buffer specified
+    by the caller to the kernel
 
 Version 2.32
 
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 9b2a253032..9b930e7466 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -100,7 +100,7 @@ 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-gettid tst-gettid-kill \
-	 tst-tgkill
+	 tst-tgkill tst-sysvsem-linux
 tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc
 
 CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
index f131a26fc7..1cdabde8f2 100644
--- a/sysdeps/unix/sysv/linux/semctl.c
+++ b/sysdeps/unix/sysv/linux/semctl.c
@@ -102,6 +102,7 @@ semun64_to_ksemun64 (int cmd, union semun64 semun64,
       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 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);
@@ -238,6 +240,7 @@ semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64)
       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, 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);
@@ -354,6 +359,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 0000000000..45f19e2d37
--- /dev/null
+++ b/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>
diff --git a/sysvipc/test-sysvsem.c b/sysvipc/test-sysvsem.c
index 01dbff343a..b7284e0b48 100644
--- a/sysvipc/test-sysvsem.c
+++ b/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>
-- 
2.25.1


             reply	other threads:[~2020-10-15 14:00 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-15 13:59 Adhemerval Zanella [this message]
2020-10-15 13:59 ` [COMMITTED 2/3] sysvipc: Fix IPC_INFO and MSG_INFO handling [BZ #26639] Adhemerval Zanella
2020-10-15 13:59 ` [COMMITTED 3/3] sysvipc: Fix IPC_INFO and SHM_INFO handling [BZ #26636] Adhemerval Zanella

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201015135950.252855-1-adhemerval.zanella@linaro.org \
    --to=adhemerval.zanella@linaro.org \
    --cc=libc-stable@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).