From patchwork Mon Sep 28 14:45:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 1372672 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=libc-alpha-bounces@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=sourceware.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=O8YiQAaB; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4C0QMM26myz9s0b for ; Tue, 29 Sep 2020 00:46:39 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3483039540ED; Mon, 28 Sep 2020 14:46:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3483039540ED DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1601304374; bh=bsgj/lNez501u/spf9qNHd71IgIa48hZWhJ9HTArR+8=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=O8YiQAaBzLiDBlUKp9N2zum08pOkXBmrfzsgrf9oMd5xVPqa5JyZ9ed+RXEK/f5Hf N/axgAf34UemtQZNca8PCI9fOKHvLOt5T4S+9zNWjvSH+J19G9Uo6qg4r/rwGTu8M8 sV1AC5ISwmGaedEEit21J2tqoAy4tDDBsGdyXODk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf44.google.com (mail-qv1-xf44.google.com [IPv6:2607:f8b0:4864:20::f44]) by sourceware.org (Postfix) with ESMTPS id 0E26939540E7 for ; Mon, 28 Sep 2020 14:46:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0E26939540E7 Received: by mail-qv1-xf44.google.com with SMTP id p15so568983qvk.5 for ; Mon, 28 Sep 2020 07:46:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bsgj/lNez501u/spf9qNHd71IgIa48hZWhJ9HTArR+8=; b=ASUUUZnWJpHCuuCxPaJho7N/K0PizdfPU+SxAQLAcN6iPd0Ea4pzb6zNJO2DTilMAy M0ZT4npQP+KyYF4c67YK1QOOh0UmvrD3/n7lLZAlxntDWkSAi4DOEbzWkvIAyougUldH 7thd67HcgP+WJM9FeMzuFk80gzFiLuXItGJbkujyfXyi1nNleKgl64OKdjDJQs+rlb5f CtKOTYbbUfDy4p0t0c03hthbXPpxVl6ovmElIg6QkeN3j78zqqbLZUbR8p8xhuOAQ7jb seZ5En1DzfUT5wvc+y8qILPwiF6oGm4i/M0JXBE2YQiIBwLCwj1qh3aB5YYNElsTxu1X EqBg== X-Gm-Message-State: AOAM533d9HwabouwcMJDFN+4tAmg4VIjLwUkIaaZRn2PAG1LzQmfIo6z Li5k76pvd2FaWtdFyKLIo0/rZ7o3YDU//Q== X-Google-Smtp-Source: ABdhPJzIlhyukcFtTvBJ1ydyJ0BYCFWIYKp3BebNtNQF4pz4Jd+VI2hIkGesW9aW25j3+bUQGJi5/g== X-Received: by 2002:a05:6214:1752:: with SMTP id dc18mr12516401qvb.10.1601304370090; Mon, 28 Sep 2020 07:46:10 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id j25sm1335782qtr.83.2020.09.28.07.46.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2020 07:46:09 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH 5/6] sysvipc: Fix IPC_INFO and SHM_INFO handling [BZ #26636] Date: Mon, 28 Sep 2020 11:45:55 -0300 Message-Id: <20200928144556.239160-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200928144556.239160-1-adhemerval.zanella@linaro.org> References: <20200928144556.239160-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Cc: Robert O'Callahan , "Dmitry V . Levin" Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" 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). --- sysdeps/unix/sysv/linux/Makefile | 2 +- sysdeps/unix/sysv/linux/shmctl.c | 24 ++- sysdeps/unix/sysv/linux/tst-sysvshm-linux.c | 195 ++++++++++++++++++++ 3 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/tst-sysvshm-linux.c diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index a54eb75d74..5a78614457 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -101,7 +101,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-sysvsem-linux tst-sysvmsg-linux + 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 diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c index 76d88441f1..1d19a798b1 100644 --- a/sysdeps/unix/sysv/linux/shmctl.c +++ b/sysdeps/unix/sysv/linux/shmctl.c @@ -90,8 +90,15 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) 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 __shmid64_ds *buf) 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 shmid_ds *buf) 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 shmid_ds *buf) switch (cmd) { - case IPC_INFO: case IPC_STAT: case SHM_STAT: case SHM_STAT_ANY: diff --git a/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c b/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c new file mode 100644 index 0000000000..0e89b5eeff --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c @@ -0,0 +1,195 @@ +/* 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 + +#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 shmall; + unsigned long shmmax; + unsigned long 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 unsigned long +read_proc_file (const char *file) +{ + FILE *f = fopen (file, "r"); + if (f == NULL) + return -1; + + unsigned long v; + int r = fscanf (f, "%lu", & v); + TEST_VERIFY_EXIT (r == 1); + + fclose (f); + return v; +} + +static bool +read_shm_stat (struct test_shminfo *tipcinfo) +{ + tipcinfo->shmall = read_proc_file ("/proc/sys/kernel/shmall"); + if (tipcinfo->shmall == -1) + return false; + tipcinfo->shmmax = read_proc_file ("/proc/sys/kernel/shmmax"); + if (tipcinfo->shmmax == -1) + return false; + tipcinfo->shmmni = read_proc_file ("/proc/sys/kernel/shmmni"); + if (tipcinfo->shmmni == -1) + return false; + return true; +} + + +/* 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"); + + if (shminfo.shm_perm.__key != key) + FAIL_EXIT1 ("shmid_ds::shm_perm::key (%d) != %d", + (int) shminfo.shm_perm.__key, (int) key); + if (shminfo.shm_perm.mode != SHM_MODE) + FAIL_EXIT1 ("shmid_ds::shm_perm::mode (%o) != %o", + shminfo.shm_perm.mode, SHM_MODE); + if (shminfo.shm_segsz != pgsz) + FAIL_EXIT1 ("shmid_ds::shm_segsz (%lu) != %lu", + (long unsigned) 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; + bool tipcget = read_shm_stat (&tipcinfo); + + int shmidx; + + /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info' + and it is tricky to verify it since it returns system 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"); + + /* We only check if /proc is mounted. */ + if (tipcget) + { + 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++) + { + if (check_shminfo (i, key, SHM_STAT)) + { + found = true; + break; + } + + /* 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 (!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