diff options
Diffstat (limited to 'testcases')
494 files changed, 10546 insertions, 16610 deletions
diff --git a/testcases/commands/df/df01.sh b/testcases/commands/df/df01.sh index ae0449c3c..5af4f68e6 100755 --- a/testcases/commands/df/df01.sh +++ b/testcases/commands/df/df01.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2015 Fujitsu Ltd. -# Copyright (c) 2018-2022 Petr Vorel <pvorel@suse.cz> +# Copyright (c) 2018-2023 Petr Vorel <pvorel@suse.cz> # Author: Zhang Jin <jy_zhangjin@cn.fujitsu.com> # # Test df command with some basic options. @@ -46,6 +46,11 @@ df_test() ROD_SILENT rm -rf $TST_MNTPOINT/testimg + # force all the background garbage collection to run to completion + if [ "$TST_FS_TYPE" = "xfs" ]; then + tst_fsfreeze $TST_MNTPOINT + fi + # flush file system buffers, then we can get the actual sizes. sync } diff --git a/testcases/commands/eject/eject-tests.sh b/testcases/commands/eject/eject-tests.sh index 7b916cfb6..76a667aa3 100755 --- a/testcases/commands/eject/eject-tests.sh +++ b/testcases/commands/eject/eject-tests.sh @@ -99,7 +99,7 @@ test3() if grep -q "$CD_DRIVE" /proc/mounts; then tst_res TFAIL "$CD_DRIVE is stil moutned" else - tst_res TPASS "$CD_DRIVE umounted succesfully" + tst_res TPASS "$CD_DRIVE umounted successfully" fi } diff --git a/testcases/commands/file/datafiles/in.csh b/testcases/commands/file/datafiles/in.csh deleted file mode 100644 index c475aef9c..000000000 --- a/testcases/commands/file/datafiles/in.csh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/csh - -echo "this is a shell script" -echo "used to test file command" diff --git a/testcases/commands/file/datafiles/in.ksh b/testcases/commands/file/datafiles/in.ksh deleted file mode 100644 index 3ae45125c..000000000 --- a/testcases/commands/file/datafiles/in.ksh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/ksh - -echo "this is a shell script" -echo "used to test file command" diff --git a/testcases/commands/file/file01.sh b/testcases/commands/file/file01.sh index df152b656..f0c129f33 100755 --- a/testcases/commands/file/file01.sh +++ b/testcases/commands/file/file01.sh @@ -2,12 +2,13 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2001 # Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> +# Copyright (c) Linux Test Project, 2017-2023 # # This program tests the file command. The tests are aimed at # testing if the file command can recognize some of the commonly # used file formats like, tar, tar.gz, rpm, C, ASCII, ELF etc. -TST_CNT=20 +TST_CNT=18 TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 @@ -61,30 +62,28 @@ do_test() "POSIX shell script text executable" \ "POSIX shell script text" \ "Bourne shell script text executable";; - 4) file_test in.ksh "Korn shell script";; - 5) file_test in.csh "C shell script";; - 6) file_test in.c "ASCII C program text" "C source, ASCII text";; - 7) file_test in.pl "[pP]erl script, ASCII text executable" \ + 4) file_test in.c "ASCII C program text" "C source, ASCII text";; + 5) file_test in.pl "[pP]erl script, ASCII text executable" \ "[pP]erl script text executable" \ "a /usr/bin/perl script text";; - 8) file_test in.py "[pP]ython3\{0,1\} script, ASCII text executable" \ + 6) file_test in.py "[pP]ython3\{0,1\} script, ASCII text executable" \ "[pP]ython3\{0,1\} script text executable";; - 9) file_test in.m4 "M4 macro processor script, ASCII text" \ + 7) file_test in.m4 "M4 macro processor script, ASCII text" \ "ASCII M4 macro language pre-processor text";; - 10) file_test in "ELF .*-bit $TEST_ARCH executable, .*" \ + 8) file_test in "ELF .*-bit $TEST_ARCH executable, .*" \ "ELF .*-bit $TEST_ARCH shared object, .*" \ "ELF .*-bit $TEST_ARCH pie executable, .*" \ "ELF .*-bit $TEST_ARCH pie shared object, .*";; - 11) file_test in.ar "current ar archive";; - 12) file_test in.tar "tar archive";; - 13) file_test in.tar.gz "gzip compressed data, .*";; - 14) file_test in.tar.bz2 "bzip2 compressed data, .*";; - 15) file_test in.src.rpm "RPM v3 src" "RPM v3.0 src";; - 16) file_test in.jpg "JPEG image data";; - 17) file_test in.png "PNG image data";; - 18) file_test in.wav "RIFF (little-endian) data, WAVE audio, Microsoft PCM";; - 19) file_test in.mp3 "MPEG ADTS, layer III";; - 20) file_test in.zip "Zip archive data";; + 9) file_test in.ar "current ar archive";; + 10) file_test in.tar "tar archive";; + 11) file_test in.tar.gz "gzip compressed data, .*";; + 12) file_test in.tar.bz2 "bzip2 compressed data, .*";; + 13) file_test in.src.rpm "RPM v3 src" "RPM v3.0 src";; + 14) file_test in.jpg "JPEG image data";; + 15) file_test in.png "PNG image data";; + 16) file_test in.wav "RIFF (little-endian) data, WAVE audio, Microsoft PCM";; + 17) file_test in.mp3 "MPEG ADTS, layer III";; + 18) file_test in.zip "Zip archive data";; esac } diff --git a/testcases/commands/insmod/insmod01.sh b/testcases/commands/insmod/insmod01.sh index 1881ba389..992b4a05a 100755 --- a/testcases/commands/insmod/insmod01.sh +++ b/testcases/commands/insmod/insmod01.sh @@ -1,6 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2016 Fujitsu Ltd. +# Copyright (c) Linux Test Project, 2016-2023 # Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> # # Test basic functionality of insmod command. @@ -10,6 +11,8 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="rmmod insmod" TST_NEEDS_MODULE="ltp_insmod01.ko" +TST_SKIP_IN_LOCKDOWN=1 +TST_SKIP_IN_SECUREBOOT=1 inserted=0 diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore index 90e8b191c..3a2b2bed6 100644 --- a/testcases/cve/.gitignore +++ b/testcases/cve/.gitignore @@ -12,3 +12,4 @@ cve-2017-16939 cve-2017-17053 cve-2022-4378 icmp_rate_limit01 +tcindex01 diff --git a/testcases/cve/cve-2015-3290.c b/testcases/cve/cve-2015-3290.c index f61d2809b..a2a8fcedd 100644 --- a/testcases/cve/cve-2015-3290.c +++ b/testcases/cve/cve-2015-3290.c @@ -195,7 +195,8 @@ static void set_ldt(void) .useable = 0 }; - TEST(tst_syscall(__NR_modify_ldt, 1, &data_desc, sizeof(data_desc))); + TEST((int)tst_syscall(__NR_modify_ldt, 1, &data_desc, + sizeof(data_desc))); if (TST_RET == -EINVAL) { tst_brk(TCONF | TRERRNO, "modify_ldt: 16-bit data segments are probably disabled"); diff --git a/testcases/cve/cve-2016-10044.c b/testcases/cve/cve-2016-10044.c index 9ac644fc2..6a8c77f3e 100644 --- a/testcases/cve/cve-2016-10044.c +++ b/testcases/cve/cve-2016-10044.c @@ -19,7 +19,7 @@ #include "tst_safe_stdio.h" #include "lapi/syscalls.h" -static FILE *f; +static FILE * f; static void cleanup(void) { @@ -29,7 +29,7 @@ static void cleanup(void) static void run(void) { - void* ctx = 0; + void *ctx = 0; char perms[8], line[BUFSIZ]; SAFE_PERSONALITY(READ_IMPLIES_EXEC); @@ -44,7 +44,7 @@ static void run(void) tst_brk(TCONF, "Could not find mapping in /proc/self/maps"); found_mapping: - if (sscanf(line, "%*x-%*x %s7", perms) < 0) + if (sscanf(line, "%*x-%*x %s", perms) != 1) tst_brk(TBROK, "failed to find permission string in %s", line); if (strchr(perms, (int)'x')) tst_res(TFAIL, "AIO mapping is executable: %s!", perms); diff --git a/testcases/cve/stack_clash.c b/testcases/cve/stack_clash.c index cd7f148c2..3a99c49bb 100644 --- a/testcases/cve/stack_clash.c +++ b/testcases/cve/stack_clash.c @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Pavel Boldin <pboldin@cloudlinux.com> + * Copyright (c) 2023 Rick Edgecombe <rick.p.edgecombe@intel.com> + * Copyright (c) Linux Test Project, 2017-2023 */ -/* This is a regression test of the Stack Clash [1] vulnerability. This tests +/*\ + * [Description] + * + * This is a regression test of the Stack Clash [1] vulnerability. This tests * that there is at least 256 PAGE_SIZE of stack guard gap which is considered * hard to hop above. Code adapted from the Novell's bugzilla [2]. * @@ -18,11 +23,19 @@ * to infinity and preallocate REQ_STACK_SIZE bytes of stack so that no calls * after `mmap` are moving stack further. * + * If the architecture meets certain requirements (only x86_64 is verified) + * then the test also tests that new mmap()s can't be placed in the stack's + * guard gap. This part of the test works by forcing a bottom up search. The + * assumptions are that the stack grows down (start gap) and either: + * + * 1. The default search is top down, and will switch to bottom up if + * space is exhausted. + * 2. The default search is bottom up and the stack is above mmap base. + * * [1] https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash * [2] https://bugzilla.novell.com/show_bug.cgi?id=CVE-2017-1000364 */ -#include <sys/mman.h> #include <sys/wait.h> #include <stdio.h> #include <unistd.h> @@ -32,6 +45,7 @@ #include "tst_test.h" #include "tst_safe_stdio.h" +#include "lapi/mmap.h" static unsigned long page_size; static unsigned long page_mask; @@ -78,6 +92,49 @@ void segv_handler(int sig, siginfo_t *info, void *data LTP_ATTRIBUTE_UNUSED) _exit(EXIT_SUCCESS); } +static void force_bottom_up(void) +{ + FILE *fh; + char buf[1024]; + unsigned long start, end, size, lastend = 0; + + /* start filling from mmap_min_addr */ + SAFE_FILE_SCANF("/proc/sys/vm/mmap_min_addr", "%lu", &lastend); + + fh = SAFE_FOPEN("/proc/self/maps", "r"); + + while (!feof(fh)) { + if (fgets(buf, sizeof(buf), fh) == NULL) + goto out; + + if (sscanf(buf, "%lx-%lx", &start, &end) != 2) { + tst_brk(TBROK | TERRNO, "sscanf"); + goto out; + } + + size = start - lastend; + + /* Skip the PROT_NONE that was just added (!size). */ + if (!size) { + lastend = end; + continue; + } + + /* If the next area is the stack, quit. */ + if (!!strstr(buf, "[stack]")) + break; + + /* This is not cleaned up. */ + SAFE_MMAP((void *)lastend, size, PROT_NONE, + MAP_ANON|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0); + + lastend = end; + } + +out: + SAFE_FCLOSE(fh); +} + unsigned long read_stack_addr_from_proc(unsigned long *stack_size) { FILE *fh; @@ -130,6 +187,28 @@ void __attribute__((noinline)) preallocate_stack(unsigned long required) garbage[0] = garbage[required - 1] = '\0'; } +static void do_mmap_placement_test(unsigned long stack_addr, unsigned long gap) +{ + void *map_test_gap; + + force_bottom_up(); + + /* + * force_bottom_up() used up all the spaces below the stack. The search down + * path should fail, and search up might take a look at the guard gap + * region. If it avoids it, the allocation will be above the stack. If it + * uses it, the allocation will be in the gap and the test should fail. + */ + map_test_gap = SAFE_MMAP(0, MAPPED_LEN, + PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); + + if (stack_addr - gap <= (unsigned long)map_test_gap && + (unsigned long)map_test_gap <= stack_addr) { + tst_res(TFAIL, "New mmap was placed in the guard gap."); + SAFE_MUNMAP(map_test_gap, MAPPED_LEN); + } +} + void do_child(void) { unsigned long stack_addr, stack_size; @@ -179,6 +258,11 @@ void do_child(void) dump_proc_self_maps(); #endif +#ifdef __x86_64__ + do_mmap_placement_test(stack_addr, gap); +#endif + + /* Now see if it can grow too close to an adjacent region. */ exhaust_stack_into_sigsegv(); } @@ -252,6 +336,7 @@ static struct tst_test test = { .test_all = stack_clash_test, .tags = (const struct tst_tag[]) { {"CVE", "2017-1000364"}, + {"linux-git", "58c5d0d6d522"}, {} } }; diff --git a/testcases/cve/tcindex01.c b/testcases/cve/tcindex01.c new file mode 100644 index 000000000..91bfafb53 --- /dev/null +++ b/testcases/cve/tcindex01.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Marcos Paulo de Souza <mpdesouza@suse.com> + * LTP port: Martin Doucha <mdoucha@suse.cz> + */ + +/*\ + * CVE-2023-1829 + * + * Test for use-after-free after removing tcindex traffic filter with certain + * parameters. + * + * Tcindex filter removed in: + * + * commit 8c710f75256bb3cf05ac7b1672c82b92c43f3d28 + * Author: Jamal Hadi Salim <jhs@mojatatu.com> + * Date: Tue Feb 14 08:49:14 2023 -0500 + * + * net/sched: Retire tcindex classifier + */ + +#include <linux/netlink.h> +#include <linux/pkt_sched.h> +#include <linux/pkt_cls.h> +#include "tst_test.h" +#include "tst_rtnetlink.h" +#include "tst_netdevice.h" +#include "lapi/sched.h" +#include "lapi/if_ether.h" +#include "lapi/rtnetlink.h" + +#define DEVNAME "ltp_dummy1" + +static const uint32_t qd_handle = TC_H_MAKE(1 << 16, 0); +static const uint32_t clsid = TC_H_MAKE(1 << 16, 1); +static const uint32_t shift = 10; +static const uint16_t mask = 0xffff; + +/* rtnetlink payloads */ +static const struct tc_htb_glob qd_opt = { + .rate2quantum = 10, + .version = 3, + .defcls = 30 +}; +static struct tc_htb_opt cls_opt = {}; + +/* htb qdisc and class options */ +static const struct tst_rtnl_attr_list qd_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_HTB_INIT, &qd_opt, sizeof(qd_opt), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; +static const struct tst_rtnl_attr_list cls_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_HTB_PARMS, &cls_opt, sizeof(cls_opt), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; + +/* tcindex filter options */ +static const struct tst_rtnl_attr_list f_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_TCINDEX_MASK, &mask, sizeof(mask), NULL}, + {TCA_TCINDEX_SHIFT, &shift, sizeof(shift), NULL}, + {TCA_TCINDEX_CLASSID, &clsid, sizeof(clsid), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; + +static void setup(void) +{ + tst_setup_netns(); + NETDEV_ADD_DEVICE(DEVNAME, "dummy"); + + cls_opt.rate.rate = cls_opt.ceil.rate = 256000; + cls_opt.buffer = 1000000 * 1600 / cls_opt.rate.rate; + cls_opt.cbuffer = 1000000 * 1600 / cls_opt.ceil.rate; +} + +static void run(void) +{ + int ret; + + NETDEV_ADD_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb", + qd_config); + NETDEV_ADD_TRAFFIC_CLASS(DEVNAME, qd_handle, clsid, "htb", cls_config); + NETDEV_ADD_TRAFFIC_FILTER(DEVNAME, qd_handle, 10, ETH_P_IP, 1, + "tcindex", f_config); + NETDEV_REMOVE_TRAFFIC_FILTER(DEVNAME, qd_handle, 10, ETH_P_IP, + 1, "tcindex"); + ret = tst_netdev_add_traffic_filter(__FILE__, __LINE__, 0, DEVNAME, + qd_handle, 10, ETH_P_IP, 1, "tcindex", f_config); + TST_ERR = tst_rtnl_errno; + NETDEV_REMOVE_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb"); + + if (ret) + tst_res(TPASS, "Removing tcindex filter works correctly"); + else if (TST_ERR == EEXIST) + tst_res(TFAIL, "Kernel traffic filter list is corrupted"); + else + tst_brk(TBROK | TTERRNO, "Unexpected rtnetlink error"); +} + +static void cleanup(void) +{ + NETDEV_REMOVE_DEVICE(DEVNAME); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_VETH", + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + "CONFIG_NET_SCH_HTB", + "CONFIG_NET_CLS_TCINDEX", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "8c710f75256b"}, + {"CVE", "2023-1829"}, + {} + } +}; diff --git a/testcases/kernel/connectors/pec/cn_pec.sh b/testcases/kernel/connectors/pec/cn_pec.sh index 082e30102..dce7f210b 100755 --- a/testcases/kernel/connectors/pec/cn_pec.sh +++ b/testcases/kernel/connectors/pec/cn_pec.sh @@ -11,7 +11,7 @@ TST_OPTS="n:" TST_SETUP=setup -TST_TESTFUNC=test +TST_TESTFUNC=do_test TST_PARSE_ARGS=parse_args TST_USAGE=usage TST_NEEDS_ROOT=1 @@ -66,7 +66,7 @@ setup() tst_res TINFO "Test process events connector" } -test() +do_test() { local event=$2 local gen_pid list_pid gen_rc lis_rc diff --git a/testcases/kernel/connectors/pec/pec_listener.c b/testcases/kernel/connectors/pec/pec_listener.c index 21ae53e87..01ee91d43 100644 --- a/testcases/kernel/connectors/pec/pec_listener.c +++ b/testcases/kernel/connectors/pec/pec_listener.c @@ -19,9 +19,9 @@ #include <signal.h> #include <linux/types.h> #include <linux/netlink.h> -#include <tst_checkpoint.h> #define TST_NO_DEFAULT_MAIN -#include <tst_test.h> +#include "tst_test.h" +#include "tst_checkpoint.h" #ifndef NETLINK_CONNECTOR diff --git a/testcases/kernel/containers/.gitignore b/testcases/kernel/containers/.gitignore deleted file mode 100644 index 5c2b90312..000000000 --- a/testcases/kernel/containers/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -/check_for_unshare -mountns/mountns01 -mountns/mountns02 -mountns/mountns03 -mountns/mountns04 -userns/userns01 -userns/userns02 -userns/userns03 -userns/userns04 -userns/userns05 -userns/userns06_capcheck -userns/userns06 -userns/userns07 -userns/userns08 diff --git a/testcases/kernel/containers/Makefile b/testcases/kernel/containers/Makefile index 4285546e7..20d2424a5 100644 --- a/testcases/kernel/containers/Makefile +++ b/testcases/kernel/containers/Makefile @@ -1,33 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2007 +# Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> top_srcdir ?= ../../.. include $(top_srcdir)/include/mk/env_pre.mk - -LIBDIR := libclone - -FILTER_OUT_DIRS := $(LIBDIR) - -LIB := $(LIBDIR)/libclone.a - -LDLIBS := -ldl -lltp - -INSTALL_TARGETS := *.sh - -$(LIBDIR): - mkdir -p "$@" - -# Make the target the real lib so we don't have to deal with rebuilding this -# every time the dependency is evaluated, like with PHONY rules. -$(LIB): $(LIBDIR) - $(MAKE) -C $^ -f "$(abs_srcdir)/$(LIBDIR)/Makefile" all - -MAKE_DEPS := $(LIB) - -trunk-clean:: | lib-clean - -lib-clean:: $(LIBDIR) - $(MAKE) -C $^ -f "$(abs_srcdir)/$(LIBDIR)/Makefile" clean - include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/testcases/kernel/containers/Makefile.inc b/testcases/kernel/containers/Makefile.inc deleted file mode 100644 index 179809bc1..000000000 --- a/testcases/kernel/containers/Makefile.inc +++ /dev/null @@ -1,45 +0,0 @@ -# -# kernel/containers testcase suite common definitions Makefile. -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Ngie Cooper, July 2009 -# - -# DO NOT USE THIS FILE FOR containers / libclone!!! - -LIBDIR := ../libclone - -LIBS := $(LIBDIR)/libclone.a - -CPPFLAGS += -I$(abs_srcdir)/$(LIBDIR) - -LDFLAGS += -L$(abs_builddir)/$(LIBDIR) - -$(LIBDIR): - mkdir -p "$@" - -# Make the target the real lib so we don't have to deal with rebuilding this -# every time the dependency is evaluated, like with PHONY rules. -$(LIBS): $(LIBDIR) - $(MAKE) -C $^ -f "$(abs_srcdir)/$^/Makefile" all - -INSTALL_TARGETS ?= *.sh - -MAKE_DEPS := $(LIBS) - -# vim: syntax=make diff --git a/testcases/kernel/containers/README b/testcases/kernel/containers/README deleted file mode 100644 index c99cacd98..000000000 --- a/testcases/kernel/containers/README +++ /dev/null @@ -1,50 +0,0 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ - -CONTAINER TESTS AUTOMATION SUITE ----------------------------- -The tests requires the Kernel to be compiled with the following configs - -CONFIG_DUMMY=y(or =m) -CONFIG_NAMESPACES=y -CONFIG_UTS_NS=y -CONFIG_IPC_NS=y -CONFIG_USER_NS=y -CONFIG_PID_NS=y -CONFIG_NET_NS=y -CONFIG_VETH=y(or =m) -CONFIG_MACVLAN=y(optional) - -The container test automation suite helps run the container functionality -(e.g: utsname etc..) tests and report results. Please refer the following -each functionality README file for detail: - -sysvipc/* - Contains all the testcases related to IPC NS tests. -posixmq/* - Contains all the testcases related to POSIX MQ NS tests. These - are strictly speaking a part of the ipc namespaces, but can be - enabled in the kernel without SYSV IPC support. -utsname/* - Contains all the testcases related to utsname tests. -libclone/* - Contains the library API for clone() . -netns/* - Contains the testcases related to the network NS tests. diff --git a/testcases/kernel/containers/TEST_PLAN.txt b/testcases/kernel/containers/TEST_PLAN.txt deleted file mode 100644 index 809abaecb..000000000 --- a/testcases/kernel/containers/TEST_PLAN.txt +++ /dev/null @@ -1,27 +0,0 @@ -################################################################################ -## Copyright (c) International Business Machines Corp., 2007 -## -## This program is free software; you can redistribute it and#or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## This program 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 General Public License -## for more details. -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -################################################################################ - -Following are tentative Testcases to be included into LTP-Containers in future: - -NAME TENTATIVE-TIME -================================================================================= -PID NAMESPACES (NEAR FUTURE) -NETWORK NAMESPACES (NEAR FUTURE) -POSIX IPC NAMESPACES (NEAR FUTURE) -TTY+CONSOLE+DEVPTS NAMESPACES (NEAR FUTURE) -PROC+SYSFS ISOLATION (NEAR FUTURE) -PER-CONTAINER CAPABILITY/SECURITY TESTS (NEAR FUTURE) -================================================================================= diff --git a/testcases/kernel/containers/libclone/Makefile b/testcases/kernel/containers/libclone/Makefile deleted file mode 100644 index 13af52b67..000000000 --- a/testcases/kernel/containers/libclone/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ - -top_srcdir ?= ../../../.. - -include $(top_srcdir)/include/mk/testcases.mk - -INTERNAL_LIB := libclone.a - -include $(top_srcdir)/include/mk/lib.mk diff --git a/testcases/kernel/containers/libclone/libclone.c b/testcases/kernel/containers/libclone/libclone.c deleted file mode 100644 index db0d9b2a5..000000000 --- a/testcases/kernel/containers/libclone/libclone.c +++ /dev/null @@ -1,142 +0,0 @@ -/* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -***************************************************************************/ -#include "libclone.h" - -int do_clone_tests(unsigned long clone_flags, - int (*fn1) (void *arg), void *arg1, - int (*fn2) (void *arg), void *arg2) -{ - int ret; - - ret = ltp_clone_quick(clone_flags | SIGCHLD, fn1, arg1); - - if (ret == -1) { - return -1; - } - if (fn2) - ret = fn2(arg2); - else - ret = 0; - - return ret; -} - -int do_unshare_tests(unsigned long clone_flags, - int (*fn1) (void *arg), void *arg1, - int (*fn2) (void *arg), void *arg2) -{ - int pid, ret = 0; - int retpipe[2]; - char buf[2]; - - if (pipe(retpipe) == -1) { - perror("pipe"); - return -1; - } - pid = fork(); - if (pid == -1) { - perror("fork"); - close(retpipe[0]); - close(retpipe[1]); - return -1; - } - if (pid == 0) { - close(retpipe[0]); - ret = tst_syscall(SYS_unshare, clone_flags); - if (ret == -1) { - if (write(retpipe[1], "0", 2) < 0) { - perror("unshare:write(retpipe[1], ..)"); - } - close(retpipe[1]); - exit(1); - } else { - if (write(retpipe[1], "1", 2) < 0) { - perror("unshare:write(retpipe[1], ..)"); - } - } - close(retpipe[1]); - ret = fn1(arg1); - exit(ret); - } else { - close(retpipe[1]); - if (read(retpipe[0], &buf, 2) < 0) { - perror("unshare:read(retpipe[0], ..)"); - } - close(retpipe[0]); - if (*buf == '0') - return -1; - if (fn2) - ret = fn2(arg2); - } - - return ret; -} - -int do_plain_tests(int (*fn1) (void *arg), void *arg1, - int (*fn2) (void *arg), void *arg2) -{ - int ret = 0, pid; - - pid = fork(); - if (pid == -1) { - perror("fork"); - return -1; - } - if (pid == 0) - exit(fn1(arg1)); - if (fn2) - ret = fn2(arg2); - return ret; -} - -int do_clone_unshare_test(int use_clone, unsigned long clone_flags, - int (*fn1) (void *arg), void *arg1) -{ - switch (use_clone) { - case T_NONE: - return do_plain_tests(fn1, arg1, NULL, NULL); - case T_CLONE: - return do_clone_tests(clone_flags, fn1, arg1, NULL, NULL); - case T_UNSHARE: - return do_unshare_tests(clone_flags, fn1, arg1, NULL, NULL); - default: - printf("%s: bad use_clone option: %d\n", __FUNCTION__, - use_clone); - return -1; - } -} - -/* - * Run fn1 in a unshared environmnent, and fn2 in the original context - */ -int do_clone_unshare_tests(int use_clone, unsigned long clone_flags, - int (*fn1) (void *arg), void *arg1, - int (*fn2) (void *arg), void *arg2) -{ - switch (use_clone) { - case T_NONE: - return do_plain_tests(fn1, arg1, fn2, arg2); - case T_CLONE: - return do_clone_tests(clone_flags, fn1, arg1, fn2, arg2); - case T_UNSHARE: - return do_unshare_tests(clone_flags, fn1, arg1, fn2, arg2); - default: - printf("%s: bad use_clone option: %d\n", __FUNCTION__, - use_clone); - return -1; - } -} diff --git a/testcases/kernel/containers/libclone/libclone.h b/testcases/kernel/containers/libclone/libclone.h deleted file mode 100644 index e92fdca02..000000000 --- a/testcases/kernel/containers/libclone/libclone.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -***************************************************************************/ -#ifndef __LIBCLONE_H -#define __LIBCLONE_H - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <libgen.h> -#include <sys/syscall.h> -#include <signal.h> -#include "lapi/syscalls.h" -#include "test.h" -#include "lapi/sched.h" - -#define T_UNSHARE 0 -#define T_CLONE 1 -#define T_NONE 2 - -#ifndef SYS_unshare -#ifdef __NR_unshare -#define SYS_unshare __NR_unshare -#elif __i386__ -#define SYS_unshare 310 -#elif __ia64__ -#define SYS_unshare 1296 -#elif __x86_64__ -#define SYS_unshare 272 -#elif __s390x__ || __s390__ -#define SYS_unshare 303 -#elif __powerpc__ -#define SYS_unshare 282 -#else -#error "unshare not supported on this architecure." -#endif -#endif - -#ifndef __NR_unshare -#define __NR_unshare SYS_unshare -#endif - -/* - * Run fn1 in a unshared environmnent, and fn2 in the original context - * Fn2 may be NULL. - */ - -int do_clone_tests(unsigned long clone_flags, - int(*fn1)(void *arg), void *arg1, - int(*fn2)(void *arg), void *arg2); - -int do_unshare_tests(unsigned long clone_flags, - int (*fn1)(void *arg), void *arg1, - int (*fn2)(void *arg), void *arg2); - -int do_fork_tests(int (*fn1)(void *arg), void *arg1, - int (*fn2)(void *arg), void *arg2); - -int do_clone_unshare_test(int use_clone, unsigned long clone_flags, - int (*fn1)(void *arg), void *arg1); - -int do_clone_unshare_tests(int use_clone, unsigned long clone_flags, - int (*fn1)(void *arg), void *arg1, - int (*fn2)(void *arg), void *arg2); - -#endif diff --git a/testcases/kernel/containers/mountns/.gitignore b/testcases/kernel/containers/mountns/.gitignore new file mode 100644 index 000000000..0555e9b3b --- /dev/null +++ b/testcases/kernel/containers/mountns/.gitignore @@ -0,0 +1,4 @@ +mountns01 +mountns02 +mountns03 +mountns04 diff --git a/testcases/kernel/containers/mountns/mountns.h b/testcases/kernel/containers/mountns/mountns.h index 615f1a058..9bb854659 100644 --- a/testcases/kernel/containers/mountns/mountns.h +++ b/testcases/kernel/containers/mountns/mountns.h @@ -8,28 +8,10 @@ #define COMMON_H #include "tst_test.h" -#include "lapi/sched.h" #define DIRA "LTP_DIR_A" #define DIRB "LTP_DIR_B" -static int dummy_child(void *v) -{ - (void)v; - return 0; -} - -static void check_newns(void) -{ - int pid, status; - - pid = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, dummy_child, NULL); - if (pid < 0) - tst_brk(TCONF, "CLONE_NEWNS not supported"); - - SAFE_WAIT(&status); -} - static void umount_folders(void) { if (tst_is_mounted(DIRA)) diff --git a/testcases/kernel/containers/mountns/mountns01.c b/testcases/kernel/containers/mountns/mountns01.c index e8f176920..8d821ea45 100644 --- a/testcases/kernel/containers/mountns/mountns01.c +++ b/testcases/kernel/containers/mountns/mountns01.c @@ -33,8 +33,9 @@ #include <sys/mount.h> #include "mountns.h" #include "tst_test.h" +#include "lapi/sched.h" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { TST_CHECKPOINT_WAIT(0); @@ -51,13 +52,14 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_UMOUNT(DIRA); - - return 0; } static void run(void) { - int ret; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; SAFE_UNSHARE(CLONE_NEWNS); @@ -67,9 +69,10 @@ static void run(void) SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); - ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); @@ -93,7 +96,6 @@ static void run(void) static void setup(void) { - check_newns(); create_folders(); } @@ -107,5 +109,10 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/mountns/mountns02.c b/testcases/kernel/containers/mountns/mountns02.c index 4b85fa79b..e7a80cbbf 100644 --- a/testcases/kernel/containers/mountns/mountns02.c +++ b/testcases/kernel/containers/mountns/mountns02.c @@ -34,8 +34,9 @@ #include <sys/mount.h> #include "mountns.h" #include "tst_test.h" +#include "lapi/sched.h" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { TST_CHECKPOINT_WAIT(0); @@ -51,13 +52,14 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_UMOUNT(DIRA); - - return 0; } static void run(void) { - int ret; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; SAFE_UNSHARE(CLONE_NEWNS); @@ -68,9 +70,10 @@ static void run(void) SAFE_MOUNT("none", DIRA, "none", MS_PRIVATE, NULL); - ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); @@ -94,7 +97,6 @@ static void run(void) static void setup(void) { - check_newns(); create_folders(); } @@ -108,5 +110,10 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/mountns/mountns03.c b/testcases/kernel/containers/mountns/mountns03.c index 1d26a25d8..6066d1c54 100644 --- a/testcases/kernel/containers/mountns/mountns03.c +++ b/testcases/kernel/containers/mountns/mountns03.c @@ -36,8 +36,9 @@ #include <sys/mount.h> #include "mountns.h" #include "tst_test.h" +#include "lapi/sched.h" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { /* * makes mount DIRA a slave of DIRA (all slave mounts have @@ -59,13 +60,14 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_UMOUNT(DIRA); - - return 0; } static void run(void) { - int ret; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; SAFE_UNSHARE(CLONE_NEWNS); @@ -76,9 +78,10 @@ static void run(void) SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); - ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } TST_CHECKPOINT_WAIT(0); @@ -104,7 +107,6 @@ static void run(void) static void setup(void) { - check_newns(); create_folders(); } @@ -118,5 +120,10 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/mountns/mountns04.c b/testcases/kernel/containers/mountns/mountns04.c index fc392f1a7..7b4dcb16d 100644 --- a/testcases/kernel/containers/mountns/mountns04.c +++ b/testcases/kernel/containers/mountns/mountns04.c @@ -22,6 +22,7 @@ #include <sys/mount.h> #include "mountns.h" #include "tst_test.h" +#include "lapi/sched.h" static void run(void) { @@ -46,7 +47,6 @@ static void run(void) static void setup(void) { - check_newns(); create_folders(); } @@ -61,4 +61,8 @@ static struct tst_test test = { .test_all = run, .needs_root = 1, .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/mqns/Makefile b/testcases/kernel/containers/mqns/Makefile index 64c3763ee..01e90ec33 100644 --- a/testcases/kernel/containers/mqns/Makefile +++ b/testcases/kernel/containers/mqns/Makefile @@ -1,29 +1,12 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2009 ## -## Copyright (c) Nadia Derbey, 2009 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) International Business Machines Corp., 2009 +# Copyright (c) Nadia Derbey, 2009 +# Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lpthread -lrt -lclone $(LDLIBS) +LDLIBS := -lrt $(LDLIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/mqns/mqns.h b/testcases/kernel/containers/mqns/mqns.h deleted file mode 100644 index 5a9056838..000000000 --- a/testcases/kernel/containers/mqns/mqns.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __MQNS_H -#define __MQNS_H - -#define DEV_MQUEUE "/dev/mqueue" -#define DEV_MQUEUE2 "/dev/mqueue2" -#define SLASH_MQ1 "/MQ1" -#define NOSLASH_MQ1 "MQ1" -#define SLASH_MQ2 "/MQ2" -#define NOSLASH_MQ2 "MQ2" - -#endif /* __MQNS_H */ diff --git a/testcases/kernel/containers/mqns/mqns_01.c b/testcases/kernel/containers/mqns/mqns_01.c index 1d109e020..d9f6e6c18 100644 --- a/testcases/kernel/containers/mqns/mqns_01.c +++ b/testcases/kernel/containers/mqns/mqns_01.c @@ -1,148 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* Copyright (c) Nadia Derbey, 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Nadia Derbey <Nadia.Derbey@bull.net> -* -* Check mqns isolation: father mqns cannot be accessed from newinstance -* -* Mount mqueue fs -* Create a posix mq -->mq1 -* unshare -* In unshared process: -* Mount newinstance mqueuefs -* Check that mq1 is not readable from new ns + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Nadia Derbey, 2009 <Nadia.Derbey@bull.net> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -***************************************************************************/ +/*\ + * [Description] + * + * Create a mqueue inside the parent and check if it can be accessed from + * the child namespace. Isolated and unshared process can't access to parent, + * but plain process can. + */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include <sys/wait.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "mqns.h" -#include "mqns_helper.h" +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" -char *TCID = "posixmq_namespace_01"; -int TST_TOTAL = 1; +#define MQNAME "/MQ1" -int p1[2]; -int p2[2]; +static mqd_t mqd; +static char *str_op; -int check_mqueue(void *vtest) +static void run(void) { - char buf[30]; - mqd_t mqd; + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD, + }; - (void) vtest; + tst_res(TINFO, "Checking namespaces isolation from parent to child"); - close(p1[1]); - close(p2[0]); + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); - if (read(p1[0], buf, strlen("go") + 1) < 0) { - printf("read(p1[0], ...) failed: %s\n", strerror(errno)); - exit(1); - } - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDONLY); - if (mqd == -1) { - if (write(p2[1], "notfnd", strlen("notfnd") + 1) < 0) { - perror("write(p2[1], ...) failed"); - exit(1); + if (!SAFE_CLONE(&clone_args)) { + TST_EXP_FAIL(mq_open(MQNAME, O_RDONLY), ENOENT); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + TST_EXP_FAIL(mq_open(MQNAME, O_RDONLY), ENOENT); + return; } } else { - if (write(p2[1], "exists", strlen("exists") + 1) < 0) { - perror("write(p2[1], \"exists\", 7) failed"); - exit(1); - } else if (mq_close(mqd) < 0) { - perror("mq_close(mqd) failed"); - exit(1); + tst_res(TINFO, "Spawning plain process"); + + if (!SAFE_FORK()) { + TST_EXP_POSITIVE(mq_open(MQNAME, O_RDONLY)); + return; } } - - exit(0); } static void setup(void) { - tst_require_root(); - check_mqns(); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); } -int main(int argc, char *argv[]) +static void cleanup(void) { - int r; - mqd_t mqd; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1 || pipe(p2) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); - } - - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0777, NULL); - if (mqd == -1) { - perror("mq_open"); - tst_brkm(TFAIL, NULL, "mq_open failed"); + if (mqd != -1) { + SAFE_MQ_CLOSE(mqd); + SAFE_MQ_UNLINK(MQNAME); } - - tst_resm(TINFO, "Checking namespaces isolation from parent to child"); - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_resm(TFAIL, "failed clone/unshare"); - mq_close(mqd); - tst_syscall(__NR_mq_unlink, NOSLASH_MQ1); - tst_exit(); - } - - close(p1[0]); - close(p2[1]); - if (write(p1[1], "go", strlen("go") + 1) < 0) - tst_resm(TBROK | TERRNO, "write(p1[1], \"go\", ...) failed"); - else if (read(p2[0], buf, 7) < 0) - tst_resm(TBROK | TERRNO, "read(p2[0], buf, ...) failed"); - else { - if (!strcmp(buf, "exists")) { - tst_resm(TFAIL, "child process found mqueue"); - } else if (!strcmp(buf, "notfnd")) { - tst_resm(TPASS, "child process didn't find mqueue"); - } else { - tst_resm(TFAIL, "UNKNOWN RESULT"); - } - } - - /* destroy the mqueue */ - if (mq_close(mqd) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "mq_close failed"); - } - tst_syscall(__NR_mq_unlink, NOSLASH_MQ1); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation <clone|unshare>" }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_02.c b/testcases/kernel/containers/mqns/mqns_02.c index d4e785b59..4348be7fc 100644 --- a/testcases/kernel/containers/mqns/mqns_02.c +++ b/testcases/kernel/containers/mqns/mqns_02.c @@ -1,180 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2009 -* Copyright (c) Nadia Derbey, 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Nadia Derbey <Nadia.Derbey@bull.net> -* -* Check mqns isolation: child mqns cannot be accessed from father -* -* Mount mqueue fs -* unshare -* In unshared process: -* Mount newinstance mqueuefs -* Create a posix mq -->mq1 -* Check that mq1 is not readable from father -* -* Changelog: -* Dec 16: accomodate new mqns semantics (Serge Hallyn) - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include <sys/wait.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "mqns.h" -#include "mqns_helper.h" - -char *TCID = "posixmq_namespace_02"; -int TST_TOTAL = 1; - -int p1[2]; -int p2[2]; - -int check_mqueue(void *vtest) -{ - char buf[30]; - mqd_t mqd; + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Nadia Derbey, 2009 <Nadia.Derbey@bull.net> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ - (void) vtest; +/*\ + * [Description] + * + * Create a mqueue with the same name in both parent and isolated/forked child, + * then check namespace isolation. + */ - close(p1[1]); - close(p2[0]); +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" - if (read(p1[0], buf, 3) < 0) { - perror("read(p1[0], ..) failed"); - exit(1); - } else { +#define MQNAME "/MQ1" - mqd = - tst_syscall(__NR_mq_open, NOSLASH_MQ1, - O_RDWR | O_CREAT | O_EXCL, 0777, NULL); - if (mqd == -1) { - if (write(p2[1], "mqfail", strlen("mqfail") + 1) < 0) { - perror("write(p2[1], \"mqfail\", ..) failed"); - exit(1); - } - } else { - - if (write(p2[1], "mqopen", strlen("mqopen") + 1) < 0) { - perror("write(p2[1], \"mqopen\", ..) failed"); - exit(1); - } else { - - if (read(p1[0], buf, 5) < 0) { - perror("read(p1[0], ..) failed"); - exit(1); - } else { - - /* destroy the mqueue */ - if (mq_close(mqd) < 0) { - perror("mq_close(mqd) failed"); - exit(1); - } else if (tst_syscall(__NR_mq_unlink, - NOSLASH_MQ1) < 0) { - perror("mq_unlink(" NOSLASH_MQ1 - ") failed"); - exit(1); - } else if (write(p2[1], "done", - strlen("done") + 1) - < 0) { - perror("write(p2[1], " - "\"done\", ..) failed"); - exit(1); - } - - } - - } +static mqd_t mqd; +static char *str_op; - } +static int create_message_queue(void) +{ + return mq_open(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); +} - } - exit(0); +static void shared_child(void) +{ + mqd_t mqd1 = -1; + TST_EXP_FAIL(mqd1 = create_message_queue(), EEXIST); + + if (mqd1 != -1) { + SAFE_MQ_CLOSE(mqd1); + SAFE_MQ_UNLINK(MQNAME); + } } -static void setup(void) +static void isolated_child(void) { - tst_require_root(); - check_mqns(); + mqd_t mqd1 = -1; + + TST_EXP_POSITIVE(mqd1 = create_message_queue()); + + if (mqd1 != -1) { + SAFE_MQ_CLOSE(mqd1); + SAFE_MQ_UNLINK(MQNAME); + } } -int main(int argc, char *argv[]) +static void run(void) { - int r; - mqd_t mqd; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1 || pipe(p2) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "pipe"); - } + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD, + }; - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_brkm(TFAIL, NULL, "failed clone/unshare"); - } + tst_res(TINFO, "Checking namespaces isolation from parent to child"); - tst_resm(TINFO, "Checking namespaces isolation (child to parent)"); + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); - close(p1[0]); - close(p2[1]); - if (write(p1[1], "go", strlen("go") + 1) < 0) { - tst_brkm(TBROK, NULL, "write(p1[1], \"go\", ..) failed"); - } + if (!SAFE_CLONE(&clone_args)) { + isolated_child(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); - if (read(p2[0], buf, 7) < 0) { - tst_resm(TBROK | TERRNO, "read(p2[0], ..) failed"); - } else if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - umount(DEV_MQUEUE); - } else if (strcmp(buf, "mqopen")) { - tst_resm(TFAIL, "child process could not create mqueue"); - umount(DEV_MQUEUE); - } else { - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDONLY); - if (mqd == -1) { - tst_resm(TPASS, - "Parent process can't see the mqueue"); - } else { - tst_resm(TFAIL | TERRNO, - "Parent process found mqueue"); - mq_close(mqd); + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + isolated_child(); + return; } - if (write(p1[1], "cont", 5) < 0) { - tst_resm(TBROK | TERRNO, "write(p1[1], ..) failed"); + } else { + tst_res(TINFO, "Spawning plain process"); + + if (!SAFE_FORK()) { + shared_child(); + return; } - read(p2[0], buf, 7); } +} - tst_exit(); +static void setup(void) +{ + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); } + +static void cleanup(void) +{ + if (mqd != -1) { + SAFE_MQ_CLOSE(mqd); + SAFE_MQ_UNLINK(MQNAME); + } +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation <clone|unshare>" }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_03.c b/testcases/kernel/containers/mqns/mqns_03.c index a7452b970..4a0399ddb 100644 --- a/testcases/kernel/containers/mqns/mqns_03.c +++ b/testcases/kernel/containers/mqns/mqns_03.c @@ -1,207 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Serge Hallyn <serue@us.ibm.com> -* -* Check ipcns+sb longevity -* -* Mount mqueue fs -* unshare -* In unshared process: -* Create "/mq1" with mq_open() -* Mount mqueuefs -* Check that /mq1 exists -* Create /dev/mqueue/mq2 through vfs (create(2)) -* Umount /dev/mqueue -* Remount /dev/mqueue -* Check that both /mq1 and /mq2 exist - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "mqns.h" -#include "mqns_helper.h" - -char *TCID = "posixmq_namespace_03"; -int TST_TOTAL = 1; - -int p1[2]; -int p2[2]; - -#define FNAM1 DEV_MQUEUE2 SLASH_MQ1 -#define FNAM2 DEV_MQUEUE2 SLASH_MQ2 - -int check_mqueue(void *vtest) + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Serge Hallyn <serue@us.ibm.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test mqueuefs from an isolated/forked process namespace. + * + * [Algorithm] + * + * Inside new IPC namespace: + * + * - mq_open() /MQ1 + * - mount mqueue inside the temporary folder + * - check for /MQ1 existance + * - creat() /MQ2 inside the temporary folder + * - umount + * - mount mqueue inside the temporary folder + * - check /MQ1 existance + * - check /MQ2 existance + * - umount + */ + +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_macros.h" + +#define CHECK_MQ_OPEN_RET(x) ((x) >= 0 || ((x) == -1 && errno != EMFILE)) + +#define DEVDIR "ltp_mqueue" +#define MQNAME1 "/MQ1" +#define MQNAME2 "/MQ2" +#define MQUEUE1 DEVDIR MQNAME1 +#define MQUEUE2 DEVDIR MQNAME2 + +static char *str_op; + +static void check_mqueue(void) { - char buf[30]; - mqd_t mqd; int rc; - struct stat statbuf; + mqd_t mqd; - (void) vtest; + tst_res(TINFO, "Creating %s mqueue from within child process", MQNAME1); - close(p1[1]); - close(p2[0]); + mqd = TST_RETRY_FUNC( + mq_open(MQNAME1, O_RDWR | O_CREAT | O_EXCL, 0777, NULL), + CHECK_MQ_OPEN_RET); + if (mqd == -1) + tst_brk(TBROK | TERRNO, "mq_open failed"); - if (read(p1[0], buf, 3) != 3) { /* go */ - perror("read failed"); - exit(1); - } + SAFE_MQ_CLOSE(mqd); - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0755, NULL); - if (mqd == -1) { - write(p2[1], "mqfail", 7); - exit(1); - } + tst_res(TINFO, "Mount %s from within child process", DEVDIR); - mq_close(mqd); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - write(p2[1], "mount1", 7); - exit(1); - } + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " does not exist at first mount"); + else + tst_res(TPASS, MQUEUE1 " exists at first mount"); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - write(p2[1], "stat1", 6); - exit(1); - } + tst_res(TINFO, "Creating %s from within child process", MQUEUE2); - rc = creat(FNAM2, 0755); - if (rc == -1) { - write(p2[1], "creat", 6); - exit(1); - } + rc = SAFE_CREAT(MQUEUE2, 0755); + SAFE_CLOSE(rc); - close(rc); + tst_res(TINFO, "Mount %s from within child process a second time", DEVDIR); - rc = umount(DEV_MQUEUE2); - if (rc == -1) { - write(p2[1], "umount", 7); - exit(1); - } + SAFE_UMOUNT(DEVDIR); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - write(p2[1], "mount2", 7); - exit(1); - } + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " does not exist at second mount"); + else + tst_res(TPASS, MQUEUE1 " exists at second mount"); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - write(p2[1], "stat2", 7); - exit(1); - } + if (access(MQUEUE2, F_OK)) + tst_res(TFAIL, MQUEUE2 " does not exist at second mount"); + else + tst_res(TPASS, MQUEUE2 " exists at second mount"); - rc = stat(FNAM2, &statbuf); - if (rc == -1) { - write(p2[1], "stat3", 7); - exit(1); - } + SAFE_UMOUNT(DEVDIR); - write(p2[1], "done", 5); + SAFE_MQ_UNLINK(MQNAME1); + SAFE_MQ_UNLINK(MQNAME2); +} - exit(0); +static void run(void) +{ + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD + }; + + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); + + if (!SAFE_CLONE(&clone_args)) { + check_mqueue(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + check_mqueue(); + return; + } + } } static void setup(void) { - tst_require_root(); - check_mqns(); + if (!str_op || (strcmp(str_op, "clone") && strcmp(str_op, "unshare"))) + tst_brk(TCONF, "Please specify clone|unshare child isolation"); + + SAFE_MKDIR(DEVDIR, 0755); } -int main(int argc, char *argv[]) +static void cleanup(void) { - int r; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, "Testing posix mq namespaces through clone(2)"); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)"); - - if (pipe(p1) == -1 || pipe(p2) == -1) - tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); - - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_brkm(TBROK | TERRNO, NULL, "failed clone/unshare"); - } - - tst_resm(TINFO, "Checking correct umount+remount of mqueuefs"); - - mkdir(DEV_MQUEUE2, 0755); - - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - - read(p2[0], buf, 7); - r = TFAIL; - if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - goto fail; - } else if (!strcmp(buf, "mount1")) { - tst_resm(TFAIL, "child process could not mount mqueue"); - goto fail; - } else if (!strcmp(buf, "stat1x")) { - tst_resm(TFAIL, "mq created by child is not in mqueuefs"); - goto fail; - } else if (!strcmp(buf, "creat")) { - tst_resm(TFAIL, "child couldn't creat mq through mqueuefs"); - goto fail; - } else if (!strcmp(buf, "umount")) { - tst_resm(TFAIL, "child couldn't umount mqueuefs"); - goto fail; - } else if (!strcmp(buf, "mount2")) { - tst_resm(TFAIL, "child couldn't remount mqueuefs"); - goto fail; - } else if (!strcmp(buf, "stat2")) { - tst_resm(TFAIL, - "mq_open()d file gone after remount of mqueuefs"); - goto fail; - } else if (!strcmp(buf, "stat3")) { - tst_resm(TFAIL, - "creat(2)'d file gone after remount of mqueuefs"); - goto fail; - } + if (!access(MQUEUE1, F_OK)) + SAFE_MQ_UNLINK(MQNAME1); - tst_resm(TPASS, "umount+remount of mqueuefs remounted the right fs"); + if (!access(MQUEUE2, F_OK)) + SAFE_MQ_UNLINK(MQNAME2); - r = 0; -fail: - umount(DEV_MQUEUE2); - rmdir(DEV_MQUEUE2); - tst_exit(); + if (tst_is_mounted(DEVDIR)) + SAFE_UMOUNT(DEVDIR); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_tmpdir = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation <clone|unshare>" }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_04.c b/testcases/kernel/containers/mqns/mqns_04.c index d07a85c04..2d943e1b6 100644 --- a/testcases/kernel/containers/mqns/mqns_04.c +++ b/testcases/kernel/containers/mqns/mqns_04.c @@ -1,187 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Serge Hallyn <serue@us.ibm.com> -* -* Check mqueuefs lifetime -* . parent creates /dev/mqueue2 -* . child mounts mqueue there -* . child does mq_open("/ab") -* . parent checks for /dev/mqueue2 -* . child exits -* . parent checks for /dev/mqueue2 -* . parent tries 'touch /dev/mqueue2/dd' -> should fail -* . parent umounts /dev/mqueue2 - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include <sys/types.h> -#include <sys/stat.h> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Serge Hallyn <serue@us.ibm.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test mqueuefs manipulation from child/parent namespaces. + * + * [Algorithm] + * + * - parent creates mqueue folder in <tmpdir> + * - child mq_open() /MQ1 mqueue + * - child mounts mqueue there + * - parent checks for <tmpdir>/mqueue/MQ1 existence + * - child exits + * - parent checks for <tmpdir>/mqueue/MQ1 existence + * - parent tries 'touch <tmpdir>/mqueue/MQ2' -> should fail + * - parent umount mqueuefs + */ + #include <sys/wait.h> -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "mqns.h" -#include "mqns_helper.h" +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_macros.h" -char *TCID = "posixmq_namespace_04"; -int TST_TOTAL = 1; +#define CHECK_MQ_OPEN_RET(x) ((x) >= 0 || ((x) == -1 && errno != EMFILE)) -int p1[2]; -int p2[2]; +#define DEVDIR "ltp_mqueue" +#define MQNAME1 "/MQ1" +#define MQNAME2 "/MQ2" +#define MQUEUE1 DEVDIR MQNAME1 +#define MQUEUE2 DEVDIR MQNAME2 -#define FNAM1 DEV_MQUEUE2 SLASH_MQ1 -#define FNAM2 DEV_MQUEUE2 SLASH_MQ2 +static char *str_op; -int check_mqueue(void *vtest) +static void check_mqueue(void) { - char buf[30]; mqd_t mqd; - int rc; - (void) vtest; + tst_res(TINFO, "Creating %s mqueue from within child process", MQNAME1); - close(p1[1]); - close(p2[0]); + mqd = TST_RETRY_FUNC( + mq_open(MQNAME1, O_RDWR | O_CREAT | O_EXCL, 0755, NULL), + CHECK_MQ_OPEN_RET); + if (mqd == -1) + tst_brk(TBROK | TERRNO, "mq_open failed"); - read(p1[0], buf, 3); /* go */ + SAFE_MQ_CLOSE(mqd); - mqd = tst_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0755, NULL); - if (mqd == -1) { - write(p2[1], "mqfail", 7); - tst_exit(); - } + tst_res(TINFO, "Mount %s from within child process", DEVDIR); - mq_close(mqd); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); +} - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - perror("mount"); - write(p2[1], "mount", 6); - tst_exit(); +static void run(void) +{ + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD + }; + + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); + + if (!SAFE_CLONE(&clone_args)) { + check_mqueue(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + check_mqueue(); + return; + } } - write(p2[1], "go", 3); - read(p1[0], buf, 3); + TST_CHECKPOINT_WAIT(0); - tst_exit(); -} + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " can't be accessed from parent"); + else + tst_res(TPASS, MQUEUE1 " can be accessed from parent"); -static void setup(void) -{ - tst_require_root(); - check_mqns(); -} + TST_CHECKPOINT_WAKE(0); -int main(int argc, char *argv[]) -{ - int rc; - int status; - char buf[30]; - struct stat statbuf; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } + tst_res(TINFO, "Waiting child to exit"); - mkdir(DEV_MQUEUE2, 0755); + tst_reap_children(); - tst_resm(TINFO, "Checking mqueue filesystem lifetime"); + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " can't be accessed from parent"); + else + tst_res(TPASS, MQUEUE1 " can be accessed from parent"); - /* fire off the test */ - rc = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (rc < 0) { - tst_resm(TFAIL, "failed clone/unshare"); - goto fail; - } + tst_res(TINFO, "Try to create %s from parent", MQUEUE2); - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - - read(p2[0], buf, 7); - if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - goto fail; - } else if (!strcmp(buf, "mount")) { - tst_resm(TFAIL, "child process could not mount mqueue"); - goto fail; - } + TST_EXP_FAIL(creat(MQUEUE2, 0755), EACCES); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - perror("stat"); - write(p1[1], "go", 3); - tst_resm(TFAIL, "parent could not see child's created mq"); - goto fail; - } - write(p1[1], "go", 3); + SAFE_UMOUNT(DEVDIR); +} - rc = wait(&status); - if (rc == -1) { - perror("wait"); - tst_resm(TFAIL, "error while parent waited on child to exit"); - goto fail; - } - if (!WIFEXITED(status)) { - tst_resm(TFAIL, "Child did not exit normally (status %d)", - status); - goto fail; - } - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - tst_resm(TFAIL, - "parent's view of child's mq died with child"); - goto fail; - } +static void setup(void) +{ + if (!str_op || (strcmp(str_op, "clone") && strcmp(str_op, "unshare"))) + tst_brk(TCONF, "Please specify clone|unshare child isolation"); - rc = creat(FNAM2, 0755); - if (rc != -1) { - tst_resm(TFAIL, - "parent was able to create a file in dead child's mqfs"); - goto fail; - } + SAFE_MKDIR(DEVDIR, 0755); +} - tst_resm(TPASS, "Child mqueue fs still visible for parent"); +static void cleanup(void) +{ + if (!access(MQUEUE1, F_OK)) + SAFE_MQ_UNLINK(MQNAME1); -fail: - umount(DEV_MQUEUE2); - rmdir(DEV_MQUEUE2); + if (!access(MQUEUE2, F_OK)) + SAFE_MQ_UNLINK(MQNAME2); - tst_exit(); + if (tst_is_mounted(DEVDIR)) + SAFE_UMOUNT(DEVDIR); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation <clone|unshare>" }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_helper.h b/testcases/kernel/containers/mqns/mqns_helper.h deleted file mode 100644 index 03f50aa36..000000000 --- a/testcases/kernel/containers/mqns/mqns_helper.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2009 - * Copyright (c) Nadia Derbey, 2009 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Serge Hallyn <serue@us.ibm.com> - ***************************************************************************/ -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <mqueue.h> -#include "../libclone/libclone.h" -#include "lapi/syscalls.h" -#include "safe_macros.h" -#include "test.h" - -static int dummy_child(void *v) -{ - (void) v; - return 0; -} - -static void check_mqns(void) -{ - int pid, status; - mqd_t mqd; - - mq_unlink("/checkmqnsenabled"); - mqd = - mq_open("/checkmqnsenabled", O_RDWR | O_CREAT | O_EXCL, 0777, NULL); - if (mqd == -1) - tst_brkm(TCONF, NULL, "mq_open check failed"); - - mq_close(mqd); - mq_unlink("/checkmqnsenabled"); - - pid = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, dummy_child, NULL); - if (pid == -1) - tst_brkm(TCONF | TERRNO, NULL, "CLONE_NEWIPC not supported"); - - SAFE_WAIT(NULL, &status); -} diff --git a/testcases/kernel/containers/netns/Makefile b/testcases/kernel/containers/netns/Makefile index 3cc2b4ae7..a8edd31b8 100644 --- a/testcases/kernel/containers/netns/Makefile +++ b/testcases/kernel/containers/netns/Makefile @@ -2,12 +2,12 @@ # Copyright (c) International Business Machines Corp., 2008 # Author: Veerendra <veeren@linux.vnet.ibm.com> # Copyright (c) 2015 Red Hat, Inc. +# Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lclone -lltp +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/netns/netns_lib.sh b/testcases/kernel/containers/netns/netns_lib.sh index 79e90336a..f6977f729 100755 --- a/testcases/kernel/containers/netns/netns_lib.sh +++ b/testcases/kernel/containers/netns/netns_lib.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2022 Petr Vorel <pvorel@suse.cz> -# Copyright (c) Linux Test Project, 2014-2021 +# Copyright (c) Linux Test Project, 2014-2023 # Copyright (c) 2015 Red Hat, Inc. TST_NEEDS_ROOT=1 @@ -20,7 +20,7 @@ TST_NET_SKIP_VARIABLE_INIT=1 IPV4_NET16_UNUSED="10.23" IPV6_NET32_UNUSED="fd00:23" -# Set to "net" for ns_create/ns_exec as their options requires +# Set to "net" for tst_ns_create/tst_ns_exec as their options requires # to specify a namespace type. Empty for ip command. NS_TYPE= @@ -28,7 +28,7 @@ NS_TYPE= tping= # Network namespaces handles for manipulating and executing commands inside -# namespaces. For 'ns_exec' handles are PIDs of daemonized processes running +# namespaces. For 'tst_ns_exec' handles are PIDs of daemonized processes running # in namespaces. NS_HANDLE0= NS_HANDLE1= @@ -40,7 +40,7 @@ NS_HANDLE1= IFCONF_IN6_ARG= # Program which will be used to enter and run other commands inside a network namespace. -# (ns_exec|ip) +# (tst_ns_exec|ip) NS_EXEC="ip" # Communication type between kernel and user space for basic setup: enabling and @@ -54,7 +54,7 @@ do_cleanup= netns_parse_args() { case $1 in - e) NS_EXEC="ns_exec" ;; + e) NS_EXEC="tst_ns_exec" ;; I) COMM_TYPE="ioctl"; tst_require_cmds ifconfig ;; esac } @@ -63,7 +63,7 @@ netns_usage() { echo "usage: $0 [ -e ] [ -I ]" echo "OPTIONS" - echo "-e Use ns_exec instead of ip" + echo "-e Use tst_ns_exec instead of ip" echo "-I Test ioctl (with ifconfig) instead of netlink (with ip)" } @@ -72,9 +72,6 @@ netns_setup() if [ "$NS_EXEC" = "ip" ]; then netns_ip_setup else - setns_check - [ $? -eq 32 ] && tst_brk TCONF "setns not supported" - NS_TYPE="net" netns_ns_exec_setup fi @@ -108,7 +105,7 @@ netns_cleanup() fi } -# Sets up NS_EXEC to use 'ns_exec', creates two network namespaces and stores +# Sets up NS_EXEC to use 'tst_ns_exec', creates two network namespaces and stores # their handles into NS_HANDLE0 and NS_HANDLE1 variables (in this case handles # are PIDs of daemonized processes running in these namespaces). Virtual # ethernet device is then created for each namespace. @@ -116,15 +113,15 @@ netns_ns_exec_setup() { local ret - NS_EXEC="ns_exec" + NS_EXEC="tst_ns_exec" - NS_HANDLE0=$(ns_create $NS_TYPE) + NS_HANDLE0=$(tst_ns_create $NS_TYPE) if [ $? -eq 1 ]; then tst_res TINFO "$NS_HANDLE0" tst_brk TBROK "unable to create a new network namespace" fi - NS_HANDLE1=$(ns_create $NS_TYPE) + NS_HANDLE1=$(tst_ns_create $NS_TYPE) if [ $? -eq 1 ]; then tst_res TINFO "$NS_HANDLE1" tst_brk TBROK "unable to create a new network namespace" @@ -133,7 +130,7 @@ netns_ns_exec_setup() $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link add veth0 type veth peer name veth1 || \ tst_brk TBROK "unable to create veth pair devices" - $NS_EXEC $NS_HANDLE0 $NS_TYPE ns_ifmove veth1 $NS_HANDLE1 + $NS_EXEC $NS_HANDLE0 $NS_TYPE tst_ns_ifmove veth1 $NS_HANDLE1 ret=$? [ $ret -eq 0 ] && return [ $ret -eq 32 ] && tst_brk TCONF "IFLA_NET_NS_PID not supported" diff --git a/testcases/kernel/containers/netns/netns_sysfs.sh b/testcases/kernel/containers/netns/netns_sysfs.sh index 179242721..814274fd0 100755 --- a/testcases/kernel/containers/netns/netns_sysfs.sh +++ b/testcases/kernel/containers/netns/netns_sysfs.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) Köry Maincent <kory.maincent@bootlin.com> 2020 # Copyright (c) 2015 Red Hat, Inc. +# Copyright (c) Linux Test Project, 2015-2023 # # Tests that a separate network namespace cannot affect sysfs contents # of the main namespace. @@ -18,12 +19,7 @@ do_setup() DUMMYDEV_HOST="dummy_test0" DUMMYDEV="dummy_test1" - setns_check - if [ $? -eq 32 ]; then - tst_brk TCONF "setns not supported" - fi - - NS_HANDLE=$(ns_create $NS_TYPE) + NS_HANDLE=$(tst_ns_create $NS_TYPE) if [ $? -eq 1 ]; then tst_res TINFO "$NS_HANDLE" tst_brk TBROK "unable to create a new network namespace" @@ -32,10 +28,10 @@ do_setup() ip link add $DUMMYDEV_HOST type dummy || \ tst_brk TBROK "failed to add a new (host) dummy device" - ns_exec $NS_HANDLE $NS_TYPE mount --make-rprivate /sys - ns_exec $NS_HANDLE $NS_TYPE ip link add $DUMMYDEV type dummy || \ + tst_ns_exec $NS_HANDLE $NS_TYPE mount --make-rprivate /sys + tst_ns_exec $NS_HANDLE $NS_TYPE ip link add $DUMMYDEV type dummy || \ tst_brk TBROK "failed to add a new dummy device" - ns_exec $NS_HANDLE $NS_TYPE mount -t sysfs none /sys 2>/dev/null + tst_ns_exec $NS_HANDLE $NS_TYPE mount -t sysfs none /sys 2>/dev/null } do_cleanup() @@ -47,8 +43,8 @@ do_cleanup() do_test() { - EXPECT_PASS ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV - EXPECT_FAIL ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV_HOST + EXPECT_PASS tst_ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV + EXPECT_FAIL tst_ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV_HOST EXPECT_FAIL test -e /sys/class/net/$DUMMYDEV } diff --git a/testcases/kernel/containers/pidns/Makefile b/testcases/kernel/containers/pidns/Makefile index 5f8383c3c..180bc7c90 100644 --- a/testcases/kernel/containers/pidns/Makefile +++ b/testcases/kernel/containers/pidns/Makefile @@ -4,8 +4,7 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lpthread -lrt -lclone $(LDLIBS) +LDLIBS := -lrt $(LDLIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/pidns/pidns01.c b/testcases/kernel/containers/pidns/pidns01.c index 5080b6fad..8b856ec90 100644 --- a/testcases/kernel/containers/pidns/pidns01.c +++ b/testcases/kernel/containers/pidns/pidns01.c @@ -8,7 +8,7 @@ /*\ * [Description] * - * Clone a process with CLONE_NEWNS flag and check: + * Clone a process with CLONE_NEWPID flag and check: * * - child process ID must be 1 * - parent process ID must be 0 @@ -17,29 +17,36 @@ #include "tst_test.h" #include "lapi/sched.h" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { pid_t cpid, ppid; - cpid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - TST_EXP_PASS(cpid == 1); - TST_EXP_PASS(ppid == 0); - - return 0; + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); } static void run(void) { - int ret; - - ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } } static struct tst_test test = { .test_all = run, .needs_root = 1, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/pidns/pidns02.c b/testcases/kernel/containers/pidns/pidns02.c index b8913d3f6..f23178cb6 100644 --- a/testcases/kernel/containers/pidns/pidns02.c +++ b/testcases/kernel/containers/pidns/pidns02.c @@ -7,7 +7,7 @@ /*\ * [Description] * - * Clone a process with CLONE_NEWNS flag and check: + * Clone a process with CLONE_NEWPID flag and check: * * - child session ID must be 1 * - parent process group ID must be 1 @@ -16,29 +16,37 @@ #include "tst_test.h" #include "lapi/sched.h" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { - pid_t sid, pgid; + TST_EXP_EQ_LI(getsid(0), 0); + TST_EXP_EQ_LI(getpgid(0), 0); - sid = getsid(0); - pgid = getpgid(0); + tst_res(TINFO, "setsid()"); + SAFE_SETSID(); - TST_EXP_PASS(sid == 1); - TST_EXP_PASS(pgid == 1); - - return 0; + TST_EXP_EQ_LI(getsid(0), 1); + TST_EXP_EQ_LI(getpgid(0), 1); } static void run(void) { - int ret; - - ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } } static struct tst_test test = { .test_all = run, .needs_root = 1, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/pidns/pidns03.c b/testcases/kernel/containers/pidns/pidns03.c index 122ba7891..d662ca9d5 100644 --- a/testcases/kernel/containers/pidns/pidns03.c +++ b/testcases/kernel/containers/pidns/pidns03.c @@ -17,7 +17,7 @@ #define PROCDIR "proc" -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { char proc_self[10]; @@ -28,8 +28,6 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) SAFE_UMOUNT(PROCDIR); TST_EXP_PASS(strcmp(proc_self, "1"), PROCDIR"/self contains 1:"); - - return 0; } static void setup(void) @@ -45,11 +43,15 @@ static void cleanup(void) static void run(void) { - int ret; + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - ret = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } } static struct tst_test test = { @@ -57,5 +59,10 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, + .forks_child = 1, .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/pidns/pidns04.c b/testcases/kernel/containers/pidns/pidns04.c index 9ac0e5aca..bed75a082 100644 --- a/testcases/kernel/containers/pidns/pidns04.c +++ b/testcases/kernel/containers/pidns/pidns04.c @@ -1,150 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -* File: pidns04.c -* -* Description: -* The pidns04.c testcase builds into the ltp framework to verify -* the basic functionality of PID Namespace. -* -* Verify that: -* 1. When parent clone a process with flag CLONE_NEWPID, the process ID of -* child should be one. -* -* 2. When parent clone a process with flag CLONE_NEWPID, the parent process ID -* of should be zero. -* -* 3. The container init process (one), should not get killed by the SIGKILL in -* the childNS -* -* Total Tests: -* -* Test Name: pidns04 -* -* Test Assertion & Strategy: -* -* From main() clone a new child process with passing the clone_flag as -* CLONE_NEWPID. -* The container init, should not get killed by the SIGKILL inside the child NS. -* Usage: <for command-line> -* pidns04 -* -* History: -* -* FLAG DATE NAME DESCRIPTION -* 08/10/08 Veerendra C <vechandr@in.ibm.com> Verifies killing of cont init. -* -*******************************************************************************/ -#define _GNU_SOURCE 1 -#include <sys/wait.h> -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#define CLEANUP cleanup -#include "pidns_helper.h" -#include "test.h" - -#define INIT_PID 1 -#define CHILD_PID 1 -#define PARENT_PID 0 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that child container does + * not get kill itself with SIGKILL. + */ -char *TCID = "pidns04"; -int TST_TOTAL = 1; -int fd[2]; +#include <sys/wait.h> +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn1() - Inside container -*/ -static int child_fn1(void *ttype) +static void child_func(void) { - int exit_val; - pid_t cpid, ppid; - cpid = getpid(); - ppid = getppid(); - char mesg[] = "I was not killed !"; - /* Child process closes up read side of pipe */ - close(fd[0]); + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Comparing the values to make sure pidns is created correctly */ - if ((cpid == CHILD_PID) && (ppid == PARENT_PID)) { - printf("PIDNS test is running inside container\n"); - kill(INIT_PID, SIGKILL); - /* Verifying whether the container init is not killed, " - If so writing into the pipe created in the parent NS" */ + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - /* Send "mesg" through the write side of pipe */ - write(fd[1], mesg, (strlen(mesg) + 1)); - exit_val = 0; - } else { - printf("got unexpected result of cpid=%d ppid=%d\n", - cpid, ppid); - exit_val = 1; - } - exit(exit_val); -} + tst_res(TINFO, "Trying to kill container from within container"); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + SAFE_KILL(1, SIGKILL); + + tst_res(TINFO, "Container is up and running"); } -int main(void) +static void run(void) { - int nbytes, status; - char readbuffer[80]; - - setup(); - - pipe(fd); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn1, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, CLEANUP, "clone failed"); - } else if (wait(&status) == -1) { - tst_brkm(TFAIL | TERRNO, CLEANUP, "wait failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + pid_t pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - /* Parent process closes up write side of pipe */ - close(fd[1]); - /* Read in a string from the pipe */ - nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); - - if (0 <= nbytes) { - tst_resm(TPASS, "Container init : %s", readbuffer); - } else { - tst_brkm(TFAIL, CLEANUP, - "Container init is killed by SIGKILL !!!"); - } - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - tst_resm(TFAIL, "Container init pid exited abnormally"); - } else if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "Container init pid got killed by signal %d", - WTERMSIG(status)); - } - CLEANUP(); - - tst_exit(); - + tst_reap_children(); } -static void cleanup(void) -{ - close(fd[0]); -} +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns05.c b/testcases/kernel/containers/pidns/pidns05.c index 79e146e36..0e7739aaa 100644 --- a/testcases/kernel/containers/pidns/pidns05.c +++ b/testcases/kernel/containers/pidns/pidns05.c @@ -1,256 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* -* Assertion: -* a) Create a container. -* b) Create many levels of child containers inside this container. -* c) Now do kill -9 init , outside of the container. -* d) This should kill all the child containers. -* (containers created at the level below) -* -* Description: -* 1. Parent process clone a process with flag CLONE_NEWPID -* 2. The container will recursively loop and creates 4 more containers. -* 3. All the container init's goes into sleep(), waiting to be terminated. -* 4. The parent process will kill child[3] by passing SIGKILL -* 5. Now parent process, verifies the child containers 4 & 5 are destroyed. -* 6. If they are killed then -* Test passed -* else Test failed. -* -* Test Name: pidns05 -* -* History: -* -* FLAG DATE NAME DESCRIPTION -* 31/10/08 Veerendra C <vechandr@in.ibm.com> Verifies killing of NestedCont's -* -*******************************************************************************/ -#define _GNU_SOURCE 1 + * Copyright (c) Veerendra C <vechandr@in.ibm.com>, 2008 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and create many levels of child + * containers. Then kill container init process from parent and check if all + * containers have been killed. + */ + #include <sys/wait.h> -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "pidns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" +#include "lapi/sched.h" -#define INIT_PID 1 -#define CINIT_PID 1 -#define PARENT_PID 0 #define MAX_DEPTH 5 -char *TCID = "pidns05"; -int TST_TOTAL = 1; -int fd[2]; - -int max_pid(void) -{ - FILE *fp; - int ret; - - fp = fopen("/proc/sys/kernel/pid_max", "r"); - if (fp != NULL) { - fscanf(fp, "%d", &ret); - fclose(fp); - } else { - tst_resm(TBROK, "Cannot open /proc/sys/kernel/pid_max"); - ret = -1; - } - return ret; -} +static struct tst_clone_args clone_args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD +}; +static pid_t pid_max; -/* find_cinit_pids() iteratively finds the pid's having same PGID as its parent. - * Input parameter - Accepts pointer to pid_t : To copy the pid's matching. - * Returns - the number of pids matched. -*/ -int find_cinit_pids(pid_t * pids) +static void child_func(int *level) { - int next = 0, pid_max, i; - pid_t parentpid, pgid, pgid2; + pid_t cpid, ppid; - pid_max = max_pid(); - parentpid = getpid(); - pgid = getpgid(parentpid); + cpid = tst_getpid(); + ppid = getppid(); - /* The loop breaks, when the loop counter reaches the parentpid value */ - for (i = parentpid + 1; i != parentpid; i++) { - if (i > pid_max) - i = 2; + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - pgid2 = getpgid(i); - if (pgid2 == pgid) { - pids[next] = i; - next++; - } + if (*level >= MAX_DEPTH) { + TST_CHECKPOINT_WAKE(0); + return; } - return next; -} - -/* -* create_nested_container() Recursively create MAX_DEPTH nested containers -*/ -int create_nested_container(void *vtest) -{ - int exit_val; - int ret, count, *level; - pid_t cpid, ppid; - cpid = getpid(); - ppid = getppid(); - char mesg[] = "Nested Containers are created"; - level = (int *)vtest; - count = *level; + (*level)++; - /* Child process closes up read side of pipe */ - close(fd[0]); - - /* Comparing the values to make sure pidns is created correctly */ - if (cpid != CINIT_PID || ppid != PARENT_PID) { - printf("Got unexpected cpid and/or ppid (cpid=%d ppid=%d)\n", - cpid, ppid); - exit_val = 1; - } - if (count > 1) { - count--; - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWPID, - create_nested_container, - (void *)&count); - if (ret == -1) { - printf("clone failed; errno = %d : %s\n", - ret, strerror(ret)); - exit_val = 1; - } else - exit_val = 0; - } else { - /* Sending mesg, 'Nested containers created' through the pipe */ - write(fd[1], mesg, (strlen(mesg) + 1)); - exit_val = 0; + if (!SAFE_CLONE(&clone_args)) { + child_func(level); + return; } - close(fd[1]); pause(); - - return exit_val; } -void kill_nested_containers() +static int find_cinit_pids(pid_t *pids) { - int orig_count, new_count, status = 0, i; - pid_t pids[MAX_DEPTH]; - pid_t pids_new[MAX_DEPTH]; + int pid; + int next = 0; + pid_t parentpid, pgid, pgid2; - orig_count = find_cinit_pids(pids); - kill(pids[MAX_DEPTH - 3], SIGKILL); - sleep(1); + parentpid = tst_getpid(); + pgid = SAFE_GETPGID(parentpid); - /* After killing child container, getting the New PID list */ - new_count = find_cinit_pids(pids_new); + for (pid = 2; pid < pid_max; pid++) { + if (pid == parentpid) + continue; - /* Verifying that the child containers were destroyed when parent is killed */ - if (orig_count - 2 != new_count) - status = -1; + pgid2 = getpgid(pid); - for (i = 0; i < new_count; i++) { - if (pids[i] != pids_new[i]) - status = -1; + if (pgid2 == pgid) { + pids[next] = pid; + next++; + } } - if (status == 0) - tst_resm(TPASS, "The number of containers killed are %d", - orig_count - new_count); - else - tst_resm(TFAIL, "Failed to kill the sub-containers of " - "the container %d", pids[MAX_DEPTH - 3]); - - /* Loops through the containers created to exit from sleep() */ - for (i = 0; i < MAX_DEPTH; i++) { - kill(pids[i], SIGKILL); - waitpid(pids[i], &status, 0); - } + return next; } static void setup(void) { - tst_require_root(); - check_newpid(); + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); } -int main(void) +static void run(void) { - int ret, nbytes, status; - char readbuffer[80]; - pid_t pid, pgid; - int count = MAX_DEPTH; - - setup(); + int i, status, children; + int level = 0; + pid_t pids_new[MAX_DEPTH]; + pid_t pids[MAX_DEPTH]; + pid_t pid; - /* - * XXX (garrcoop): why in the hell is this fork-wait written this way? - * This doesn't add up with the pattern used for the rest of the tests, - * so I'm pretty damn sure this test is written incorrectly. - */ - pid = fork(); - if (pid == -1) { - tst_brkm(TBROK | TERRNO, NULL, "fork failed"); - } else if (pid != 0) { - /* - * NOTE: use waitpid so that we know we're waiting for the - * _top-level_ child instead of a spawned subcontainer. - * - * XXX (garrcoop): Might want to mask SIGCHLD in the top-level - * child too, or not *shrugs*. - */ - if (waitpid(pid, &status, 0) == -1) { - perror("wait failed"); - } - if (WIFEXITED(status)) - exit(WEXITSTATUS(status)); - else - exit(status); + pid = SAFE_CLONE(&clone_args); + if (!pid) { + child_func(&level); + return; } - /* To make all the containers share the same PGID as its parent */ - setpgid(0, 0); + TST_CHECKPOINT_WAIT(0); - pid = getpid(); - pgid = getpgid(pid); - SAFE_PIPE(NULL, fd); + TST_EXP_POSITIVE(find_cinit_pids(pids)); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, - create_nested_container, (void *)&count)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } + SAFE_KILL(pid, SIGKILL); + SAFE_WAITPID(0, &status, 0); - close(fd[1]); - /* Waiting for the MAX_DEPTH number of containers to be created */ - nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); - close(fd[0]); - if (nbytes > 0) - tst_resm(TINFO, " %d %s", MAX_DEPTH, readbuffer); - else - tst_brkm(TFAIL, NULL, "unable to create %d containers", - MAX_DEPTH); + children = find_cinit_pids(pids_new); - /* Kill the container created */ - kill_nested_containers(); + if (children > 0) { + tst_res(TFAIL, "%d children left after sending SIGKILL", children); - tst_exit(); + for (i = 0; i < MAX_DEPTH; i++) { + kill(pids[i], SIGKILL); + waitpid(pids[i], &status, 0); + } + + return; + } + + tst_res(TPASS, "No children left after sending SIGKILL to the first child"); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns06.c b/testcases/kernel/containers/pidns/pidns06.c index d6623941a..c85a875e4 100644 --- a/testcases/kernel/containers/pidns/pidns06.c +++ b/testcases/kernel/containers/pidns/pidns06.c @@ -1,133 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -************************************************************************* -* Description: -* Testcase tries killing of the parent namespace pid by the container-init. -* It also tries killing of non-existent PID, by the container-init. -* Returns Success if Unable to kill, and proper error number is set. -* else Returns Failure -* -* Steps: -* 1. Parent process clone a process with flag CLONE_NEWPID -* 2. The pid of the parent namespace is passed to the container. -* 3. Container receieves the PID and passes SIGKILL to this PID. -* 4. If kill() is unsuccessful and the errno is set to 'No Such process' -* then sets PASS -* else, -* sets FAIL -* 5. It also verifies by passing SIGKILL to FAKE_PID -* 6. If kill() is unsuccessful and the errno is set to 'No Such process' -* then sets PASS -* else, -* sets FAIL -* -*******************************************************************************/ -#define _GNU_SOURCE 1 -#include <stdio.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <assert.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include "pidns_helper.h" -#include "test.h" + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -#define CINIT_PID 1 -#define PARENT_PID 0 -#define FAKE_PID -1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that parent process can't + * be killed from child namespace. + */ -char *TCID = "pidns06"; -int TST_TOTAL = 1; +#include "tst_test.h" +#include "lapi/sched.h" -/* - * kill_pid_in_childfun() - * Cont-init tries to kill the parent-process using parent's global Pid. - * Also checks passing SIGKILL to non existent PID in the container. - */ -static int kill_pid_in_childfun(void *vtest) +static void child_func(int pid) { - int cpid, ppid, *par_pid; - int ret = 0; - cpid = getpid(); - ppid = getppid(); - par_pid = (int *)vtest; + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Checking the values to make sure pidns is created correctly */ - if (cpid != CINIT_PID || ppid != PARENT_PID) { - printf("Unexpected result for Container: init " - "pid=%d ppid=%d\n", cpid, ppid); - exit(1); - } + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - /* - * While trying kill() of the pid of the parent namespace.. - * Check to see if the errno was set to the expected, value of 3 : ESRCH - */ - ret = kill(*par_pid, SIGKILL); - if (ret == -1 && errno == ESRCH) { - printf("Container: killing parent pid=%d failed as expected " - "with ESRCH\n", *par_pid); - } else { - printf("Container: killing parent pid=%d, didn't fail as " - "expected with ESRCH (%d) and a return value of -1. Got " - "%d (\"%s\") and a return value of %d instead.\n", - *par_pid, ESRCH, errno, strerror(errno), ret); - exit(1); - } - /* - * While killing non-existent pid in the container, - * Check to see if the errno was set to the expected, value of 3 : ESRCH - */ - ret = kill(FAKE_PID, SIGKILL); - if (ret == -1 && errno == ESRCH) { - printf("Container: killing non-existent pid failed as expected " - "with ESRCH\n"); - } else { - printf("Container: killing non-existent pid, didn't fail as " - "expected with ESRCH (%d) and a return value of -1. Got " - "%d (\"%s\") and a return value of %d instead.\n", - ESRCH, errno, strerror(errno), ret); - exit(1); - } + tst_res(TINFO, "Trying to kill parent from within container"); - exit(0); + TST_EXP_FAIL(kill(pid, SIGKILL), ESRCH); } -static void setup(void) +static void run(void) { - tst_require_root(); - check_newpid(); -} - -int main(void) -{ - int status; - - setup(); - + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; pid_t pid = getpid(); - tst_resm(TINFO, "Parent: Passing the pid of the process %d", pid); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, kill_pid_in_childfun, - (void *)&pid)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } else if (wait(&status) == -1) { - tst_brkm(TFAIL | TERRNO, NULL, "wait failed"); + if (!SAFE_CLONE(&args)) { + child_func(pid); + return; } - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns10.c b/testcases/kernel/containers/pidns/pidns10.c index b38b9fd18..c2a9094b6 100644 --- a/testcases/kernel/containers/pidns/pidns10.c +++ b/testcases/kernel/containers/pidns/pidns10.c @@ -1,112 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns10.c -* * -* * Description: -* * The pidns10.c testcase verifies inside the container, if kill(-1, signal) -* * fails with ESRCH when there are no processes in container. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Invoke kill(-1, SIGUSR1) inside container and check return code and error. -* * kill() should have failed;except swapper & init, no process is inside. -* * -* * Usage: <for command-line> -* * pidns10 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * <gowrishankar.m@in.ibm.com> -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include <sys/wait.h> -#include <sys/types.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns10"; -int TST_TOTAL = 1; + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -int child_fn(void *); +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that killing subprocesses + * from child namespace will raise ESRCH error. + */ -#define CHILD_PID 1 -#define PARENT_PID 0 +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - int exit_val, ret; - pid_t pid, ppid; + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Set process id and parent pid */ - pid = getpid(); - ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("cinit: pidns was not created.\n"); - return 1; - } + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - if ((ret = kill(-1, SIGUSR1)) == -1 && errno == ESRCH) { - printf("cinit: kill(-1, sig) failed with -1 / ESRCH as " - "expected\n"); - exit_val = 0; - } else { - printf("cinit: kill(-1, sig) didn't fail with -1 / ESRCH " - "(%d); failed with %d / %d instead", ESRCH, ret, errno); - exit_val = 1; - } - exit(exit_val); -} + tst_res(TINFO, "Trying to kill all subprocesses from within container"); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_FAIL(kill(-1, SIGKILL), ESRCH); } -int main(void) +static void run(void) { - int status; - pid_t pid; - - setup(); - - pid = getpid(); - - /* Container creation on PID namespace */ - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TBROK | TTERRNO, NULL, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - sleep(1); - if (wait(&status) < 0) - tst_resm(TWARN, "parent: waitpid() failed."); - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - tst_resm(TBROK, "container was terminated abnormally"); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns12.c b/testcases/kernel/containers/pidns/pidns12.c index fb1ec90ca..1811dbc36 100644 --- a/testcases/kernel/containers/pidns/pidns12.c +++ b/testcases/kernel/containers/pidns/pidns12.c @@ -25,11 +25,11 @@ static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LT sig_pid = si->si_pid; } -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { struct sigaction sa; - TST_EXP_EQ_LI(getpid(), 1); + TST_EXP_EQ_LI(tst_getpid(), 1); TST_EXP_EQ_LI(getppid(), 0); sa.sa_flags = SA_SIGINFO; @@ -41,21 +41,25 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); TST_EXP_EQ_LI(sig_pid, 0); - - return 0; } static void run(void) { - int ret; - - ret = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + int pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; + } TST_CHECKPOINT_WAIT(0); - SAFE_KILL(ret, SIGUSR1); + SAFE_KILL(pid, SIGUSR1); TST_CHECKPOINT_WAKE(0); } @@ -63,5 +67,10 @@ static void run(void) static struct tst_test test = { .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/pidns/pidns13.c b/testcases/kernel/containers/pidns/pidns13.c index 6a155027c..65fcc4443 100644 --- a/testcases/kernel/containers/pidns/pidns13.c +++ b/testcases/kernel/containers/pidns/pidns13.c @@ -42,7 +42,7 @@ static void child_signal_handler(int sig, siginfo_t *si, void *unused LTP_ATTRIBUTE_UNUSED) { tst_res(TWARN, "cinit(pid %d): Caught signal! sig=%d, si_fd=%d, si_code=%d", - getpid(), sig, si->si_fd, si->si_code); + tst_getpid(), sig, si->si_fd, si->si_code); } static void child_fn(unsigned int cinit_no) @@ -54,7 +54,7 @@ static void child_fn(unsigned int cinit_no) pid_t pid, ppid; int flags; - pid = tst_syscall(__NR_getpid); + pid = tst_getpid(); ppid = getppid(); if (pid != CHILD_PID || ppid != PARENT_PID) tst_brk(TBROK, "cinit%u: pidns not created.", cinit_no); @@ -104,7 +104,10 @@ static void child_fn(unsigned int cinit_no) static void run(void) { - const struct tst_clone_args cargs = { CLONE_NEWPID, SIGCHLD }; + const struct tst_clone_args cargs = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; SAFE_PIPE(pipe_fd); diff --git a/testcases/kernel/containers/pidns/pidns16.c b/testcases/kernel/containers/pidns/pidns16.c index 2ee61065a..313b0a097 100644 --- a/testcases/kernel/containers/pidns/pidns16.c +++ b/testcases/kernel/containers/pidns/pidns16.c @@ -1,157 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** - -* * Test Assertion. -* *---------------- -* * kill -USR1 container_init -* * - from the parent process and also inside a container -* * - Where init has defined a custom handler for USR1 -* * - Should call the handler and -* * - Verify whether the signal handler is called from the proper process. -* * -* * Description: -* * Create PID namespace container. -* * Container init defines the handler for SIGUSR1 and waits indefinetly. -* * Parent sends SIGUSR1 to container init. -* * The signal handler is handled and the cont-init resumes normally. -* * From the container, again the signal SIGUSR1 is sent. -* * In the sig-handler check if it's invoked from correct pid(parent/container) -* * If cont-init wakes up properly - -* * it will return expected value at exit which is verified at the end. -* * -* * History: -* * DATE NAME DESCRIPTION -* * 04/11/08 Veerendra C <vechandr@in.ibm.com> Verifying cont init kill -USR1 -* -*******************************************************************************/ -#include "config.h" + * Copyright (c) International Business Machines Corp., 2007 + * 04/11/08 Veerendra C <vechandr@in.ibm.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and verifies that siginfo->si_pid is + * set to 0 if sender (parent process) sent the signal. Then send signal from + * container itself and check if siginfo->si_pid is set to 1. + */ #define _GNU_SOURCE 1 -#include <stdio.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <sys/types.h> #include <signal.h> -#include <unistd.h> -#include "pidns_helper.h" -#include "test.h" - -#define CHILD_PID 1 -#define PARENT_PID 0 +#include "tst_test.h" +#include "lapi/sched.h" -char *TCID = "pidns16"; -int TST_TOTAL = 3; +static volatile int signal_pid; -void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - static int c = 1; - pid_t expected_pid; - - /* Verifying from which process the signal handler is signalled */ - - switch (c) { - case 1: - expected_pid = PARENT_PID; - break; - case 2: - expected_pid = CHILD_PID; - break; - default: - tst_resm(TBROK, "child should NOT be signalled 3+ times"); - return; - } - - if (si->si_pid == expected_pid) - tst_resm(TPASS, "child is signalled from expected pid %d", - expected_pid); - else - tst_resm(TFAIL, "child is signalled from unexpected pid %d," - " expecting pid %d", si->si_pid, expected_pid); - - c++; + signal_pid = si->si_pid; } -/* - * child_fn() - Inside container - */ -int child_fn(void *ttype) +static void child_func(void) { struct sigaction sa; - pid_t pid, ppid; + pid_t cpid, ppid; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if ((pid != CHILD_PID) || (ppid != PARENT_PID)) - tst_resm(TBROK, "pidns is not created."); + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); + + tst_res(TINFO, "Catching SIGUSR1 signal"); - /* Set signal handler for SIGUSR1, also mask other signals */ sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); + SAFE_SIGFILLSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) - tst_resm(TBROK, "%d: sigaction() failed", pid); - - pause(); - tst_resm(TINFO, "Container: Resumed after receiving SIGUSR1 " - "from parentNS "); - if (kill(pid, SIGUSR1) != 0) { - tst_resm(TFAIL, "kill(SIGUSR1) fails."); - } - tst_resm(TINFO, "Container: Resumed after sending SIGUSR1 " - "from container itself"); - _exit(10); -} + SAFE_SIGACTION(SIGUSR1, &sa, NULL); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + TST_EXP_EQ_LI(signal_pid, 0); + + tst_res(TINFO, "Sending SIGUSR1 from container itself"); + + SAFE_KILL(cpid, SIGUSR1); + + TST_EXP_EQ_LI(signal_pid, 1); } -/*********************************************************************** -* M A I N -***********************************************************************/ -int main() +static void run(void) { - int status; - pid_t cpid; - - setup(); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + pid_t pid; - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); + signal_pid = -1; - if (cpid < 0) { - tst_resm(TBROK, "clone() failed."); + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - sleep(1); - if (kill(cpid, SIGUSR1) != 0) { - tst_resm(TFAIL, "kill(SIGUSR1) fails."); - } - sleep(1); - if (waitpid(cpid, &status, 0) < 0) - tst_resm(TWARN, "waitpid() failed."); - - if ((WIFEXITED(status)) && (WEXITSTATUS(status) == 10)) - tst_resm(TPASS, "container init continued successfuly, " - "after handling signal -USR1"); - else - tst_resm(TFAIL, "c-init failed to continue after " - "passing kill -USR1"); - tst_exit(); + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Sending SIGUSR1 from parent"); + + SAFE_KILL(pid, SIGUSR1); + + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns17.c b/testcases/kernel/containers/pidns/pidns17.c index cf0c5826f..4633ec14b 100644 --- a/testcases/kernel/containers/pidns/pidns17.c +++ b/testcases/kernel/containers/pidns/pidns17.c @@ -1,162 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns17.c -* * -* * Description: -* * The pidns17.c testcase verifies inside the container, if kill(-1, SIGUSR1) -* * terminates all children running inside. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Spawn many children inside it. -* * Invoke kill(-1, SIGUSR1) inside container and check if it terminates -* * all children. -* * -* * Usage: <for command-line> -* * pidns17 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * <gowrishankar.m@in.ibm.com> -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include <sys/wait.h> -#include <sys/types.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> -#include "pidns_helper.h" -#include "test.h" + * Copyright (c) International Business Machines Corp., 2007 + * 13/11/08 Gowrishankar M <gowrishankar.m@in.ibm.com> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -char *TCID = "pidns17"; -int TST_TOTAL = 1; +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and spawn many children inside the + * container. Then terminate all children and check if they were signaled. + */ -int child_fn(void *); +#include <sys/wait.h> +#include "tst_test.h" +#include "lapi/sched.h" -#define CHILD_PID 1 -#define PARENT_PID 0 +#define CHILDREN_NUM 10 -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - int children[10], exit_val, i, status; - pid_t pid, ppid; + int children[CHILDREN_NUM], status; + unsigned int i; + pid_t cpid, ppid; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("cinit: pidns was not created\n"); - exit(1); - } - exit_val = 0; + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); + + tst_res(TINFO, "Spawning %d children", CHILDREN_NUM); - /* Spawn many children */ - for (i = 0; i < ARRAY_SIZE(children); i++) { - switch ((children[i] = fork())) { - case -1: - perror("fork failed"); - exit_val = 1; - break; - case 0: + for (i = 0; i < CHILDREN_NUM; i++) { + children[i] = SAFE_FORK(); + if (!children[i]) { pause(); - /* XXX (garrcoop): why exit with an exit code of 2? */ - exit(2); - break; - default: - /* fork succeeded. */ - break; + return; } } - /* wait for last child to get scheduled */ - sleep(1); - if (kill(-1, SIGUSR1) == -1) { - perror("cinit: kill(-1, SIGUSR1) failed"); - exit_val = 1; - } + tst_res(TINFO, "Terminate children with SIGUSR1"); - for (i = 0; i < ARRAY_SIZE(children); i++) { - if (waitpid(children[i], &status, 0) == -1) { - perror("cinit: waitpid failed"); - kill(children[i], SIGTERM); - waitpid(children[i], &status, 0); - exit_val = 1; - } - if (!(WIFSIGNALED(status) || WTERMSIG(status) == SIGUSR1)) { - /* - * XXX (garrcoop): this status reporting is overly - * noisy. Someone obviously needs to read the - * constraints documented in wait(2) a bit more - * closely -- in particular the relationship between - * WIFEXITED and WEXITSTATUS, and WIFSIGNALED and - * WTERMSIG. - */ - printf("cinit: found a child alive still " - "%d exit: %d, %d, signal %d, %d", i, - WIFEXITED(status), WEXITSTATUS(status), - WIFSIGNALED(status), WTERMSIG(status)); - exit_val = 1; - } - } - if (exit_val == 0) - printf("cinit: all children have terminated.\n"); + SAFE_KILL(-1, SIGUSR1); - exit(exit_val); -} + for (i = 0; i < CHILDREN_NUM; i++) { + SAFE_WAITPID(children[i], &status, 0); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_EQ_LI(WIFSIGNALED(status), 1); + TST_EXP_EQ_LI(WTERMSIG(status), SIGUSR1); + } } -int main(void) +static void run(void) { - int status; - pid_t pid; - - setup(); - - pid = getpid(); - - /* Container creation on PID namespace */ - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TBROK | TTERRNO, NULL, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - sleep(1); - if (wait(&status) == -1) - tst_resm(TFAIL, "waitpid failed"); - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "container exited abnormally"); - else if (WIFSIGNALED(status)) - tst_resm(TFAIL, - "container was signaled with signal = %d", - WTERMSIG(status)); - - tst_exit(); - } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns20.c b/testcases/kernel/containers/pidns/pidns20.c index 9f369699a..914820865 100644 --- a/testcases/kernel/containers/pidns/pidns20.c +++ b/testcases/kernel/containers/pidns/pidns20.c @@ -26,18 +26,18 @@ static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LT signals++; } -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_func(void) { struct sigaction sa; sigset_t newset; pid_t cpid, ppid; - cpid = getpid(); + cpid = tst_getpid(); ppid = getppid(); if (cpid != 1 || ppid != 0) { tst_res(TFAIL, "Got unexpected result of cpid=%d ppid=%d", cpid, ppid); - return 0; + return; } SAFE_SIGEMPTYSET(&newset); @@ -56,30 +56,34 @@ static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) if (signals != 1) { tst_res(TFAIL, "Received %d signals", signals); - return 0; + return; } if (last_signo != SIGUSR1) { tst_res(TFAIL, "Received %s signal", tst_strsig(last_signo)); - return 0; + return; } tst_res(TPASS, "Received SIGUSR1 signal after unblock"); - - return 0; } static void run(void) { - int ret; - - ret = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, NULL); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + int pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; + } TST_CHECKPOINT_WAIT(0); - SAFE_KILL(ret, SIGUSR1); + SAFE_KILL(pid, SIGUSR1); TST_CHECKPOINT_WAKE(0); } @@ -87,5 +91,10 @@ static void run(void) static struct tst_test test = { .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, }; diff --git a/testcases/kernel/containers/pidns/pidns30.c b/testcases/kernel/containers/pidns/pidns30.c index c8b0806c0..4a8bc5e2b 100644 --- a/testcases/kernel/containers/pidns/pidns30.c +++ b/testcases/kernel/containers/pidns/pidns30.c @@ -1,296 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) Bull S.A.S. 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns30.c -* -* Description: -* This testcase checks if the si_pid is correctly set when a process -* that has registered for notification on a posix mqueue is in a -* descendant namespace wrt the process that sends a message to that posix -* mqueue. -* -* Test Assertion & Strategy: -* Parent Child -* -------------------------------------------------------------------------- -* Create a POSIX mqueue. -* Create a PID namespace container. -* Open that mqueue for reading -* Register for notification when a -* message arrives in that mqueue -* Install a handler for SIGUSR1. -* Write something to the mqueue. -* Inside the handler, check that -* si_pid is set to 0 -* -* Usage: <for command-line> -* pidns30 -* -* History: -* DATE NAME DESCRIPTION -* 01/12/08 Nadia Derbey Creation of this test. -* <Nadia.Derbey@bull.net> -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include <sys/wait.h> -#include <sys/types.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <mqueue.h> -#include "lapi/syscalls.h" -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns30"; -int TST_TOTAL = 1; - -char *mqname = "mq1"; -int result = TFAIL; - -int father_to_child[2]; -int child_to_father[2]; - -#define CHILD_PID 1 -#define PARENT_PID 0 + * Copyright (c) Bull S.A.S. 2008 + * 01/12/08 Nadia Derbey <Nadia.Derbey@bull.net> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -#define MSG "HOW ARE YOU" -#define MSG_PRIO 1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag, register notification on a posix + * mqueue and send a mqueue message from the parent. Then check if signal + * notification contains si_pid of the parent. + */ -#define NO_STEP -1 -#define F_STEP_0 0x00 -#define F_STEP_1 0x01 -#define F_STEP_2 0x02 -#define F_STEP_3 0x03 -#define C_STEP_0 0x10 -#define C_STEP_1 0x11 -#define C_STEP_2 0x12 +#define _GNU_SOURCE +#include <signal.h> +#include <mqueue.h> +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" +#include "lapi/sched.h" -mqd_t rc = -1; -mqd_t mqd = -1; +#define MQNAME "/LTP_PIDNS30_MQ" -static void remove_pipe(int *fd) -{ - close(fd[0]); - close(fd[1]); -} +static mqd_t mqd = -1; +static siginfo_t info; +static volatile int received; static void remove_mqueue(mqd_t mqd) { - mq_close(mqd); - tst_syscall(__NR_mq_unlink, mqname); -} + if (mqd != -1) + SAFE_MQ_CLOSE(mqd); -static void cleanup(void) -{ - if (mqd != -1) { - remove_mqueue(mqd); - } - if (rc != -1) { - remove_mqueue(rc); - } - remove_pipe(father_to_child); - remove_pipe(child_to_father); + mq_unlink(MQNAME); } -static void cleanup_child(void) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - if (mqd != -1) { - tst_syscall(__NR_mq_notify, mqd, NULL); - } - cleanup(); + received = 1; + memcpy(&info, si, sizeof(info)); } -/* - * child_signal_handler() - to handle SIGUSR1 - * - * XXX (garrcoop): add calls to cleanup_child() -- or should this be handled - * from the libltp signal handler? - */ -static void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_func(void) { - char buf[256]; - struct mq_attr attr; - - if (si->si_signo != SIGUSR1) { - printf("received signal = %d unexpectedly\n", si->si_signo); - return; - } - - if (si->si_code != SI_MESGQ) { - printf("expected signal code SI_MESGQ; got %d instead\n", - si->si_code); - return; - } - - if (si->si_pid) { - printf("expected signal originator PID = 0; got %d instead\n", - si->si_pid); - return; - } else { - printf("signal originator PID = 0\n"); - result = TPASS; - } - - /* - * Now read the message - Be silent on errors since this is not the - * test purpose. - */ - rc = mq_getattr(si->si_int, &attr); - if (rc != -1) - mq_receive(si->si_int, buf, attr.mq_msgsize, NULL); -} - -/* - * child_fn() - Inside container - * - * XXX (garrcoop): add more calls to cleanup_child()? - */ -int child_fn(void *arg) -{ - pid_t pid, ppid; + pid_t cpid, ppid; struct sigaction sa; struct sigevent notif; - char buf[5]; + mqd_t mqd_child; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("pidns was not created\n"); - return 1; - } - - /* Close the appropriate end of each pipe */ - close(child_to_father[0]); - close(father_to_child[1]); + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - while (read(father_to_child[0], buf, 1) != 1) - sleep(1); + TST_CHECKPOINT_WAIT(0); - mqd = tst_syscall(__NR_mq_open, mqname, O_RDONLY, 0, NULL); - if (mqd == -1) { - perror("mq_open failed"); - return 1; - } else - printf("mq_open succeeded\n"); + tst_res(TINFO, "Register notification on posix mqueue"); - /* Register for notification on message arrival */ + mqd_child = SAFE_MQ_OPEN(MQNAME, O_RDONLY, 0, NULL); notif.sigev_notify = SIGEV_SIGNAL; notif.sigev_signo = SIGUSR1; - notif.sigev_value.sival_int = mqd; - if (tst_syscall(__NR_mq_notify, mqd, ¬if) == -1) { - perror("mq_notify failed"); - return 1; - } else - printf("successfully registered for notification\n"); + notif.sigev_value.sival_int = mqd_child; + + SAFE_MQ_NOTIFY(mqd_child, ¬if); - /* Define handler for SIGUSR1 */ sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); + SAFE_SIGEMPTYSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - perror("sigaction failed"); - return 1; - } else - printf("successfully registered handler for SIGUSR1\n"); - - /* Ask parent to send a message to the mqueue */ - if (write(child_to_father[1], "c:ok", 5) != 5) { - perror("write failed"); - return 1; - } + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - sleep(3); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Has parent sent a message? */ - read(father_to_child[0], buf, 5); - if (strcmp(buf, "f:ok") != 0) { - printf("parent did not send the message!\n"); - return 1; - } - printf("parent is done - cleaning up\n"); - - cleanup_child(); + if (received) + tst_res(TPASS, "Signal notification has been received"); + else + tst_res(TFAIL, "Signal notification has not been received"); - exit(0); + TST_EXP_EQ_LI(info.si_signo, SIGUSR1); + TST_EXP_EQ_LI(info.si_code, SI_MESGQ); + TST_EXP_EQ_LI(info.si_pid, 0); } -static void setup(void) +static void cleanup(void) { - tst_require_root(); - check_newpid(); + remove_mqueue(mqd); } -int main(void) +static void run(void) { - int status; - char buf[5]; - pid_t cpid; + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - setup(); + remove_mqueue(mqd); + received = 0; - if (pipe(child_to_father) == -1 || pipe(father_to_child) == -1) { - tst_brkm(TBROK | TERRNO, cleanup, "pipe failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - tst_syscall(__NR_mq_unlink, mqname); - - /* container creation on PID namespace */ - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - mqd = - tst_syscall(__NR_mq_open, mqname, O_RDWR | O_CREAT | O_EXCL, 0777, - NULL); - if (mqd == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mq_open failed"); - else - tst_resm(TINFO, "successfully created posix mqueue"); - - if (write(father_to_child[1], buf, 1) != 1) - tst_brkm(TBROK | TERRNO, cleanup, "write failed"); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, 0); - /* Close the appropriate end of each pipe */ - close(child_to_father[1]); - close(father_to_child[0]); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Is container ready */ - read(child_to_father[0], buf, 5); - if (strcmp(buf, "c:ok") != 0) - tst_brkm(TBROK, cleanup, - "container did not respond as expected!"); - - rc = mq_send(mqd, MSG, strlen(MSG), MSG_PRIO); - if (rc == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mq_send failed"); - else - tst_resm(TINFO, "mq_send succeeded"); + tst_res(TINFO, "Send mqueue message"); - /* Tell the child the message has been sent */ - if (write(father_to_child[1], "f:ok", 5) != 5) - tst_brkm(TBROK | TERRNO, cleanup, "write failed"); + SAFE_MQ_SEND(mqd, "pippo", 5, 1); - /* Wait for child to finish */ - if (wait(&status) == -1) - tst_resm(TBROK | TERRNO, "wait failed"); - - cleanup(); - - tst_exit(); + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns31.c b/testcases/kernel/containers/pidns/pidns31.c index 8821ec83c..7312f8bdc 100644 --- a/testcases/kernel/containers/pidns/pidns31.c +++ b/testcases/kernel/containers/pidns/pidns31.c @@ -1,330 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) Bull S.A.S. 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns31.c -* -* Description: -* This testcase checks if the si_pid is correctly set when a process -* that has registered for notification on a posix mqueue is in an -* ancestor namespace wrt the process that sends a message to that posix -* mqueue. -* -* Test Assertion & Strategy: -* Parent Child -* -------------------------------------------------------------------------- -* Create a POSIX mqueue. -* Create a PID namespace container. -* Register for notification when a -* message arrives in that mqueue -* Install a handler for SIGUSR1. -* Open that mqueue for writing -* Write something to the mqueue. -* Inside the handler, check that -* si_pid is set to the child's pid -* -* Usage: <for command-line> -* pidns31 -* -* History: -* DATE NAME DESCRIPTION -* 04/12/08 Nadia Derbey Creation of this test. -* <Nadia.Derbey@bull.net> -* -******************************************************************************/ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include <sys/wait.h> -#include <sys/types.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <mqueue.h> -#include "lapi/syscalls.h" -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns31"; -int TST_TOTAL = 1; - -char *mqname = "mq1"; -int result = TFAIL; - -int father_to_child[2]; - -#define CHILD_PID 1 -#define PARENT_PID 0 + * Copyright (c) Bull S.A.S. 2008 + * 01/12/08 Nadia Derbey <Nadia.Derbey@bull.net> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -#define MSG "HOW ARE YOU" -#define MSG_PRIO 1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag, register notification on a posix + * mqueue and send a mqueue message from the child. Then check if signal + * notification contains si_pid of the child. + */ -#define NO_STEP -1 -#define F_STEP_0 0x00 -#define F_STEP_1 0x01 -#define F_STEP_2 0x02 -#define F_STEP_3 0x03 -#define C_STEP_0 0x10 -#define C_STEP_1 0x11 +#define _GNU_SOURCE 1 +#include <signal.h> +#include <mqueue.h> +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" +#include "lapi/sched.h" -struct notify_info { - mqd_t mqd; - pid_t pid; -}; +#define MQNAME "/LTP_PIDNS30_MQ" -static void remove_pipe(int *fd) -{ - close(fd[0]); - close(fd[1]); -} +static mqd_t mqd = -1; +static volatile int received; +static siginfo_t info; static void remove_mqueue(mqd_t mqd) { - mq_close(mqd); - tst_syscall(__NR_mq_unlink, mqname); -} + if (mqd != -1) + SAFE_MQ_CLOSE(mqd); -/* - * steps F_STEP_XX : called from main - * steps C_STEP_XX : called from child_fn - */ -static void cleanup_resources(int step, mqd_t mqd) -{ - switch (step) { - case C_STEP_1: - close(father_to_child[0]); - /* fall through */ - case C_STEP_0: - mq_close(mqd); - break; - - case F_STEP_3: - remove_mqueue(mqd); - close(father_to_child[1]); - break; - - case F_STEP_2: - tst_syscall(__NR_mq_notify, mqd, NULL); - /* fall through */ - case F_STEP_1: - remove_mqueue(mqd); - /* fall through */ - case F_STEP_0: - remove_pipe(father_to_child); - break; - default: - tst_resm(TWARN, "Unknown code - no resource removed."); - break; - } + mq_unlink(MQNAME); } -/* - * cleanup_mqueue() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * step == -1 means no local resource to remove. - */ -void cleanup_mqueue(int result, int step, mqd_t mqd) +static void signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - if (step != NO_STEP) - cleanup_resources(step, mqd); - - tst_exit(); + memcpy(&info, si, sizeof(info)); + received++; } -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - pid_t pid, ppid; - mqd_t mqd; - char buf[5]; + pid_t cpid, ppid; + mqd_t mqd_child; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - tst_resm(TBROK, "cinit: pidns is not created"); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - - /* Close the appropriate end of pipe */ - close(father_to_child[1]); - - /* Is parent ready to receive a message? */ - read(father_to_child[0], buf, 5); - if (strcmp(buf, "f:ok")) { - tst_resm(TBROK, "cinit: parent did not send the message!"); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - tst_resm(TINFO, "cinit: my father is ready to receive a message"); - - mqd = tst_syscall(__NR_mq_open, mqname, O_WRONLY, 0, NULL); - if (mqd == (mqd_t) - 1) { - tst_resm(TBROK, "cinit: mq_open() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - tst_resm(TINFO, "cinit: mq_open succeeded"); - - if (mq_send(mqd, MSG, strlen(MSG), MSG_PRIO) == (mqd_t) - 1) { - tst_resm(TBROK, "cinit: mq_send() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, C_STEP_0, mqd); - } - tst_resm(TINFO, "cinit: mq_send() succeeded"); - - /* Cleanup and exit */ - cleanup_resources(C_STEP_1, mqd); - exit(0); -} + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); -/* - * father_signal_handler() - */ -static void father_signal_handler(int sig, siginfo_t * si, void *unused) -{ - char buf[256]; - struct mq_attr attr; - struct notify_info *info; + TST_CHECKPOINT_WAIT(0); - if (si->si_signo != SIGUSR1) { - tst_resm(TBROK, "father: received %s unexpectedly", - strsignal(si->si_signo)); - return; - } - - if (si->si_code != SI_MESGQ) { - tst_resm(TBROK, "father: expected signal code SI_MESGQ - " - "Got %d", si->si_code); - return; - } - - if (!si->si_ptr) { - tst_resm(TBROK, "father: expected si_ptr - Got NULL"); - return; - } - - info = (struct notify_info *)si->si_ptr; - - if (si->si_pid != info->pid) { - tst_resm(TFAIL, - "father: expected signal originator PID = %d - Got %d", - info->pid, si->si_pid); - return; - } + tst_res(TINFO, "Send mqueue message from child"); - tst_resm(TPASS, "father: signal originator PID = %d", si->si_pid); - result = TPASS; + mqd_child = SAFE_MQ_OPEN(MQNAME, O_WRONLY, 0, NULL); + SAFE_MQ_SEND(mqd_child, "pippo", 5, 1); - /* - * Now read the message - Be silent on errors since this is not the - * test purpose. - */ - if (!mq_getattr(info->mqd, &attr)) - mq_receive(info->mqd, buf, attr.mq_msgsize, NULL); + TST_CHECKPOINT_WAKE(0); } -static void setup(void) +static void cleanup(void) { - tst_require_root(); - check_newpid(); + remove_mqueue(mqd); } -/*********************************************************************** -* M A I N -***********************************************************************/ - -int main(void) +static void run(void) { pid_t cpid; - mqd_t mqd; - struct sigevent notif; struct sigaction sa; - int status; - struct notify_info info; + struct sigevent notif; + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - setup(); + remove_mqueue(mqd); + received = 0; - if (pipe(father_to_child) == -1) { - tst_resm(TBROK, "parent: pipe() failed. aborting!"); - cleanup_mqueue(TBROK, NO_STEP, 0); + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_func(); + return; } - tst_syscall(__NR_mq_unlink, mqname); - mqd = - tst_syscall(__NR_mq_open, mqname, O_RDWR | O_CREAT | O_EXCL, 0777, - NULL); - if (mqd == (mqd_t) - 1) { - tst_resm(TBROK, "parent: mq_open() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_0, 0); - } - tst_resm(TINFO, "parent: successfully created posix mqueue"); + tst_res(TINFO, "Register notification on posix mqueue"); - /* container creation on PID namespace */ - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid < 0) { - tst_resm(TBROK, "parent: clone() failed(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } - tst_resm(TINFO, "parent: successfully created child (pid = %d)", cpid); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); - /* Register for notification on message arrival */ notif.sigev_notify = SIGEV_SIGNAL; notif.sigev_signo = SIGUSR1; - info.mqd = mqd; - info.pid = cpid; - notif.sigev_value.sival_ptr = &info; - if (tst_syscall(__NR_mq_notify, mqd, ¬if) == (mqd_t) -1) { - tst_resm(TBROK, "parent: mq_notify() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } - tst_resm(TINFO, "parent: successfully registered for notification"); - - /* Define handler for SIGUSR1 */ - sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); - sa.sa_sigaction = father_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - tst_resm(TBROK, "parent: sigaction() failed(%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_2, mqd); - } - tst_resm(TINFO, "parent: successfully registered handler for SIGUSR1"); - /* Close the appropriate end of pipe */ - close(father_to_child[0]); - - /* Tell the child a message can be sent */ - if (write(father_to_child[1], "f:ok", 5) != 5) { - tst_resm(TBROK, "parent: pipe is broken(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_2, mqd); - } + SAFE_MQ_NOTIFY(mqd, ¬if); - sleep(3); + sa.sa_flags = SA_SIGINFO; + SAFE_SIGEMPTYSET(&sa.sa_mask); + sa.sa_sigaction = signal_handler; + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - /* Wait for child to finish */ - if (wait(&status) == -1) { - tst_resm(TBROK, "parent: wait() failed(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - cleanup_mqueue(result, F_STEP_3, mqd); + tst_reap_children(); - tst_exit(); + TST_EXP_EQ_LI(received, 1); + TST_EXP_EQ_LI(info.si_signo, SIGUSR1); + TST_EXP_EQ_LI(info.si_code, SI_MESGQ); + TST_EXP_EQ_LI(info.si_pid, cpid); } + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns32.c b/testcases/kernel/containers/pidns/pidns32.c index 3f7df788e..0738369b1 100644 --- a/testcases/kernel/containers/pidns/pidns32.c +++ b/testcases/kernel/containers/pidns/pidns32.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ /*\ @@ -12,32 +12,35 @@ */ #define _GNU_SOURCE - #include <sys/mman.h> #include "tst_test.h" +#include "tst_atomic.h" #include "lapi/sched.h" #define MAXNEST 32 +static const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, +}; static int *level; -static int child_func(LTP_ATTRIBUTE_UNUSED void *arg) +static pid_t child_func(void) { - pid_t cpid; - int status; - - if (*level == MAXNEST) - return 0; + pid_t cpid = 0; - (*level)++; + if (tst_atomic_inc(level) == MAXNEST) + return cpid; - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, 0); - if (cpid < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_func(); + return cpid; + } - SAFE_WAITPID(cpid, &status, 0); + tst_reap_children(); - return 0; + return cpid; } static void setup(void) @@ -45,28 +48,25 @@ static void setup(void) level = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); } -static void run(void) +static void cleanup(void) { - int ret, status; - - *level = 1; - - ret = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, 0); - if (ret < 0) - tst_brk(TBROK | TERRNO, "clone failed"); + SAFE_MUNMAP(level, sizeof(int)); +} - SAFE_WAITPID(ret, &status, 0); +static void run(void) +{ + *level = 0; - if (*level < MAXNEST) { - tst_res(TFAIL, "Nested containers should be %d, but they are %d", MAXNEST, *level); + if (!child_func()) return; - } - tst_res(TPASS, "All %d containers have been nested", MAXNEST); + TST_EXP_EQ_LI(*level, MAXNEST); } static struct tst_test test = { .test_all = run, .needs_root = 1, .setup = setup, + .cleanup = cleanup, + .forks_child = 1, }; diff --git a/testcases/kernel/containers/pidns/pidns_helper.h b/testcases/kernel/containers/pidns/pidns_helper.h deleted file mode 100644 index 3b356768f..000000000 --- a/testcases/kernel/containers/pidns/pidns_helper.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -*/ - -#include "../libclone/libclone.h" -#include "test.h" -#include "safe_macros.h" - -static int dummy_child(void *v) -{ - (void) v; - return 0; -} - -static int check_newpid(void) -{ - int pid, status; - - pid = do_clone_unshare_test(T_CLONE, CLONE_NEWPID, dummy_child, NULL); - if (pid == -1) - tst_brkm(TCONF | TERRNO, NULL, "CLONE_NEWPID not supported"); - SAFE_WAIT(NULL, &status); - - return 0; -} diff --git a/testcases/kernel/containers/share/.gitignore b/testcases/kernel/containers/share/.gitignore deleted file mode 100644 index 06615d9ea..000000000 --- a/testcases/kernel/containers/share/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/ns_ifmove -/ns_create -/ns_exec -/setns_check diff --git a/testcases/kernel/containers/share/Makefile b/testcases/kernel/containers/share/Makefile deleted file mode 100644 index 962d6889d..000000000 --- a/testcases/kernel/containers/share/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2015 Red Hat, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of version 2 the GNU General Public License as -# published by the Free Software Foundation. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -############################################################################## -top_srcdir ?= ../../../.. - -include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc - -LDLIBS := -lltp - -include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/share/ns_create.c b/testcases/kernel/containers/share/ns_create.c deleted file mode 100644 index 3f09e71e0..000000000 --- a/testcases/kernel/containers/share/ns_create.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2015 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Written by Matus Marhefka <mmarhefk@redhat.com> - * - *********************************************************************** - * Creates a child process in the new specified namespace(s), child is then - * daemonized and is running in the background. PID of the daemonized child - * process is printed on the stdout. As the new namespace(s) is(are) maintained - * by the daemonized child process it(they) can be removed by killing this - * process. - * - */ - -#define _GNU_SOURCE -#include <sys/syscall.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "test.h" -#include "lapi/sched.h" -#include "ns_common.h" - -char *TCID = "ns_create"; - - -void print_help(void) -{ - int i; - - printf("usage: ns_create <%s", params[0].name); - - for (i = 1; params[i].name; i++) - printf("|,%s", params[i].name); - printf(">\nThe only argument is a comma separated list " - "of namespaces to create.\nExample: ns_create net,ipc\n"); -} - -static int child_fn(void *arg LTP_ATTRIBUTE_UNUSED) -{ - int i; - - if (setsid() == -1) { - tst_resm(TINFO | TERRNO, "setsid"); - exit(1); - } - - if (chdir("/") == -1) { - tst_resm(TINFO | TERRNO, "chdir"); - exit(1); - } - - /* close all inherrited file descriptors */ - for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) - close(i); - - pause(); - return 0; -} - -/* - * ./ns_create <ipc,mnt,net,pid,user,uts> - */ -int main(int argc, char *argv[]) -{ - int pid, flags; - char *token; - - if (argc < 2) { - print_help(); - return 1; - } - - flags = 0; - while ((token = strsep(&argv[1], ","))) { - struct param *p = get_param(token); - - if (!p) { - tst_resm(TINFO, "Unknown namespace: %s", token); - print_help(); - return 1; - } - - flags |= p->flag; - } - - pid = ltp_clone_quick(flags | SIGCHLD, child_fn, NULL); - if (pid == -1) { - tst_resm(TINFO | TERRNO, "ltp_clone_quick"); - return 1; - } - - printf("%d", pid); - return 0; -} diff --git a/testcases/kernel/containers/share/ns_exec.c b/testcases/kernel/containers/share/ns_exec.c deleted file mode 100644 index 4abd1063b..000000000 --- a/testcases/kernel/containers/share/ns_exec.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2015 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Written by Matus Marhefka <mmarhefk@redhat.com> - * - *********************************************************************** - * Enters the namespace(s) of a process specified by a PID and then executes - * the indicated program inside that namespace(s). - * - */ - -#define _GNU_SOURCE -#include <sys/syscall.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "test.h" -#include "lapi/syscalls.h" -#include "lapi/sched.h" -#include "ns_common.h" - -char *TCID = "ns_exec"; -int ns_fd[NS_TOTAL]; -int ns_fds; - - -void print_help(void) -{ - int i; - - printf("usage: ns_exec <NS_PID> <%s", params[0].name); - - for (i = 1; params[i].name; i++) - printf("|,%s", params[i].name); - printf("> <PROGRAM> [ARGS]\nSecond argument indicates the types" - " of a namespaces maintained by NS_PID\nand is specified" - " as a comma separated list.\nExample: ns_exec 1234 net,ipc" - " ip a\n"); -} - -static int open_ns_fd(const char *pid, const char *ns) -{ - int fd; - char file_buf[30]; - - sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns); - - fd = open(file_buf, O_RDONLY); - if (fd > 0) { - ns_fd[ns_fds] = fd; - ++ns_fds; - return 0; - } else if (fd == -1 && errno != ENOENT) { - tst_resm(TINFO | TERRNO, "open"); - return -1; - } - - return 0; -} - -static void close_ns_fd(void) -{ - int i; - - for (i = 0; i < ns_fds; i++) - close(ns_fd[i]); -} - -static int child_fn(void *arg) -{ - char **args = (char **)arg; - - execvp(args[3], args+3); - tst_resm(TINFO | TERRNO, "execvp"); - return 1; -} - -/* - * ./ns_exec <NS_PID> <ipc,mnt,net,pid,user,uts> <PROGRAM> [ARGS] - */ -int main(int argc, char *argv[]) -{ - int i, rv, pid; - char *token; - - rv = syscall(__NR_setns, -1, 0); - if (rv == -1 && errno == ENOSYS) { - tst_resm(TINFO, "setns is not supported in the kernel"); - return 1; - } - - if (argc < 4) { - print_help(); - return 1; - } - - memset(ns_fd, 0, sizeof(ns_fd)); - while ((token = strsep(&argv[2], ","))) { - struct param *p = get_param(token); - - if (!p) { - tst_resm(TINFO, "Unknown namespace: %s", token); - print_help(); - return 1; - } - - if (open_ns_fd(argv[1], token) != 0) - return 1; - } - - if (ns_fds == 0) { - tst_resm(TINFO, "no namespace entries in /proc/%s/ns/", - argv[1]); - return 1; - } - - for (i = 0; i < ns_fds; i++) { - if (syscall(__NR_setns, ns_fd[i], 0) == -1) { - tst_resm(TINFO | TERRNO, "setns"); - close_ns_fd(); - return 1; - } - } - - pid = ltp_clone_quick(SIGCHLD, (void *)child_fn, (void *)argv); - if (pid == -1) { - tst_resm(TINFO | TERRNO, "ltp_clone_quick"); - close_ns_fd(); - return 1; - } - - if (waitpid(pid, &rv, 0) == -1) { - tst_resm(TINFO | TERRNO, "waitpid"); - return 1; - } - - close_ns_fd(); - - if (WIFEXITED(rv)) - return WEXITSTATUS(rv); - - return 0; -} diff --git a/testcases/kernel/containers/share/ns_ifmove.c b/testcases/kernel/containers/share/ns_ifmove.c deleted file mode 100644 index 12642c6f4..000000000 --- a/testcases/kernel/containers/share/ns_ifmove.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (c) 2015 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Written by Matus Marhefka <mmarhefk@redhat.com> - * - *********************************************************************** - * Moves a network interface to the namespace of a process specified by a PID. - * - */ - -#define _GNU_SOURCE -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <asm/types.h> -#include <sys/socket.h> -#include <linux/rtnetlink.h> -#include <sys/ioctl.h> -#include <linux/if.h> -#include <net/ethernet.h> -#include <arpa/inet.h> -#include "test.h" - -#include "config.h" - -char *TCID = "ns_ifmove"; - -#if HAVE_DECL_IFLA_NET_NS_PID - -struct { - struct nlmsghdr nh; - struct ifinfomsg ifi; - char attrbuf[512]; -} req; - - -int get_intf_index_from_name(const char *intf_name) -{ - struct ifreq ifr; - int sock_fd; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, intf_name, sizeof(ifr.ifr_name) - 1); - ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; - - sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (sock_fd == -1) { - tst_resm(TINFO | TERRNO, "socket"); - return -1; - } - - /* gets interface index */ - if (ioctl(sock_fd, SIOCGIFINDEX, &ifr) == -1) { - tst_resm(TINFO | TERRNO, "ioctl"); - close(sock_fd); - return -1; - } - - close(sock_fd); - return ifr.ifr_ifindex; -} - -/* - * ./ns_ifmove <INTERFACE_NAME> <NAMESPACE_PID> - */ -int main(int argc, char **argv) -{ - struct rtattr *rta; - int intf_index, pid, rtnetlink_socket; - - if (argc != 3) { - tst_resm(TINFO, "%s <INTERFACE_NAME> <NAMESPACE_PID>", - argv[0]); - return 1; - } - - intf_index = get_intf_index_from_name(argv[1]); - if (intf_index == -1) { - tst_resm(TINFO , "unable to get interface index"); - return 1; - } - - pid = atoi(argv[2]); - - rtnetlink_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); - if (rtnetlink_socket == -1) { - tst_resm(TINFO | TERRNO, "socket"); - return 1; - } - - memset(&req, 0, sizeof(req)); - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.nh.nlmsg_flags = NLM_F_REQUEST; - req.nh.nlmsg_type = RTM_NEWLINK; - req.ifi.ifi_family = AF_UNSPEC; - req.ifi.ifi_index = intf_index; - req.ifi.ifi_change = 0xffffffff; - rta = (struct rtattr *)(((char *) &req) + - NLMSG_ALIGN(req.nh.nlmsg_len)); - rta->rta_type = IFLA_NET_NS_PID; - rta->rta_len = RTA_LENGTH(sizeof(int)); - req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + - RTA_LENGTH(sizeof(pid)); - memcpy(RTA_DATA(rta), &pid, sizeof(pid)); - - if (send(rtnetlink_socket, &req, req.nh.nlmsg_len, 0) == -1) { - tst_resm(TINFO | TERRNO, "send"); - return 1; - } - - close(rtnetlink_socket); - return 0; -} - -#else - -int main(void) -{ - tst_brkm(TCONF, NULL, "IFLA_NET_NS_PID not defined in linux/if_link.h"); -} - -#endif diff --git a/testcases/kernel/containers/share/setns_check.c b/testcases/kernel/containers/share/setns_check.c deleted file mode 100644 index 75aad17f3..000000000 --- a/testcases/kernel/containers/share/setns_check.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (c) 2015 Fujitsu Ltd. - * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - *********************************************************************** - * Check for setns() availability, should be called before ns_exec. - * - */ - -#include "test.h" -#include "lapi/syscalls.h" - -char *TCID = "setns_check"; - -int main(void) -{ - if (syscall(__NR_setns, -1, 0) == -1 && errno == ENOSYS) - tst_brkm(TCONF, NULL, "setns is not supported in the kernel"); - else - return 0; -} diff --git a/testcases/kernel/containers/sysvipc/common.h b/testcases/kernel/containers/sysvipc/common.h index 9b0fc16e9..180cf9bd7 100644 --- a/testcases/kernel/containers/sysvipc/common.h +++ b/testcases/kernel/containers/sysvipc/common.h @@ -19,24 +19,7 @@ enum { T_NONE, }; -static int dummy_child(void *v) -{ - (void)v; - return 0; -} - -static void check_newipc(void) -{ - int pid, status; - - pid = ltp_clone_quick(CLONE_NEWIPC | SIGCHLD, dummy_child, NULL); - if (pid < 0) - tst_brk(TCONF | TERRNO, "CLONE_NEWIPC not supported"); - - SAFE_WAITPID(pid, &status, 0); -} - -static inline int get_clone_unshare_enum(const char* str_op) +static inline int get_clone_unshare_enum(const char *str_op) { int use_clone; @@ -54,16 +37,22 @@ static inline int get_clone_unshare_enum(const char* str_op) return use_clone; } -static void clone_test(unsigned long clone_flags, int (*fn1)(void *arg), void *arg1) +static void clone_test(unsigned long clone_flags, void (*fn1)()) { + const struct tst_clone_args clone_args = { + .flags = clone_flags, + .exit_signal = SIGCHLD, + }; int pid; - pid = ltp_clone_quick(clone_flags | SIGCHLD, fn1, arg1); - if (pid < 0) - tst_brk(TBROK | TERRNO, "ltp_clone_quick error"); + pid = SAFE_CLONE(&clone_args); + if (!pid) { + fn1(); + exit(0); + } } -static void unshare_test(unsigned long clone_flags, int (*fn1)(void *arg), void *arg1) +static void unshare_test(unsigned long clone_flags, void (*fn1)()) { int pid; @@ -71,34 +60,33 @@ static void unshare_test(unsigned long clone_flags, int (*fn1)(void *arg), void if (!pid) { SAFE_UNSHARE(clone_flags); - fn1(arg1); + fn1(); exit(0); } } -static void plain_test(int (*fn1)(void *arg), void *arg1) +static void plain_test(void (*fn1)()) { int pid; pid = SAFE_FORK(); if (!pid) { - fn1(arg1); + fn1(); exit(0); } } -static void clone_unshare_test(int use_clone, unsigned long clone_flags, - int (*fn1)(void *arg), void *arg1) +static void clone_unshare_test(int use_clone, unsigned long clone_flags, void (*fn1)()) { switch (use_clone) { case T_NONE: - plain_test(fn1, arg1); + plain_test(fn1); break; case T_CLONE: - clone_test(clone_flags, fn1, arg1); + clone_test(clone_flags, fn1); break; case T_UNSHARE: - unshare_test(clone_flags, fn1, arg1); + unshare_test(clone_flags, fn1); break; default: tst_brk(TBROK, "%s: bad use_clone option: %d", __FUNCTION__, use_clone); diff --git a/testcases/kernel/containers/sysvipc/mesgq_nstest.c b/testcases/kernel/containers/sysvipc/mesgq_nstest.c index 056b5d086..4b12c1ce1 100644 --- a/testcases/kernel/containers/sysvipc/mesgq_nstest.c +++ b/testcases/kernel/containers/sysvipc/mesgq_nstest.c @@ -42,7 +42,7 @@ struct msg_buf { char mtext[80]; }; -static int check_mesgq(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_mesgq(void) { int id, n; struct msg_buf msg = {}; @@ -55,7 +55,7 @@ static int check_mesgq(LTP_ATTRIBUTE_UNUSED void *vtest) else tst_res(TPASS, "%s: container didn't find mesgq", str_op); - return 0; + return; } if (use_clone == T_NONE) { @@ -68,11 +68,10 @@ static int check_mesgq(LTP_ATTRIBUTE_UNUSED void *vtest) if (strcmp(msg.mtext, MSG_TEXT)) tst_res(TFAIL, "Received the wrong text message"); - return 0; + return; } tst_res(TFAIL, "%s: container init process found mesgq", str_op); - return 0; } static void run(void) @@ -87,16 +86,12 @@ static void run(void) tst_res(TINFO, "mesgq namespaces test: %s", str_op); - clone_unshare_test(use_clone, CLONE_NEWIPC, check_mesgq, NULL); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_mesgq); } static void setup(void) { use_clone = get_clone_unshare_enum(str_op); - - if (use_clone != T_NONE) - check_newipc(); - ipc_id = SAFE_MSGGET(KEY_VAL, IPC_CREAT | IPC_EXCL | 0600); } diff --git a/testcases/kernel/containers/sysvipc/msg_comm.c b/testcases/kernel/containers/sysvipc/msg_comm.c index 238863d9c..3762adb02 100644 --- a/testcases/kernel/containers/sysvipc/msg_comm.c +++ b/testcases/kernel/containers/sysvipc/msg_comm.c @@ -38,7 +38,7 @@ struct sysv_msg { char mtext[1]; }; -static int chld1_msg(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld1_msg(void) { int id; struct sysv_msg m = { @@ -66,11 +66,9 @@ static int chld1_msg(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE(0); SAFE_MSGCTL(id, IPC_RMID, NULL); - - return 0; } -static int chld2_msg(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld2_msg(void) { int id; struct sysv_msg m = { @@ -85,24 +83,17 @@ static int chld2_msg(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_MSGCTL(id, IPC_RMID, NULL); - - return 0; } static void run(void) { - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_msg, NULL); - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_msg, NULL); -} - -static void setup(void) -{ - check_newipc(); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_msg); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_msg); } static struct tst_test test = { .test_all = run, - .setup = setup, .needs_root = 1, .needs_checkpoints = 1, + .forks_child = 1, }; diff --git a/testcases/kernel/containers/sysvipc/sem_comm.c b/testcases/kernel/containers/sysvipc/sem_comm.c index 3323ec09f..d8f0956a7 100644 --- a/testcases/kernel/containers/sysvipc/sem_comm.c +++ b/testcases/kernel/containers/sysvipc/sem_comm.c @@ -33,7 +33,7 @@ #define TESTKEY 124426L -static int chld1_sem(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld1_sem(void) { int id; struct sembuf sm = { @@ -56,11 +56,9 @@ static int chld1_sem(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_SEMCTL(id, 0, IPC_RMID); - - return 0; } -static int chld2_sem(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld2_sem(void) { int id; struct sembuf sm = { @@ -93,24 +91,17 @@ static int chld2_sem(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE(0); SAFE_SEMCTL(id, 0, IPC_RMID); - - return 0; } static void run(void) { - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL); - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL); -} - -static void setup(void) -{ - check_newipc(); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem); } static struct tst_test test = { .test_all = run, - .setup = setup, .needs_root = 1, .needs_checkpoints = 1, + .forks_child = 1, }; diff --git a/testcases/kernel/containers/sysvipc/sem_nstest.c b/testcases/kernel/containers/sysvipc/sem_nstest.c index ac1dae443..35d55cbac 100644 --- a/testcases/kernel/containers/sysvipc/sem_nstest.c +++ b/testcases/kernel/containers/sysvipc/sem_nstest.c @@ -35,7 +35,7 @@ static char *str_op; static int use_clone; static int ipc_id = -1; -static int check_semaphore(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_semaphore(void) { int id; @@ -47,7 +47,7 @@ static int check_semaphore(LTP_ATTRIBUTE_UNUSED void *vtest) else tst_res(TPASS, "%s: container didn't find semaphore", str_op); - return 0; + return; } tst_res(TINFO, "PID %d: fetched existing semaphore..id = %d", getpid(), id); @@ -56,22 +56,16 @@ static int check_semaphore(LTP_ATTRIBUTE_UNUSED void *vtest) tst_res(TPASS, "Plain cloned process found semaphore inside container"); else tst_res(TFAIL, "%s: Container init process found semaphore", str_op); - - return 0; } static void run(void) { - clone_unshare_test(use_clone, CLONE_NEWIPC, check_semaphore, NULL); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_semaphore); } static void setup(void) { use_clone = get_clone_unshare_enum(str_op); - - if (use_clone != T_NONE) - check_newipc(); - ipc_id = SAFE_SEMGET(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); } diff --git a/testcases/kernel/containers/sysvipc/semtest_2ns.c b/testcases/kernel/containers/sysvipc/semtest_2ns.c index edff3f522..f03b18f72 100644 --- a/testcases/kernel/containers/sysvipc/semtest_2ns.c +++ b/testcases/kernel/containers/sysvipc/semtest_2ns.c @@ -40,7 +40,7 @@ static char *str_op; static int use_clone; -static int check_sem1(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_sem1(void) { int id; struct sembuf sm = { @@ -62,11 +62,9 @@ static int check_sem1(LTP_ATTRIBUTE_UNUSED void *vtest) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_SEMCTL(id, IPC_RMID, 0); - - return 0; } -static int check_sem2(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_sem2(void) { int id; struct sembuf sm = { @@ -112,22 +110,17 @@ static int check_sem2(LTP_ATTRIBUTE_UNUSED void *vtest) } TST_CHECKPOINT_WAKE(0); - - return 0; } static void run(void) { - clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem1, NULL); - clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem2, NULL); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem1); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem2); } static void setup(void) { use_clone = get_clone_unshare_enum(str_op); - - if (use_clone != T_NONE) - check_newipc(); } static void cleanup(void) diff --git a/testcases/kernel/containers/sysvipc/shm_comm.c b/testcases/kernel/containers/sysvipc/shm_comm.c index 12ad49110..e7ba8c8de 100644 --- a/testcases/kernel/containers/sysvipc/shm_comm.c +++ b/testcases/kernel/containers/sysvipc/shm_comm.c @@ -35,7 +35,7 @@ #define TESTKEY 124426L #define SHMSIZE 50 -static int chld1_shm(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld1_shm(void) { int id; char *shmem; @@ -56,11 +56,9 @@ static int chld1_shm(LTP_ATTRIBUTE_UNUSED void *arg) SAFE_SHMDT(shmem); SAFE_SHMCTL(id, IPC_RMID, NULL); - - return 0; } -static int chld2_shm(LTP_ATTRIBUTE_UNUSED void *arg) +static void chld2_shm(void) { int id; char *shmem; @@ -77,24 +75,17 @@ static int chld2_shm(LTP_ATTRIBUTE_UNUSED void *arg) SAFE_SHMDT(shmem); SAFE_SHMCTL(id, IPC_RMID, NULL); - - return 0; } static void run(void) { - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm, NULL); - clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm, NULL); -} - -static void setup(void) -{ - check_newipc(); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm); } static struct tst_test test = { .test_all = run, - .setup = setup, .needs_root = 1, .needs_checkpoints = 1, + .forks_child = 1, }; diff --git a/testcases/kernel/containers/sysvipc/shmem_2nstest.c b/testcases/kernel/containers/sysvipc/shmem_2nstest.c index ea3de94bd..a184cfcb4 100644 --- a/testcases/kernel/containers/sysvipc/shmem_2nstest.c +++ b/testcases/kernel/containers/sysvipc/shmem_2nstest.c @@ -40,7 +40,7 @@ static char *str_op; static int use_clone; -static int check_shmem1(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_shmem1(void) { int id; @@ -51,11 +51,9 @@ static int check_shmem1(LTP_ATTRIBUTE_UNUSED void *vtest) TST_CHECKPOINT_WAKE_AND_WAIT(0); SAFE_SHMCTL(id, IPC_RMID, NULL); - - return 0; } -static int check_shmem2(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_shmem2(void) { TST_CHECKPOINT_WAIT(0); @@ -74,22 +72,17 @@ static int check_shmem2(LTP_ATTRIBUTE_UNUSED void *vtest) } TST_CHECKPOINT_WAKE(0); - - return 0; } static void run(void) { - clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem1, NULL); - clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem2, NULL); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem1); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem2); } static void setup(void) { use_clone = get_clone_unshare_enum(str_op); - - if (use_clone != T_NONE) - check_newipc(); } static struct tst_test test = { diff --git a/testcases/kernel/containers/sysvipc/shmnstest.c b/testcases/kernel/containers/sysvipc/shmnstest.c index d8ace723e..63ae62aa6 100644 --- a/testcases/kernel/containers/sysvipc/shmnstest.c +++ b/testcases/kernel/containers/sysvipc/shmnstest.c @@ -27,7 +27,7 @@ static char *str_op; static int use_clone; static int ipc_id = -1; -static int check_shmid(LTP_ATTRIBUTE_UNUSED void *vtest) +static void check_shmid(void) { TEST(shmget(TESTKEY, 100, 0)); if (TST_RET < 0) { @@ -41,22 +41,16 @@ static int check_shmid(LTP_ATTRIBUTE_UNUSED void *vtest) else tst_res(TFAIL, "%s: child process found shmid", str_op); } - - return 0; } static void run(void) { - clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmid, NULL); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmid); } static void setup(void) { use_clone = get_clone_unshare_enum(str_op); - - if (use_clone != T_NONE) - check_newipc(); - ipc_id = shmget(TESTKEY, 100, IPC_CREAT); } diff --git a/testcases/kernel/containers/userns/.gitignore b/testcases/kernel/containers/userns/.gitignore new file mode 100644 index 000000000..dbd4aee27 --- /dev/null +++ b/testcases/kernel/containers/userns/.gitignore @@ -0,0 +1,9 @@ +userns01 +userns02 +userns03 +userns04 +userns05 +userns06_capcheck +userns06 +userns07 +userns08 diff --git a/testcases/kernel/containers/userns/Makefile b/testcases/kernel/containers/userns/Makefile index 80681096d..1531d1de6 100644 --- a/testcases/kernel/containers/userns/Makefile +++ b/testcases/kernel/containers/userns/Makefile @@ -1,26 +1,11 @@ -############################################################################### -# ## -# Copyright (c) Huawei Technologies Co., Ltd., 2015 ## -# ## -# This program is free software; you can redistribute it and#or modify ## -# it under the terms of the GNU General Public License as published by ## -# the Free Software Foundation; either version 2 of the License, or ## -# (at your option) any later version. ## -# ## -# This program 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 General Public License ## -# for more details. ## -# ## -# You should have received a copy of the GNU General Public License ## -# along with this program. ## -############################################################################### +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Huawei Technologies Co., Ltd., 2015 +# Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lclone $(LDLIBS) $(CAP_LIBS) +LDLIBS := $(LDLIBS) $(CAP_LIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/userns/common.h b/testcases/kernel/containers/userns/common.h index 635d0f190..9b3a47b69 100644 --- a/testcases/kernel/containers/userns/common.h +++ b/testcases/kernel/containers/userns/common.h @@ -8,35 +8,17 @@ #define COMMON_H #include "tst_test.h" -#include "lapi/sched.h" #define UID_MAP 0 #define GID_MAP 1 -static int dummy_child(void *v) -{ - (void)v; - return 0; -} - -static inline void check_newuser(void) -{ - int pid, status; - - pid = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, dummy_child, NULL); - if (pid == -1) - tst_brk(TCONF | TTERRNO, "CLONE_NEWUSER not supported"); - - SAFE_WAIT(&status); -} - static inline void updatemap(int cpid, int type, int idnum, int parentmappid) { char path[BUFSIZ]; char content[BUFSIZ]; int fd; - switch(type) { + switch (type) { case UID_MAP: sprintf(path, "/proc/%d/uid_map", cpid); break; diff --git a/testcases/kernel/containers/userns/userns01.c b/testcases/kernel/containers/userns/userns01.c index 8ed7a9f41..6fe0cd637 100644 --- a/testcases/kernel/containers/userns/userns01.c +++ b/testcases/kernel/containers/userns/userns01.c @@ -20,9 +20,9 @@ #define _GNU_SOURCE #include <stdio.h> -#include "common.h" #include "config.h" #include <sys/capability.h> +#include "lapi/sched.h" #define OVERFLOWUIDPATH "/proc/sys/kernel/overflowuid" #define OVERFLOWGIDPATH "/proc/sys/kernel/overflowgid" @@ -30,10 +30,7 @@ static long overflowuid; static long overflowgid; -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_fn1(void) { int uid, gid; cap_t caps; @@ -45,10 +42,8 @@ static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) tst_res(TINFO, "USERNS test is running in a new user namespace."); - if (uid != overflowuid || gid != overflowgid) - tst_res(TFAIL, "got unexpected uid=%d gid=%d", uid, gid); - else - tst_res(TPASS, "got expected uid and gid"); + TST_EXP_EQ_LI(uid, overflowuid); + TST_EXP_EQ_LI(gid, overflowgid); caps = cap_get_proc(); @@ -68,31 +63,32 @@ static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) tst_res(TFAIL, "unexpected effective/permitted caps at %d", i); else tst_res(TPASS, "expected capabilities"); - - return 0; } static void setup(void) { - check_newuser(); - SAFE_FILE_SCANF(OVERFLOWUIDPATH, "%ld", &overflowuid); SAFE_FILE_SCANF(OVERFLOWGIDPATH, "%ld", &overflowgid); } static void run(void) { - int pid; - - pid = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, child_fn1, NULL); - if (pid < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_fn1(); + return; + } } static struct tst_test test = { .setup = setup, .test_all = run, .needs_root = 1, + .forks_child = 1, .caps = (struct tst_cap []) { TST_CAP(TST_CAP_DROP, CAP_NET_RAW), {} diff --git a/testcases/kernel/containers/userns/userns02.c b/testcases/kernel/containers/userns/userns02.c index dd784000e..3c8ce2133 100644 --- a/testcases/kernel/containers/userns/userns02.c +++ b/testcases/kernel/containers/userns/userns02.c @@ -14,13 +14,10 @@ #define _GNU_SOURCE #include <stdio.h> -#include "common.h" #include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_fn1(void) { int uid, gid; @@ -29,29 +26,26 @@ static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) uid = geteuid(); gid = getegid(); - if (uid == 100 && gid == 100) - tst_res(TPASS, "got expected uid and gid"); - else - tst_res(TFAIL, "got unexpected uid=%d gid=%d", uid, gid); - - return 0; -} - -static void setup(void) -{ - check_newuser(); + TST_EXP_EQ_LI(uid, 100); + TST_EXP_EQ_LI(gid, 100); } static void run(void) { + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; int childpid; int parentuid; int parentgid; char path[BUFSIZ]; - childpid = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, child_fn1, NULL); - if (childpid < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + childpid = SAFE_CLONE(&args); + if (!childpid) { + child_fn1(); + return; + } parentuid = geteuid(); parentgid = getegid(); @@ -71,9 +65,9 @@ static void run(void) } static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS", diff --git a/testcases/kernel/containers/userns/userns03.c b/testcases/kernel/containers/userns/userns03.c index b90cc09ba..fca858702 100644 --- a/testcases/kernel/containers/userns/userns03.c +++ b/testcases/kernel/containers/userns/userns03.c @@ -32,8 +32,9 @@ #include <stdio.h> #include <stdbool.h> -#include "common.h" #include "tst_test.h" +#include "lapi/sched.h" +#include "common.h" #define CHILD1UID 0 #define CHILD1GID 0 @@ -42,23 +43,12 @@ #define UID_MAP 0 #define GID_MAP 1 -static int cpid1; -static int parentuid; -static int parentgid; - -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_fn1(void) { TST_CHECKPOINT_WAIT(0); - return 0; } -/* - * child_fn2() - Inside a new user namespace - */ -static int child_fn2(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_fn2(int cpid1, int parentuid, int parentgid) { int uid, gid; char cpid1uidpath[BUFSIZ]; @@ -70,12 +60,8 @@ static int child_fn2(LTP_ATTRIBUTE_UNUSED void *arg) uid = geteuid(); gid = getegid(); - tst_res(TINFO, "uid=%d, gid=%d", uid, gid); - - if (uid != CHILD2UID || gid != CHILD2GID) - tst_res(TFAIL, "unexpected uid=%d gid=%d", uid, gid); - else - tst_res(TPASS, "expected uid and gid"); + TST_EXP_EQ_LI(uid, CHILD2UID); + TST_EXP_EQ_LI(gid, CHILD2GID); /* Get the uid parameters of the child_fn2 process */ SAFE_FILE_SCANF("/proc/self/uid_map", "%d %d %d", &idinsidens, &idoutsidens, &length); @@ -127,32 +113,34 @@ static int child_fn2(LTP_ATTRIBUTE_UNUSED void *arg) TST_CHECKPOINT_WAKE(0); TST_CHECKPOINT_WAKE(1); - - return 0; -} - -static void setup(void) -{ - check_newuser(); } static void run(void) { - pid_t cpid2; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid1, cpid2; + uid_t parentuid; + gid_t parentgid; char path[BUFSIZ]; int fd; - int ret; parentuid = geteuid(); parentgid = getegid(); - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, child_fn1, NULL); - if (cpid1 < 0) - tst_brk(TBROK | TTERRNO, "cpid1 clone failed"); + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, child_fn2, NULL); - if (cpid2 < 0) - tst_brk(TBROK | TTERRNO, "cpid2 clone failed"); + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(cpid1, parentuid, parentgid); + return; + } if (access("/proc/self/setgroups", F_OK) == 0) { sprintf(path, "/proc/%d/setgroups", cpid1); @@ -168,19 +156,12 @@ static void run(void) * do so will fail with the error EPERM.) */ - /* test that setgroups can't be re-enabled */ - fd = SAFE_OPEN(path, O_WRONLY, 0644); - ret = write(fd, "allow", 5); - - if (ret != -1) - tst_brk(TBROK, "write action should fail"); - else if (errno != EPERM) - tst_brk(TBROK | TTERRNO, "unexpected error"); + tst_res(TINFO, "Check if setgroups can be re-enabled"); + fd = SAFE_OPEN(path, O_WRONLY, 0644); + TST_EXP_FAIL2(write(fd, "allow", 5), EPERM); SAFE_CLOSE(fd); - tst_res(TPASS, "setgroups can't be re-enabled"); - sprintf(path, "/proc/%d/setgroups", cpid2); fd = SAFE_OPEN(path, O_WRONLY, 0644); @@ -198,9 +179,9 @@ static void run(void) } static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS", diff --git a/testcases/kernel/containers/userns/userns04.c b/testcases/kernel/containers/userns/userns04.c index d8639502e..d20041f06 100644 --- a/testcases/kernel/containers/userns/userns04.c +++ b/testcases/kernel/containers/userns/userns04.c @@ -15,56 +15,49 @@ #define _GNU_SOURCE #include <stdio.h> -#include "common.h" #include "tst_test.h" -#include "lapi/syscalls.h" +#include "lapi/sched.h" -static void setup(void) -{ - check_newuser(); - tst_syscall(__NR_setns, -1, 0); -} - -static int child_fn1(LTP_ATTRIBUTE_UNUSED void *arg) +static void child_fn1(void) { TST_CHECKPOINT_WAIT(0); - return 0; } -static int child_fn2(void *arg) +static void child_fn2(int fd) { - TEST(tst_syscall(__NR_setns, ((long)arg), CLONE_NEWUSER)); - if (TST_RET != -1 || TST_ERR != EPERM) - tst_res(TFAIL | TERRNO, "child2 setns() error"); - else - tst_res(TPASS, "child2 setns() failed as expected"); - + TST_EXP_FAIL(setns(fd, CLONE_NEWUSER), EPERM); TST_CHECKPOINT_WAIT(1); - - return 0; } static void run(void) { + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; pid_t cpid1, cpid2, cpid3; char path[BUFSIZ]; int fd; - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } sprintf(path, "/proc/%d/ns/user", cpid1); fd = SAFE_OPEN(path, O_RDONLY, 0644); - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn2, (void *)((long)fd)); - if (cpid2 < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); - /* child 3 - throw-away process changing ns to child1 */ + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(fd); + return; + } + cpid3 = SAFE_FORK(); if (!cpid3) { - TST_EXP_PASS(tst_syscall(__NR_setns, fd, CLONE_NEWUSER)); + TST_EXP_PASS(setns(fd, CLONE_NEWUSER)); return; } @@ -75,7 +68,6 @@ static void run(void) } static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, .forks_child = 1, diff --git a/testcases/kernel/containers/userns/userns05.c b/testcases/kernel/containers/userns/userns05.c index 4c16694b1..e7a00af18 100644 --- a/testcases/kernel/containers/userns/userns05.c +++ b/testcases/kernel/containers/userns/userns05.c @@ -18,15 +18,12 @@ #include <stdio.h> #include "tst_test.h" +#include "lapi/sched.h" #include "common.h" -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void) +static void child_fn1(void) { TST_CHECKPOINT_WAIT(0); - return 0; } static unsigned int getusernsidbypid(int pid) @@ -47,14 +44,21 @@ static unsigned int getusernsidbypid(int pid) static void run(void) { + const struct tst_clone_args args1 = { .exit_signal = SIGCHLD }; + const struct tst_clone_args args2 = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; int cpid1, cpid2, cpid3; unsigned int parentuserns, cpid1userns, cpid2userns, newparentuserns; parentuserns = getusernsidbypid(getpid()); - cpid1 = ltp_clone_quick(SIGCHLD, (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + cpid1 = SAFE_CLONE(&args1); + if (!cpid1) { + child_fn1(); + return; + } cpid1userns = getusernsidbypid(cpid1); @@ -64,23 +68,20 @@ static void run(void) * CLONE_NEWUSER flag is a member of the same user namespace as its * parent */ - if (parentuserns != cpid1userns) - tst_res(TFAIL, "userns:parent should be equal to cpid1"); - else - tst_res(TPASS, "userns:parent is equal to cpid1"); + TST_EXP_EQ_LI(parentuserns, cpid1userns); - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, NULL); - if (cpid2 < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + cpid2 = SAFE_CLONE(&args2); + if (!cpid2) { + child_fn1(); + return; + } cpid2userns = getusernsidbypid(cpid2); TST_CHECKPOINT_WAKE(0); - if (parentuserns == cpid2userns) - tst_res(TFAIL, "userns:parent should be not equal to cpid2"); - else - tst_res(TPASS, "userns:parent is not equal to cpid2"); + TST_EXP_EXPR(parentuserns != cpid2userns, + "parent namespace != child namespace"); cpid3 = SAFE_FORK(); if (!cpid3) { @@ -91,20 +92,12 @@ static void run(void) * is moved into a new user namespace which is not shared * with any previously existing process */ - if (parentuserns == newparentuserns) - tst_res(TFAIL, "unshared namespaces with same id"); - else - tst_res(TPASS, "unshared namespaces with different id"); + TST_EXP_EXPR(parentuserns != newparentuserns, + "parent namespace != unshared child namespace"); } } -static void setup(void) -{ - check_newuser(); -} - static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, .forks_child = 1, diff --git a/testcases/kernel/containers/userns/userns06.c b/testcases/kernel/containers/userns/userns06.c index 39f02e38a..a270dafdc 100644 --- a/testcases/kernel/containers/userns/userns06.c +++ b/testcases/kernel/containers/userns/userns06.c @@ -20,6 +20,7 @@ #define _GNU_SOURCE #include <stdio.h> +#include "lapi/sched.h" #include "common.h" #define TEST_APP "userns06_capcheck" @@ -29,7 +30,7 @@ #define CHILD2UID 200 #define CHILD2GID 200 -static int child_fn1(void) +static void child_fn1(void) { char *const args[] = { TEST_APP, "privileged", NULL }; int ret; @@ -39,11 +40,9 @@ static int child_fn1(void) ret = execv(args[0], args); if (ret == -1) tst_brk(TBROK | TERRNO, "execv: unexpected error"); - - return 0; } -static int child_fn2(void) +static void child_fn2(void) { int uid, gid, ret; char *const args[] = { TEST_APP, "unprivileged", NULL }; @@ -53,27 +52,20 @@ static int child_fn2(void) uid = geteuid(); gid = getegid(); - if (uid != CHILD2UID || gid != CHILD2GID) { - tst_res(TFAIL, "unexpected uid=%d gid=%d", uid, gid); - return 1; - } - - tst_res(TPASS, "expected uid and gid"); + TST_EXP_EQ_LI(uid, CHILD2UID); + TST_EXP_EQ_LI(gid, CHILD2GID); ret = execv(args[0], args); if (ret == -1) tst_brk(TBROK | TERRNO, "execv: unexpected error"); - - return 0; -} - -static void setup(void) -{ - check_newuser(); } static void run(void) { + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; pid_t cpid1; pid_t cpid2; int parentuid; @@ -84,13 +76,17 @@ static void run(void) parentuid = geteuid(); parentgid = getegid(); - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brk(TBROK | TTERRNO, "cpid1 clone failed"); + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn2, NULL); - if (cpid2 < 0) - tst_brk(TBROK | TTERRNO, "cpid2 clone failed"); + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(); + return; + } if (access("/proc/self/setgroups", F_OK) == 0) { sprintf(path, "/proc/%d/setgroups", cpid1); @@ -117,9 +113,9 @@ static void run(void) } static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, .resource_files = (const char *[]) { TEST_APP, diff --git a/testcases/kernel/containers/userns/userns06_capcheck.c b/testcases/kernel/containers/userns/userns06_capcheck.c index c048ef63f..8669657b9 100644 --- a/testcases/kernel/containers/userns/userns06_capcheck.c +++ b/testcases/kernel/containers/userns/userns06_capcheck.c @@ -24,8 +24,8 @@ int main(int argc, char *argv[]) { cap_t caps; int i, last_cap; - cap_flag_value_t flag_val; - cap_flag_value_t expected_flag = 1; + cap_flag_value_t cap_flag; + cap_flag_value_t expected_cap_flag = 1; tst_reinit(); @@ -35,24 +35,21 @@ int main(int argc, char *argv[]) SAFE_FILE_SCANF("/proc/sys/kernel/cap_last_cap", "%d", &last_cap); if (strcmp("privileged", argv[1])) - expected_flag = 0; + expected_cap_flag = 0; caps = cap_get_proc(); for (i = 0; i <= last_cap; i++) { - cap_get_flag(caps, i, CAP_EFFECTIVE, &flag_val); - if (flag_val != expected_flag) + cap_get_flag(caps, i, CAP_EFFECTIVE, &cap_flag); + if (cap_flag != expected_cap_flag) break; - cap_get_flag(caps, i, CAP_PERMITTED, &flag_val); - if (flag_val != expected_flag) + cap_get_flag(caps, i, CAP_PERMITTED, &cap_flag); + if (cap_flag != expected_cap_flag) break; } - if (flag_val != expected_flag) - tst_res(TFAIL, "unexpected effective/permitted caps at %d", i); - else - tst_res(TPASS, "expected caps at %d", i); + TST_EXP_EQ_LI(cap_flag, expected_cap_flag); return 0; } diff --git a/testcases/kernel/containers/userns/userns07.c b/testcases/kernel/containers/userns/userns07.c index 4659de636..2217a5ed0 100644 --- a/testcases/kernel/containers/userns/userns07.c +++ b/testcases/kernel/containers/userns/userns07.c @@ -16,19 +16,17 @@ #include <sys/wait.h> #include "common.h" #include "tst_test.h" +#include "lapi/sched.h" #define MAXNEST 32 -static void setup(void) +static void child_fn1(const int level) { - check_newuser(); -} - -static int child_fn1(void *arg) -{ - pid_t cpid1; - long level = (long)arg; - int status; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid; int parentuid; int parentgid; @@ -36,63 +34,68 @@ static int child_fn1(void *arg) if (level == MAXNEST) { tst_res(TPASS, "nested all children"); - return 0; + return; } - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, (void *)(level + 1)); - if (cpid1 < 0) { - tst_res(TFAIL | TERRNO, "level %ld, unexpected error", level); - return 1; + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_fn1(level + 1); + return; } parentuid = geteuid(); parentgid = getegid(); - updatemap(cpid1, UID_MAP, 0, parentuid); - updatemap(cpid1, GID_MAP, 0, parentgid); + updatemap(cpid, UID_MAP, 0, parentuid); + updatemap(cpid, GID_MAP, 0, parentgid); TST_CHECKPOINT_WAKE(0); - SAFE_WAITPID(cpid1, &status, 0); - - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_brk(TBROK, "child %s", tst_strstatus(status)); - - return 0; + tst_reap_children(); } static void run(void) { - pid_t cpid1; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid; int parentuid; int parentgid; char path[BUFSIZ]; - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, (void *)child_fn1, (void *)0); - if (cpid1 < 0) - tst_brk(TBROK | TTERRNO, "clone failed"); + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_fn1(0); + return; + } parentuid = geteuid(); parentgid = getegid(); if (access("/proc/self/setgroups", F_OK) == 0) { - sprintf(path, "/proc/%d/setgroups", cpid1); + sprintf(path, "/proc/%d/setgroups", cpid); SAFE_FILE_PRINTF(path, "deny"); } - updatemap(cpid1, UID_MAP, 0, parentuid); - updatemap(cpid1, GID_MAP, 0, parentgid); + updatemap(cpid, UID_MAP, 0, parentuid); + updatemap(cpid, GID_MAP, 0, parentgid); TST_CHECKPOINT_WAKE(0); } static struct tst_test test = { - .setup = setup, .test_all = run, .needs_root = 1, + .forks_child = 1, .needs_checkpoints = 1, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS", NULL, }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/unprivileged_userns_clone", "1", TST_SR_SKIP}, + {} + }, }; diff --git a/testcases/kernel/containers/userns/userns08.c b/testcases/kernel/containers/userns/userns08.c index 2697d874b..72d7f8d12 100644 --- a/testcases/kernel/containers/userns/userns08.c +++ b/testcases/kernel/containers/userns/userns08.c @@ -31,8 +31,8 @@ static pid_t clone_newuser(void) { const struct tst_clone_args cargs = { - CLONE_NEWUSER, - SIGCHLD + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, }; return SAFE_CLONE(&cargs); @@ -136,6 +136,7 @@ static struct tst_test test = { }, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/user/max_user_namespaces", NULL, TST_SR_SKIP}, + {"/proc/sys/kernel/unprivileged_userns_clone", "1", TST_SR_SKIP}, {} }, .tags = (const struct tst_tag[]) { diff --git a/testcases/kernel/containers/userns/userns_helper.h b/testcases/kernel/containers/userns/userns_helper.h deleted file mode 100644 index be47690ea..000000000 --- a/testcases/kernel/containers/userns/userns_helper.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - */ - -#include "../libclone/libclone.h" -#include "test.h" -#include "safe_macros.h" -#include <stdbool.h> - -#define UID_MAP 0 -#define GID_MAP 1 - -static int dummy_child(void *v) -{ - (void) v; - return 0; -} - -static int check_newuser(void) -{ - int pid, status; - - pid = do_clone_unshare_test(T_CLONE, CLONE_NEWUSER, dummy_child, NULL); - if (pid == -1) - tst_brkm(TCONF | TERRNO, NULL, "CLONE_NEWUSER not supported"); - SAFE_WAIT(NULL, &status); - - return 0; -} - -LTP_ATTRIBUTE_UNUSED static int updatemap(int cpid, bool type, int idnum, - int parentmappid, void (*cleanup)(void)) -{ - char path[BUFSIZ]; - char content[BUFSIZ]; - int fd; - - if (type == UID_MAP) - sprintf(path, "/proc/%d/uid_map", cpid); - else if (type == GID_MAP) - sprintf(path, "/proc/%d/gid_map", cpid); - else - tst_brkm(TBROK, cleanup, "invalid type parameter"); - - sprintf(content, "%d %d 1", idnum, parentmappid); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, content, strlen(content)); - SAFE_CLOSE(cleanup, fd); - return 0; -} diff --git a/testcases/kernel/containers/utsname/.gitignore b/testcases/kernel/containers/utsname/.gitignore index 0e1f41dc8..945ed280e 100644 --- a/testcases/kernel/containers/utsname/.gitignore +++ b/testcases/kernel/containers/utsname/.gitignore @@ -1 +1,4 @@ -/utstest +/utsname01 +/utsname02 +/utsname03 +/utsname04 diff --git a/testcases/kernel/containers/utsname/Makefile b/testcases/kernel/containers/utsname/Makefile index 5efcbf648..b6beb8b8f 100644 --- a/testcases/kernel/containers/utsname/Makefile +++ b/testcases/kernel/containers/utsname/Makefile @@ -1,28 +1,7 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc - -LDLIBS := -lclone -lpthread -lrt $(LDLIBS) - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/utsname/runutstests_noltp.sh b/testcases/kernel/containers/utsname/runutstests_noltp.sh deleted file mode 100755 index 43cb7e26b..000000000 --- a/testcases/kernel/containers/utsname/runutstests_noltp.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ - -oldhostname=`hostname` -exit_code=0 -echo "unshare tests" -for i in `seq 1 5`; do - echo "test $i (unshare)" - ./utstest_noltp unshare $i - if [ $? -ne 0 ]; then - exit_code=$? - fi -done -echo "clone tests" -for i in `seq 1 5`; do - echo "test $i (clone)" - ./utstest_noltp clone $i - if [ $? -ne 0 ]; then - exit_code=$? - fi -done -hostname "$oldhostname" -exit $exit_code diff --git a/testcases/kernel/containers/utsname/utsname01.c b/testcases/kernel/containers/utsname/utsname01.c new file mode 100644 index 000000000..fc5c1a271 --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname01.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Clone two plain processes and check if both read the same hostname. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" + +static char *hostname1; +static char *hostname2; + +static void run(void) +{ + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!SAFE_FORK()) { + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + return; + } + + if (!SAFE_FORK()) { + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); + return; + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, hostname2)); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/utsname/utsname02.c b/testcases/kernel/containers/utsname/utsname02.c new file mode 100644 index 000000000..aa90596d4 --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname02.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Clone two plain processes, change hostname in the first one then check if + * hostaname has changed inside the second one as well. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" + +#define HOSTNAME "LTP_HOSTNAME" + +static char *hostname1; +static char *hostname2; +static char originalhost[HOST_NAME_MAX]; + +static void reset_hostname(void) +{ + SAFE_SETHOSTNAME(originalhost, strlen(originalhost)); +} + +static void run(void) +{ + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!SAFE_FORK()) { + SAFE_SETHOSTNAME(HOSTNAME, strlen(HOSTNAME)); + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + + TST_CHECKPOINT_WAKE(0); + return; + } + + if (!SAFE_FORK()) { + TST_CHECKPOINT_WAIT(0); + + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); + return; + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, HOSTNAME)); + TST_EXP_PASS(strcmp(hostname2, HOSTNAME)); + + reset_hostname(); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(originalhost, 0, HOST_NAME_MAX); + + SAFE_GETHOSTNAME(originalhost, HOST_NAME_MAX); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); + + reset_hostname(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/utsname/utsname03.c b/testcases/kernel/containers/utsname/utsname03.c new file mode 100644 index 000000000..e5a4a56dc --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname03.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Clone two processes using CLONE_NEWUTS, change hostname from the first + * container and check if hostname didn't change inside the second one. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/sched.h" + +#define HOSTNAME "LTP_HOSTNAME" + +static char *str_op; +static char *hostname1; +static char *hostname2; +static char originalhost[HOST_NAME_MAX]; + +static void reset_hostname(void) +{ + SAFE_SETHOSTNAME(originalhost, strlen(originalhost)); +} + +static void child1_run(void) +{ + SAFE_SETHOSTNAME(HOSTNAME, strlen(HOSTNAME)); + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + + TST_CHECKPOINT_WAKE(0); +} + +static void child2_run(void) +{ + TST_CHECKPOINT_WAIT(0); + + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); +} + +static void run(void) +{ + const struct tst_clone_args cargs = { + .flags = CLONE_NEWUTS, + .exit_signal = SIGCHLD, + }; + + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!str_op || !strcmp(str_op, "clone")) { + tst_res(TINFO, "clone() with CLONE_NEWUTS"); + + if (!SAFE_CLONE(&cargs)) { + child1_run(); + return; + } + + if (!SAFE_CLONE(&cargs)) { + child2_run(); + return; + } + } else { + tst_res(TINFO, "unshare() with CLONE_NEWUTS"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWUTS); + child1_run(); + return; + } + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWUTS); + child2_run(); + return; + } + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, HOSTNAME)); + TST_EXP_PASS(strcmp(hostname2, originalhost)); + + reset_hostname(); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(originalhost, 0, HOST_NAME_MAX); + + SAFE_GETHOSTNAME(originalhost, HOST_NAME_MAX); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); + + reset_hostname(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode <clone|unshare>" }, + {}, + }, +}; diff --git a/testcases/kernel/containers/utsname/utsname04.c b/testcases/kernel/containers/utsname/utsname04.c new file mode 100644 index 000000000..bf97880ba --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname04.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Drop root privileges, create a container with CLONE_NEWUTS and verify that + * we receive a permission error. + */ + +#define _GNU_SOURCE + +#include <pwd.h> +#include "tst_test.h" +#include "lapi/sched.h" + +static char *str_op; + +static void run(void) +{ + const struct tst_clone_args cargs = { + .flags = CLONE_NEWUTS, + .exit_signal = SIGCHLD, + }; + struct passwd *pw; + + tst_res(TINFO, "Dropping root privileges"); + + pw = SAFE_GETPWNAM("nobody"); + SAFE_SETRESUID(pw->pw_uid, pw->pw_uid, pw->pw_uid); + + if (!str_op || !strcmp(str_op, "clone")) { + TEST(tst_clone(&cargs)); + + if (TST_RET == -1) + tst_res(TPASS, "clone3() fails as expected"); + else if (TST_RET == -2) + tst_res(TPASS, "clone() fails as expected"); + else + tst_res(TFAIL, "tst_clone returns %ld", TST_RET); + + TST_EXP_PASS(errno == EPERM); + } else { + if (!SAFE_FORK()) { + TST_EXP_EQ_LI(unshare(CLONE_NEWUTS), -1); + TST_EXP_PASS(errno == EPERM); + return; + } + } +} + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode <clone|unshare>" }, + {}, + }, +}; diff --git a/testcases/kernel/containers/utsname/utstest.c b/testcases/kernel/containers/utsname/utstest.c deleted file mode 100644 index 9ad19b6b2..000000000 --- a/testcases/kernel/containers/utsname/utstest.c +++ /dev/null @@ -1,353 +0,0 @@ -/* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program 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 General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** - * Copyright 2007 IBM - * Author: Serge Hallyn <serue@us.ibm.com> - * - * test1: - P1: A=gethostname - P2: B=gethostname - Ensure(A==B) - - * test2: - P1: sethostname(A); - P2: (wait); B=gethostname - Ensure (A==B) - - * test3: - P1: A=gethostname; unshare(utsname); sethostname(newname); C=gethostname - P2: B=gethostname; (wait); (wait); D=gethostname - Ensure (A==B && A==D && C!=D) - - * test4: - P1: A=gethostname; unshare(utsname); (wait); C=gethostname - P2: B=gethostname; (wait); sethostname(newname); D=gethostname - Ensure (A==B && A==C && C!=D) - - * test5: - P1: drop_privs(); unshare(utsname); (wait); C=gethostname - P2: (wait); sethostname(B); D=gethostname - Ensure (B==C==D) and state is ok. - * - */ - -#define _GNU_SOURCE 1 -#include <sys/wait.h> -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include "libclone.h" -#include "test.h" -#include "safe_macros.h" - -char *TCID = "uts_namespace"; -int TST_TOTAL = 1; - -static int dummy_child(void *v) -{ - (void) v; - return 0; -} - -static void check_newuts(void) -{ - int pid, status; - - pid = do_clone_unshare_test(T_CLONE, CLONE_NEWUTS, dummy_child, NULL); - if (pid == -1) - tst_brkm(TCONF | TERRNO, NULL, "CLONE_NEWUTS not supported"); - - SAFE_WAIT(NULL, &status); -} - -int drop_root(void) -{ - int ret; - ret = setresuid(1000, 1000, 1000); - if (ret) { - perror("setresuid"); - exit(4); - } - return 1; -} - -#define HLEN 100 -#define NAME1 "serge1" -#define NAME2 "serge2" - -int p1fd[2], p2fd[2]; -static char oldhost[HLEN]; -pid_t cpid; - -void picknewhostname(char *orig, char *new) -{ - memset(new, 0, HLEN); - if (strcmp(orig, NAME1) == 0) - strcpy(new, NAME2); - else - strcpy(new, NAME1); -} - -void zeroize(char *s) -{ - memset(s, 0, HLEN); -} - -char *tsttype; -int P1(void *vtest) -{ - char hostname[HLEN], newhostname[HLEN], rhostname[HLEN]; - int err; - int len; - int testnum; - - testnum = atoi((char *)vtest); - - close(p1fd[1]); - close(p2fd[0]); - - switch (testnum) { - case 1: - gethostname(hostname, HLEN); - zeroize(rhostname); - len = read(p1fd[0], rhostname, HLEN); - if (strcmp(hostname, rhostname) == 0) { - tst_resm(TPASS, "test 1 (%s): success", tsttype); - tst_exit(); - } - tst_brkm(TFAIL, NULL, - "test 1 (%s): hostname 1 %s, hostname 2 %s", - tsttype, hostname, rhostname); - case 2: - gethostname(hostname, HLEN); - picknewhostname(hostname, newhostname); - err = sethostname(newhostname, strlen(newhostname)); - write(p2fd[1], "1", 1); - if (err == -1) { - tst_brkm(TFAIL, NULL, - "test 2 (%s): failed to sethostname", - tsttype); - } - zeroize(rhostname); - len = read(p1fd[0], rhostname, HLEN); - if (strcmp(newhostname, rhostname) == 0) { - tst_resm(TPASS, "test 2 (%s): success", tsttype); - tst_exit(); - } - tst_brkm(TFAIL, NULL, - "test 2 (%s) hostname 1 %s, hostname 2 %s", - tsttype, newhostname, rhostname); - case 3: - gethostname(hostname, HLEN); - picknewhostname(hostname, newhostname); - err = sethostname(newhostname, strlen(newhostname)); - write(p2fd[1], "1", 1); - if (err == -1) { - tst_brkm(TFAIL, NULL, - "test 3 (%s): failed to sethostname", - tsttype); - } - - zeroize(rhostname); - len = read(p1fd[0], rhostname, HLEN); - if (strcmp(newhostname, rhostname) == 0) { - tst_brkm(TFAIL, - NULL, - "test 3 (%s): hostname 1 %s, hostname 2 %s, these should have been different", - tsttype, newhostname, rhostname); - } - if (strcmp(hostname, rhostname) == 0) { - tst_resm(TPASS, "test 3 (%s): success", tsttype); - tst_exit(); - } - tst_brkm(TFAIL, - NULL, - "test 3 (%s): hostname 1 %s, hostname 2 %s, should have been same", - tsttype, hostname, rhostname); - - case 4: - gethostname(hostname, HLEN); - write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */ - zeroize(rhostname); - len = read(p1fd[0], rhostname, HLEN); - gethostname(newhostname, HLEN); - if (strcmp(hostname, newhostname) != 0) { - tst_brkm(TFAIL, - NULL, - "test 4 (%s): hostname 1 %s, hostname 2 %s, should be same", - tsttype, hostname, newhostname); - } - if (strcmp(hostname, rhostname) == 0) { - tst_brkm(TFAIL, - NULL, - "test 4 (%s): hostname 1 %s, hostname 2 %s, should be different", - tsttype, hostname, rhostname); - } - tst_resm(TPASS, "test 4 (%s): successful", tsttype); - tst_exit(); - case 5: - write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */ - zeroize(rhostname); - len = read(p1fd[0], rhostname, HLEN); - gethostname(newhostname, HLEN); - if (strcmp(rhostname, newhostname) != 0) { - tst_brkm(TFAIL, - NULL, - "test 5 (%s): hostnames %s and %s should be same", - tsttype, rhostname, newhostname); - } - tst_resm(TPASS, "test 5 (%s): successful", tsttype); - tst_exit(); - default: - break; - } - tst_exit(); -} - -int P2(void *vtest) -{ - char hostname[HLEN], newhostname[HLEN]; - int len; - int testnum; - - testnum = atoi((char *)vtest); - - close(p1fd[0]); - close(p2fd[1]); - - switch (testnum) { - case 1: - gethostname(hostname, HLEN); - write(p1fd[1], hostname, strlen(hostname)); - break; - case 2: - case 3: - len = 0; - while (!len) { - len = read(p2fd[0], hostname, 1); - } - gethostname(hostname, HLEN); - write(p1fd[1], hostname, strlen(hostname)); - break; - case 4: - case 5: - len = 0; - while (!len) { - len = read(p2fd[0], hostname, 1); - } - if (hostname[0] == '0') { - tst_resm(TPASS, "P2: P1 claims error"); - return 0; - } - gethostname(hostname, HLEN); - picknewhostname(hostname, newhostname); - sethostname(newhostname, strlen(newhostname)); - write(p1fd[1], newhostname, strlen(newhostname)); - break; - default: - tst_resm(TFAIL, "undefined test: %d", testnum); - break; - } - return 0; -} - -static void setup(void) -{ - gethostname(oldhost, HLEN); - tst_require_root(); - check_newuts(); -} - -static void cleanup(void) -{ - sethostname(oldhost, strlen(oldhost)); -} - -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -int main(int argc, char *argv[]) -{ - int r, pid, use_clone = T_UNSHARE; - int testnum; - void *vtest; - - setup(); - if (argc != 3) { - tst_resm(TFAIL, "Usage: %s <clone|unshare> <testnum>", - argv[0]); - tst_resm(TFAIL, - " where clone or unshare specifies unshare method,"); - tst_resm(TFAIL, " and testnum is between 1 and 5 inclusive"); - exit(2); - } - if (pipe(p1fd) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2fd) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - - tsttype = UNSHARESTR; - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } - - testnum = atoi(argv[2]); - - vtest = (void *)argv[2]; - switch (testnum) { - case 1: - case 2: - r = do_clone_unshare_tests(T_NONE, 0, P1, vtest, P2, vtest); - break; - case 3: - case 4: - r = do_clone_unshare_tests(use_clone, CLONE_NEWUTS, - P1, vtest, P2, vtest); - break; - case 5: - pid = fork(); - if (pid == -1) { - perror("fork"); - exit(2); - } - if (pid == 0) { - if (!drop_root()) { - tst_brkm(TFAIL, NULL, "failed to drop root."); - } - r = do_clone_unshare_test(use_clone, CLONE_NEWUTS, - P1, vtest); - write(p2fd[1], "0", 1); /* don't let p2 hang */ - exit(0); - } else { - P2(vtest); - } - break; - default: - tst_resm(TFAIL, - "testnum should be between 1 and 5 inclusive."); - break; - } - - cleanup(); - tst_exit(); -} diff --git a/testcases/kernel/controllers/cgroup/.gitignore b/testcases/kernel/controllers/cgroup/.gitignore index 8deae77da..9f1d1ada9 100644 --- a/testcases/kernel/controllers/cgroup/.gitignore +++ b/testcases/kernel/controllers/cgroup/.gitignore @@ -2,3 +2,4 @@ /cgroup_regression_getdelays /cgroup_core01 /cgroup_core02 +/cgroup_core03 diff --git a/testcases/kernel/controllers/cgroup/cgroup_core03.c b/testcases/kernel/controllers/cgroup/cgroup_core03.c new file mode 100644 index 000000000..7d40d47f9 --- /dev/null +++ b/testcases/kernel/controllers/cgroup/cgroup_core03.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2012 Christian Brauner <brauner-AT-kernel.org> + * Copyright (c) 2023 SUSE LLC <wegao@suse.com> + */ + +/*\ + * [Description] + * + * This test is copied from kselftest + * tools/testing/selftests/cgroup/test_kill.c. + * + * Only simple test implemented within current case, the other cases such + * as test_cgkill_tree and test_cgkill_forkbomb can be created later. + * + */ + +#include <sys/wait.h> + +#include "lapi/syscalls.h" +#include "tst_test.h" + +#define MAX_PID_NUM 100 +#define PID_NUM MIN(MAX_PID_NUM, (tst_ncpus_available() + 1)) +#define BUF_LEN (20 * PID_NUM) + +static int *data_ptr; +static char *buf; +static struct tst_cg_group *cg_child_test_simple; + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (WIFSIGNALED(status)) + return 0; + + return -1; +} + +static int cg_run_nowait(const struct tst_cg_group *const cg) +{ + int pid; + + pid = SAFE_FORK(); + if (pid == 0) { + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + if (tst_atomic_inc(data_ptr) == PID_NUM) + TST_CHECKPOINT_WAKE(0); + pause(); + } + + return pid; +} + +static int cg_count_procs(const struct tst_cg_group *cg) +{ + char *ptr; + + int nr = 0; + + SAFE_CG_READ(cg, "cgroup.procs", buf, BUF_LEN); + + for (ptr = buf; *ptr; ptr++) + if (*ptr == '\n') + nr++; + + return nr; +} + +static void run(void) +{ + pid_t pids[MAX_PID_NUM]; + int i; + *data_ptr = 0; + + cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple"); + + if (!SAFE_CG_HAS(cg_child_test_simple, "cgroup.kill")) { + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); + tst_brk(TCONF, "cgroup.kill is not supported on your distribution"); + } + + memset(buf, 0, BUF_LEN); + + for (i = 0; i < PID_NUM; i++) + pids[i] = cg_run_nowait(cg_child_test_simple); + + TST_CHECKPOINT_WAIT(0); + TST_EXP_VAL(cg_count_procs(cg_child_test_simple), PID_NUM); + SAFE_CG_PRINTF(cg_child_test_simple, "cgroup.kill", "%d", 1); + + for (i = 0; i < PID_NUM; i++) + TST_EXP_PASS_SILENT(wait_for_pid(pids[i])); + + TST_EXP_VAL(cg_count_procs(cg_child_test_simple), 0); + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); +} + +static void setup(void) +{ + buf = tst_alloc(BUF_LEN); + data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(uintptr_t)); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .max_runtime = 20, + .needs_cgroup_ctrls = (const char *const []){ "base", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh index d80b83bbd..72d3c53f4 100755 --- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh +++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh @@ -7,7 +7,7 @@ TCID="cgroup_fj_stress" TST_CNT=1 -TST_TESTFUNC=test +TST_TESTFUNC=do_test TST_SETUP=setup TST_CLEANUP=cleanup TST_POS_ARGS=4 @@ -126,7 +126,7 @@ cleanup() common_cleanup } -test() +do_test() { tst_res TINFO "Creating subgroups ..." diff --git a/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh b/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh index 3fcba1491..5b53544cf 100755 --- a/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh +++ b/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh @@ -200,7 +200,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "9" ) @@ -279,7 +279,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "10" ) @@ -346,7 +346,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; * ) diff --git a/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh b/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh index bbbd2fbcb..5b09fb273 100755 --- a/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh +++ b/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh @@ -144,7 +144,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "4" ) @@ -210,7 +210,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "5" ) @@ -270,7 +270,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; diff --git a/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh b/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh index ab73c801b..5cb6bb566 100755 --- a/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh +++ b/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh @@ -63,7 +63,7 @@ cleanup() return 0 } - find $CPUCTL -type d | sort | sed -n '2,$p' | tac | while read tmpdir + find $CPUCTL -type d | sort | sed -n '2,$p' | tac | while read -r tmpdir do while read tmppid do diff --git a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh index 87ba7da1f..0cfa0c17e 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh @@ -184,7 +184,7 @@ cleanup() echo $CHILDREN_VALUE > $CLONE_CHILDREN echo $SCHED_LB_VALUE > $SCHED_LB - find "$CPUSET" -type d | sort | sed -n '2,$p' | tac | while read subdir + find "$CPUSET" -type d | sort | sed -n '2,$p' | tac | while read -r subdir do while read pid do diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh index eddd7f6c5..fff0ab318 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh @@ -33,10 +33,12 @@ check exit_status=0 # usable physical memory -py_mem=$(free -m | awk '{if(NR==2) print $4 + $6 + $7}') +py_mem=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) +py_mem=$(( $py_mem / 1024 )) # free swap space -sw_mem=$(free -m | awk '{if(NR==4) print $4}') +sw_mem=$(awk '/SwapFree/ {print $2}' /proc/meminfo) +sw_mem=$(( $sw_mem / 1024 )) # the memory which is going to be used usemem=$((py_mem - 20)) diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh index e2767ef05..f7230a4ea 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh @@ -38,7 +38,15 @@ nr_mems=$N_NODES # on which it is running. The other nodes' slab space has littler change.(less # than 1000 kb). upperlimit=10000 -lowerlimit=2000 + +# set lowerlimit according to pagesize +# pagesize(bytes) | lowerlimit(kb) +# ------------------------------------ +# 4096 | 2048 +# 16384 | 8192 + +PAGE_SIZE=`tst_getconf PAGESIZE` +lowerlimit=$((PAGE_SIZE * 512 / 1024)) cpus_all="$(seq -s, 0 $((nr_cpus-1)))" mems_all="$(seq -s, 0 $((nr_mems-1)))" diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh index cb7dbd867..c1e7cea8f 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh @@ -41,7 +41,7 @@ mems_all="$(seq -s, 0 $((nr_mems-1)))" cpu_of_node0=0 HUGEPAGESIZE=$(awk '/Hugepagesize/{ print $2 }' /proc/meminfo) -HUGEPAGESIZE=$(($HUGEPAGESIZE * 1024)) +HUGEPAGESIZE=$((${HUGEPAGESIZE:-0} * 1024)) MEMORY_RESULT="$CPUSET_TMP/memory_result" diff --git a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh index 8e87d20e4..a5757309f 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh @@ -12,7 +12,7 @@ TST_SETUP=setup TST_CLEANUP=cleanup -TST_TESTFUNC=test +TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_MIN_KVER="3.18" @@ -130,6 +130,11 @@ setup() tst_res TINFO "test starts with cgroup version $cgroup_version" + if [ "$cgroup_version" = "2" ]; then + tst_brk TCONF "cgroup v2 found, skipping test" + return + fi + if ! [ -f ${root_cpuset_dir}/${cpu_exclusive} ]; then cpu_exclusive=cpu_exclusive cpus=cpus @@ -178,7 +183,7 @@ cleanup() cgroup_cleanup } -test() +do_test() { local cpu_exclusive_tmp cpus_value diff --git a/testcases/kernel/controllers/freezer/00_description.txt b/testcases/kernel/controllers/freezer/00_description.txt index b59741282..989a4a405 100644 --- a/testcases/kernel/controllers/freezer/00_description.txt +++ b/testcases/kernel/controllers/freezer/00_description.txt @@ -21,7 +21,7 @@ freeze_self_thaw.sh The subshell process sleeps and then freezes the control group it is a part of. We then thaw the subshell process. We expect the unthawed subshell process to need cleanup afterwards (allows us to test - successfull thawing). + successful thawing). freeze_sleep_thaw.sh This bash script tests freezer code by starting a long sleep process. diff --git a/testcases/kernel/controllers/freezer/freeze_self_thaw.sh b/testcases/kernel/controllers/freezer/freeze_self_thaw.sh index 773c4afa1..f6943cda8 100755 --- a/testcases/kernel/controllers/freezer/freeze_self_thaw.sh +++ b/testcases/kernel/controllers/freezer/freeze_self_thaw.sh @@ -22,7 +22,7 @@ # This bash script tests freezer code by starting a long subshell process. # The subshell process sleeps and then freezes the control group it is a # part of. We then thaw the subshell process. We expect the unthawed subshell -# process to need cleanup afterwards (allows us to test successfull thawing). +# process to need cleanup afterwards (allows us to test successful thawing). # . "${CGROUPS_TESTROOT}/libcgroup_freezer" diff --git a/testcases/kernel/controllers/freezer/vfork_freeze.sh b/testcases/kernel/controllers/freezer/vfork_freeze.sh index 4bb844ff4..6d3487600 100755 --- a/testcases/kernel/controllers/freezer/vfork_freeze.sh +++ b/testcases/kernel/controllers/freezer/vfork_freeze.sh @@ -60,7 +60,7 @@ TMPLOG="$TMPDIR/${0##*/}.$$.txt" # create new processes. The vfork'ed processes then sleep, causing the # parent process ($sample_proc) to enter the TASK_UNINTERRUPTIBLE state # for the duration of the sleep. -function vfork_sleep() +vfork_sleep() { vfork -s$sample_sleep 1 -f "$TMPLOG" & local rc=$? diff --git a/testcases/kernel/controllers/io/io_control01.c b/testcases/kernel/controllers/io/io_control01.c index c4e171af5..691196886 100644 --- a/testcases/kernel/controllers/io/io_control01.c +++ b/testcases/kernel/controllers/io/io_control01.c @@ -55,6 +55,7 @@ static void run(void) char *buf = SAFE_MALLOC(MAX((size_t)BUFSIZ, pgsz)); struct io_stats start; + memset(&start, 0, sizeof(struct io_stats)); SAFE_CG_READ(tst_cg, "io.stat", buf, BUFSIZ - 1); line = strtok_r(buf, "\n", &buf_ptr); while (line) { diff --git a/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh b/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh index 1be98a056..3a02d16c2 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh @@ -8,11 +8,11 @@ # Restructure for LTP: Shi Weihua <shiwh@cn.fujitsu.com> # Added memcg enable/disable functionality: Rishikesh K Rajak <risrajak@linux.vnet.ibm.com> -MEMCG_TESTFUNC=test +MEMCG_TESTFUNC=do_test MEMCG_SHMMAX=1 TST_TEST_DATA="--mmap-anon --mmap-file --shm" -test() +do_test() { ROD echo $MEMORY_LIMIT \> memory.limit_in_bytes diff --git a/testcases/kernel/controllers/memcg/functional/memcg_lib.sh b/testcases/kernel/controllers/memcg/functional/memcg_lib.sh index dbb61e6b1..5efede9cf 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_lib.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_lib.sh @@ -404,8 +404,8 @@ fi # Post 4.16 kernel updates stat in batch (> 32 pages) every time # Post 6.1 kernel updates stat in batch (> 64 pages) every time # 1813e51eece0ad6 ("memcg: increase MEMCG_CHARGE_BATCH to 64") -# has been merged since 5.14.0-191.el9. -if tst_kvcmp -lt "6.1 RHEL9:5.14.0-191" ; then +# has been merged since 5.14.0-191.el9 and 4.18.0-438.el8. +if tst_kvcmp -lt "6.1 RHEL9:5.14.0-191 RHEL8:4.18.0-438" ; then PAGESIZES=$(($PAGESIZE * 33)) else PAGESIZES=$(($PAGESIZE * 65)) diff --git a/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh b/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh index cb52840d7..47cac9af8 100755 --- a/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh +++ b/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh @@ -33,14 +33,17 @@ setup() echo 3 > /proc/sys/vm/drop_caches sleep 2 - local mem_free=`cat /proc/meminfo | grep MemFree | awk '{ print $2 }'` - local swap_free=`cat /proc/meminfo | grep SwapFree | awk '{ print $2 }'` - local pgsize=`tst_getconf PAGESIZE` - - MEM=$(( $mem_free + $swap_free / 2 )) + local mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo) + local mem_available=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) + local swap_free=$(awk '/SwapFree/ {print $2}' /proc/meminfo) + local mem_min=$(cat /proc/sys/vm/min_free_kbytes) + + mem_min=$(( $mem_min + $mem_min/10 )) + [ $swap_free -gt $mem_min ] && RESERVED_MEM=0 || RESERVED_MEM=$mem_min + [ $mem_free -lt $mem_available ] && MEM=$mem_free || MEM=$mem_available + MEM=$(( $MEM - $RESERVED_MEM )) MEM=$(( $MEM / 1024 )) RUN_TIME=$(( 15 * 60 )) - [ "$pgsize" = "4096" ] && THREAD_SPARE_MB=1 || THREAD_SPARE_MB=8 tst_res TINFO "Calculated available memory $MEM MB" } @@ -93,12 +96,12 @@ run_stress() test1() { - run_stress 150 $(( ($MEM - 150 * $THREAD_SPARE_MB) / 150 )) 5 $RUN_TIME + run_stress 150 $(( $MEM / 150 )) 5 $RUN_TIME } test2() { - run_stress 1 $(( $MEM - $THREAD_SPARE_MB)) 5 $RUN_TIME + run_stress 1 $MEM 5 $RUN_TIME } . cgroup_lib.sh diff --git a/testcases/kernel/crypto/pcrypt_aead01.c b/testcases/kernel/crypto/pcrypt_aead01.c index 5eefee4cb..3b4f5d8d1 100644 --- a/testcases/kernel/crypto/pcrypt_aead01.c +++ b/testcases/kernel/crypto/pcrypt_aead01.c @@ -7,7 +7,7 @@ * Originally found by syzkaller: * https://groups.google.com/forum/#!topic/syzkaller-bugs/NKn_ivoPOpk * - * Test for CVE-2017-5754 - pcrypt mishandles freeing instances. + * Test for CVE-2017-18075 - pcrypt mishandles freeing instances. * * The test works by adding and then removing pcrypt-AEAD instances. * See commit d76c68109f37 crypto: pcrypt - fix freeing pcrypt instances. @@ -78,7 +78,7 @@ static struct tst_test test = { .max_runtime = 300, .tags = (const struct tst_tag[]) { {"linux-git", "d76c68109f37"}, - {"CVE", "2017-5754"}, + {"CVE", "2017-18075"}, {} } }; diff --git a/testcases/kernel/device-drivers/nls/README b/testcases/kernel/device-drivers/nls/README index 67c1d8f0c..1de4ec442 100644 --- a/testcases/kernel/device-drivers/nls/README +++ b/testcases/kernel/device-drivers/nls/README @@ -11,7 +11,7 @@ Before loading nlsTest.ko the nls_base.ko module must already be loaded. Building -------- -To build nlsTest.ko you will need to have the the Linux kernel sources installed +To build nlsTest.ko you will need to have the Linux kernel sources installed on your build environment. Execute "make" from the current directory should build the nlsTest.ko. diff --git a/testcases/kernel/device-drivers/zram/zram01.sh b/testcases/kernel/device-drivers/zram/zram01.sh index 58d233f91..6bc305f2c 100755 --- a/testcases/kernel/device-drivers/zram/zram01.sh +++ b/testcases/kernel/device-drivers/zram/zram01.sh @@ -105,6 +105,26 @@ zram_mount() tst_res TPASS "mount of zram device(s) succeeded" } +read_mem_used_total() +{ + echo $(awk '{print $3}' $1) +} + +# Reads /sys/block/zram*/mm_stat until mem_used_total is not 0. +check_read_mem_used_total() +{ + local file="$1" + local mem_used_total + + tst_res TINFO "$file" + cat $file >&2 + + mem_used_total=$(read_mem_used_total $file) + [ "$mem_used_total" -eq 0 ] && return 1 + + return 0 +} + zram_fill_fs() { local mem_used_total @@ -133,9 +153,12 @@ zram_fill_fs() continue fi - mem_used_total=`awk '{print $3}' "/sys/block/zram$i/mm_stat"` + TST_RETRY_FUNC "check_read_mem_used_total /sys/block/zram$i/mm_stat" 0 + mem_used_total=$(read_mem_used_total /sys/block/zram$i/mm_stat) + tst_res TINFO "mem_used_total: $mem_used_total" + v=$((100 * 1024 * $b / $mem_used_total)) - r=`echo "scale=2; $v / 100 " | bc` + r=$(echo "scale=2; $v / 100 " | bc) if [ "$v" -lt 100 ]; then tst_res TFAIL "compression ratio: $r:1" diff --git a/testcases/kernel/fs/doio/write_log.c b/testcases/kernel/fs/doio/write_log.c index e8ef9c7cb..c06677fc6 100644 --- a/testcases/kernel/fs/doio/write_log.c +++ b/testcases/kernel/fs/doio/write_log.c @@ -87,7 +87,7 @@ /*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/ #endif -char Wlog_Error_String[256]; +char Wlog_Error_String[2048]; #if __STDC__ static int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag); @@ -129,7 +129,7 @@ int wlog_open(struct wlog_file *wfile, int trunc, int mode) umask(omask); if (wfile->w_afd == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not open write_log - open(%s, %#o, %#o) failed: %s\n", wfile->w_file, oflags, mode, strerror(errno)); return -1; @@ -141,7 +141,7 @@ int wlog_open(struct wlog_file *wfile, int trunc, int mode) oflags = O_RDWR; if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not open write log - open(%s, %#o) failed: %s\n", wfile->w_file, oflags, strerror(errno)); close(wfile->w_afd); @@ -218,14 +218,14 @@ int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, reclen += 2; if (write(wfile->w_afd, wbuf, reclen) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not write log - write(%s, %s, %d) failed: %s\n", wfile->w_file, wbuf, reclen, strerror(errno)); return -1; } else { offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen; if (offset == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n", wfile->w_file, strerror(errno)); return -1; @@ -233,13 +233,13 @@ int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, } } else { if ((lseek(wfile->w_rfd, offset, SEEK_SET)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, %ld, SEEK_SET) failed: %s\n", wfile->w_file, offset, strerror(errno)); return -1; } else { if ((write(wfile->w_rfd, wbuf, reclen)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not write log - write(%s, %s, %d) failed: %s\n", wfile->w_file, wbuf, reclen, strerror(errno)); @@ -274,14 +274,14 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, */ if ((lseek(fd, 0, SEEK_END)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_END) failed: %s\n", wfile->w_file, strerror(errno)); return -1; } offset = lseek(fd, 0, SEEK_CUR); if ((offset == -1)) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n", wfile->w_file, strerror(errno)); return -1; @@ -309,7 +309,7 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, * Move to the proper file offset, and read into buf */ if ((lseek(fd, offset, SEEK_SET)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, %d, SEEK_SET) failed: %s\n", wfile->w_file, offset, strerror(errno)); return -1; @@ -318,7 +318,7 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, nbytes = read(fd, bufstart, bufend - bufstart - leftover); if (nbytes == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not read history file at offset %d - read(%d, %p, %d) failed: %s\n", offset, fd, bufstart, (int)(bufend - bufstart - leftover), diff --git a/testcases/kernel/fs/fs_bind/fs_bind_lib.sh b/testcases/kernel/fs/fs_bind/fs_bind_lib.sh index 2dd9ef08f..52190a7ca 100644 --- a/testcases/kernel/fs/fs_bind/fs_bind_lib.sh +++ b/testcases/kernel/fs/fs_bind/fs_bind_lib.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2005 # Copyright (c) 2021 Joerg Vehlow <joerg.vehlow@aox-tech.de> +# Copyright (c) Linux Test Project, 2022-2023 # Based on work by: Avantika Mathur (mathurav@us.ibm.com) TST_NEEDS_TMPDIR=1 @@ -109,7 +110,7 @@ fs_bind_check() fi if [ $use_ns -eq 1 ]; then - output="$(ns_exec ${FS_BIND_MNTNS_PID} mnt diff -r "$PWD/$dir1" "$PWD/$dir2" 2> /dev/null)" + output="$(tst_ns_exec ${FS_BIND_MNTNS_PID} mnt diff -r "$PWD/$dir1" "$PWD/$dir2" 2> /dev/null)" else output="$(diff -r "$dir1" "$dir2" 2> /dev/null)" fi @@ -197,13 +198,13 @@ _fs_bind_setup_test() fs_bind_create_ns() { [ -n "$FS_BIND_MNTNS_PID" ] && tst_brk TBROK "Namespace exist already" - FS_BIND_MNTNS_PID=$(ns_create mnt) + FS_BIND_MNTNS_PID=$(tst_ns_create mnt) } fs_bind_exec_ns() { [ -z "$FS_BIND_MNTNS_PID" ] && tst_brk TBROK "Namespace does not exist" - EXPECT_PASS ns_exec $FS_BIND_MNTNS_PID mnt "$@" + EXPECT_PASS tst_ns_exec $FS_BIND_MNTNS_PID mnt "$@" } fs_bind_destroy_ns() diff --git a/testcases/kernel/fs/fs_fill/fs_fill.c b/testcases/kernel/fs/fs_fill/fs_fill.c index 2027b6df1..2ecd8e2ad 100644 --- a/testcases/kernel/fs/fs_fill/fs_fill.c +++ b/testcases/kernel/fs/fs_fill/fs_fill.c @@ -18,6 +18,7 @@ #include "tst_test.h" #define MNTPOINT "mntpoint" +#define THREADS_DIR MNTPOINT "/subdir" static volatile int run; static unsigned int nthreads; @@ -99,9 +100,15 @@ static void setup(void) nthreads = tst_ncpus_conf() + 2; workers = SAFE_MALLOC(sizeof(struct worker) * nthreads); + /* + * Avoid creating the thread directories in the root of the filesystem + * to not hit the root entries limit on a FAT16 filesystem. + */ + SAFE_MKDIR(THREADS_DIR, 0700); + for (i = 0; i < nthreads; i++) { snprintf(workers[i].dir, sizeof(workers[i].dir), - MNTPOINT "/thread%i", i + 1); + THREADS_DIR "/thread%i", i + 1); SAFE_MKDIR(workers[i].dir, 0700); } diff --git a/testcases/kernel/fs/fsstress/fsstress.c b/testcases/kernel/fs/fsstress/fsstress.c index 42ee696a5..272d87a1f 100644 --- a/testcases/kernel/fs/fsstress/fsstress.c +++ b/testcases/kernel/fs/fsstress/fsstress.c @@ -32,7 +32,8 @@ #include "config.h" #include "global.h" -#include <tst_common.h> +#include "tst_common.h" + #ifdef HAVE_SYS_PRCTL_H # include <sys/prctl.h> #endif diff --git a/testcases/kernel/fs/fsstress/global.h b/testcases/kernel/fs/fsstress/global.h index 4ec382426..e7d0cde47 100644 --- a/testcases/kernel/fs/fsstress/global.h +++ b/testcases/kernel/fs/fsstress/global.h @@ -33,7 +33,7 @@ #ifndef GLOBAL_H #define GLOBAL_H -/* xfs-specific includes */ +#define _GNU_SOURCE #if defined(NO_XFS) # include "xfscompat.h" @@ -42,8 +42,6 @@ # include <attr/attributes.h> #endif -/* libc includes */ - #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/time.h> @@ -58,9 +56,6 @@ #include <stdlib.h> #include <stdio.h> #include <unistd.h> - -#ifndef O_DIRECT -#define O_DIRECT 040000 -#endif +#include "lapi/fcntl.h" #endif diff --git a/testcases/kernel/fs/lftest/lftest.c b/testcases/kernel/fs/lftest/lftest.c index 7290fb0df..9e293d9e3 100644 --- a/testcases/kernel/fs/lftest/lftest.c +++ b/testcases/kernel/fs/lftest/lftest.c @@ -65,7 +65,7 @@ static void run(void) tst_res(TINFO, "total time for test to run: %d minute(s) and %d seconds", diff / 60, diff % 60); - tst_res(TPASS, "test successfull"); + tst_res(TPASS, "test successful"); } static struct tst_test test = { diff --git a/testcases/kernel/fs/read_all/Makefile b/testcases/kernel/fs/read_all/Makefile index 0e6dec2d3..fb73e8fbc 100644 --- a/testcases/kernel/fs/read_all/Makefile +++ b/testcases/kernel/fs/read_all/Makefile @@ -6,5 +6,6 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk CFLAGS += -D_GNU_SOURCE -pthread +read_all: LDLIBS+=-lrt include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c b/testcases/kernel/fs/scsi/ltpscsi/scsimain.c index ae484e0f1..ce23ae1e7 100644 --- a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c +++ b/testcases/kernel/fs/scsi/ltpscsi/scsimain.c @@ -28,6 +28,7 @@ [0x12][ |lu][pg cde][res ][al len][cntrl ] */ +#define _GNU_SOURCE #include <unistd.h> #include <fcntl.h> #include <stdio.h> @@ -53,10 +54,6 @@ #define ME "scsimain: " -#ifndef O_DIRECT -#define O_DIRECT 040000 -#endif - #define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ //static char * version_str = "0.21 20030513"; diff --git a/testcases/kernel/io/direct_io/diotest3.c b/testcases/kernel/io/direct_io/diotest3.c index 92f7afaad..ba2fd0473 100644 --- a/testcases/kernel/io/direct_io/diotest3.c +++ b/testcases/kernel/io/direct_io/diotest3.c @@ -292,6 +292,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-2: Write with Direct IO, Read without */ @@ -309,6 +310,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-3: Read, Write with Direct IO. */ diff --git a/testcases/kernel/io/direct_io/diotest4.c b/testcases/kernel/io/direct_io/diotest4.c index f3c9c19d7..45c677b5b 100644 --- a/testcases/kernel/io/direct_io/diotest4.c +++ b/testcases/kernel/io/direct_io/diotest4.c @@ -62,7 +62,6 @@ #include <sys/file.h> #include <fcntl.h> #include <sys/types.h> -#include <sys/mman.h> #include <sys/syscall.h> #include <errno.h> diff --git a/testcases/kernel/io/direct_io/diotest6.c b/testcases/kernel/io/direct_io/diotest6.c index 1905380f0..fb925ff0a 100644 --- a/testcases/kernel/io/direct_io/diotest6.c +++ b/testcases/kernel/io/direct_io/diotest6.c @@ -320,6 +320,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-2: Write with Direct IO, Read without */ @@ -337,6 +338,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-3: Read, Write with Direct IO. */ diff --git a/testcases/kernel/io/ltp-aiodio/aiocp.c b/testcases/kernel/io/ltp-aiodio/aiocp.c index bc0e209b2..6212d8ee8 100644 --- a/testcases/kernel/io/ltp-aiodio/aiocp.c +++ b/testcases/kernel/io/ltp-aiodio/aiocp.c @@ -297,8 +297,8 @@ static void run(void) return; } - srcfd = SAFE_OPEN(srcname, srcflags | O_RDONLY, 0666); - dstfd = SAFE_OPEN(dstname, srcflags | O_RDONLY, 0666); + srcfd = SAFE_OPEN(srcname, O_RDONLY, 0666); + dstfd = SAFE_OPEN(dstname, O_RDONLY, 0666); reads = howmany(filesize, buffsize); diff --git a/testcases/kernel/ipc/semaphore/.gitignore b/testcases/kernel/ipc/semaphore/.gitignore deleted file mode 100644 index 944e5ca1e..000000000 --- a/testcases/kernel/ipc/semaphore/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/sem01 -/sem02 diff --git a/testcases/kernel/ipc/semaphore/Makefile b/testcases/kernel/ipc/semaphore/Makefile deleted file mode 100644 index 9ab85745d..000000000 --- a/testcases/kernel/ipc/semaphore/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# testcases/kernel/ipc/semaphore Makefile. -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Ngie Cooper, July 2009 -# - -top_srcdir ?= ../../../.. - -include $(top_srcdir)/include/mk/testcases.mk - -CPPFLAGS += -I../include -LDLIBS += -lpthread - -include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/ipc/semaphore/sem01.c b/testcases/kernel/ipc/semaphore/sem01.c deleted file mode 100644 index 582624d60..000000000 --- a/testcases/kernel/ipc/semaphore/sem01.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * FILE : sem01.c - * DESCRIPTION : Creates a semaphore and two processes. The processes - * each go through a loop where they semdown, delay for a - * random amount of time, and semup, so they will almost - * always be fighting for control of the semaphore. - * HISTORY: - * 01/15/2001 Paul Larson (plars@us.ibm.com) - * -written - * 11/09/2001 Manoj Iyer (manjo@ausin.ibm.com) - * Modified. - * - Removed compiler warnings. - * added exit to the end of function main() - * - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/ipc.h> -#include "lapi/sem.h" - -int verbose = 0; -int loops = 100; -int errors = 0; - -int semup(int semid) -{ - struct sembuf semops; - semops.sem_num = 0; - semops.sem_op = 1; - semops.sem_flg = SEM_UNDO; - if (semop(semid, &semops, 1) == -1) { - perror("semup"); - errors++; - return 1; - } - return 0; -} - -int semdown(int semid) -{ - struct sembuf semops; - semops.sem_num = 0; - semops.sem_op = -1; - semops.sem_flg = SEM_UNDO; - if (semop(semid, &semops, 1) == -1) { - perror("semdown"); - errors++; - return 1; - } - return 0; -} - -void delayloop() -{ - int delay; - delay = 1 + ((100.0 * rand()) / RAND_MAX); - if (verbose) - printf("in delay function for %d microseconds\n", delay); - usleep(delay); -} - -void mainloop(int semid) -{ - int i; - for (i = 0; i < loops; i++) { - if (semdown(semid)) { - printf("semdown failed\n"); - } - if (verbose) - printf("sem is down\n"); - delayloop(); - if (semup(semid)) { - printf("semup failed\n"); - } - if (verbose) - printf("sem is up\n"); - } -} - -int main(int argc, char *argv[]) -{ - int semid, opt; - union semun semunion; - extern char *optarg; - pid_t pid; - int chstat; - - while ((opt = getopt(argc, argv, "l:vh")) != EOF) { - switch ((char)opt) { - case 'l': - loops = atoi(optarg); - break; - case 'v': - verbose = 1; - break; - case 'h': - default: - printf("Usage: -l loops [-v]\n"); - exit(1); - } - } - - /* set up the semaphore */ - if ((semid = semget((key_t) 9142, 1, 0666 | IPC_CREAT)) < 0) { - printf("error in semget()\n"); - exit(-1); - } - semunion.val = 1; - if (semctl(semid, 0, SETVAL, semunion) == -1) { - printf("error in semctl\n"); - } - - if ((pid = fork()) < 0) { - printf("fork error\n"); - exit(-1); - } - if (pid) { - /* parent */ - srand(pid); - mainloop(semid); - waitpid(pid, &chstat, 0); - if (!WIFEXITED(chstat)) { - printf("child exited with status\n"); - exit(-1); - } - if (semctl(semid, 0, IPC_RMID, semunion) == -1) { - printf("error in semctl\n"); - } - if (errors) { - printf("FAIL: there were %d errors\n", errors); - } else { - printf("PASS: error count is 0\n"); - } - exit(errors); - } else { - /* child */ - mainloop(semid); - } - exit(0); -} diff --git a/testcases/kernel/kvm/.gitignore b/testcases/kernel/kvm/.gitignore index 349260359..9638a6fc7 100644 --- a/testcases/kernel/kvm/.gitignore +++ b/testcases/kernel/kvm/.gitignore @@ -1 +1,4 @@ /kvm_pagefault01 +/kvm_svm01 +/kvm_svm02 +/kvm_svm03 diff --git a/testcases/kernel/kvm/Makefile b/testcases/kernel/kvm/Makefile index 6986844be..ce4a5ede2 100644 --- a/testcases/kernel/kvm/Makefile +++ b/testcases/kernel/kvm/Makefile @@ -8,8 +8,8 @@ include $(top_srcdir)/include/mk/testcases.mk ASFLAGS = CPPFLAGS += -I$(abs_srcdir)/include GUEST_CPPFLAGS = $(CPPFLAGS) -DCOMPILE_PAYLOAD -GUEST_CFLAGS = -ffreestanding -O2 -Wall -fno-asynchronous-unwind-tables -mno-mmx -mno-sse -GUEST_LDFLAGS = -nostdlib -Wl,--build-id=none -fno-stack-protector +GUEST_CFLAGS = -ffreestanding -O2 -Wall -fno-asynchronous-unwind-tables -fno-stack-protector -mno-mmx -mno-sse +GUEST_LDFLAGS = -nostdlib -Wl,--build-id=none -z noexecstack GUEST_LDLIBS = KVM_LD ?= $(LD) @@ -48,6 +48,9 @@ endif lib_guest.o $(ARCH_OBJ): CPPFLAGS := $(GUEST_CPPFLAGS) lib_guest.o $(ARCH_OBJ): CFLAGS := $(GUEST_CFLAGS) +kvm_svm03: CFLAGS += -pthread +kvm_svm03: LDLIBS += -pthread + include $(top_srcdir)/include/mk/generic_leaf_target.mk %-payload.o: %.c lib_guest.o $(ARCH_OBJ) diff --git a/testcases/kernel/kvm/bootstrap_x86.S b/testcases/kernel/kvm/bootstrap_x86.S index 5ec4c0b7e..a39c6bea7 100644 --- a/testcases/kernel/kvm/bootstrap_x86.S +++ b/testcases/kernel/kvm/bootstrap_x86.S @@ -7,6 +7,9 @@ .set KVM_TEXIT, 0xff .set RESULT_ADDRESS, 0xfffff000 +.set KVM_GDT_SIZE, 32 + +.set MSR_VM_HSAVE_PA, 0xc0010117 /* * This section will be allocated at address 0x1000 and @@ -31,7 +34,7 @@ protected_mode_entry: mov %eax, %es jmp init_memlayout -.section .data.gdt32, "a", @progbits +.section .init.gdt32, "a", @progbits .macro gdt32_entry type:req l=0 d=0 dpl=0 limit=0xfffff g=1 p=1 .4byte \limit & 0xffff @@ -44,7 +47,7 @@ kvm_gdt: .8byte 0 gdt32_entry type=0x1a l=0 d=1 /* Code segment protected_mode, 32bits */ gdt32_entry type=0x12 /* Data segment, writable */ - .skip 16 /* Stack and TSS segment descriptors */ + .skip (KVM_GDT_SIZE-3)*8 /* Stack, TSS and other segment descriptors */ .Lgdt_end: .global kvm_gdt_desc @@ -196,6 +199,25 @@ kvm_read_cregs: pop %edi ret +.global kvm_read_sregs +kvm_read_sregs: + push %edi + mov 8(%esp), %edi + mov %cs, %ax + movw %ax, (%edi) + mov %ds, %ax + movw %ax, 2(%edi) + mov %es, %ax + movw %ax, 4(%edi) + mov %fs, %ax + movw %ax, 6(%edi) + mov %gs, %ax + movw %ax, 8(%edi) + mov %ss, %ax + movw %ax, 10(%edi) + pop %edi + ret + handle_interrupt: /* save CPU state */ push %ebp @@ -331,6 +353,83 @@ kvm_yield: hlt ret +.global kvm_svm_guest_entry +kvm_svm_guest_entry: + call *%eax +1: hlt + jmp 1b + +.global kvm_svm_vmrun +kvm_svm_vmrun: + push %edi + mov 8(%esp), %edi + push %ebx + push %esi + push %ebp + + clgi + + /* Save full host state */ + movl $MSR_VM_HSAVE_PA, %ecx + rdmsr + vmsave + push %eax + + /* Load guest registers */ + push %edi + movl (%edi), %eax + /* %eax is loaded by vmrun from VMCB */ + movl 0x0c(%edi), %ebx + movl 0x14(%edi), %ecx + movl 0x1c(%edi), %edx + movl 0x2c(%edi), %esi + movl 0x34(%edi), %ebp + /* %esp is loaded by vmrun from VMCB */ + movl 0x24(%edi), %edi + + vmload + vmrun + vmsave + + /* Clear guest register buffer */ + push %edi + push %ecx + movl 8(%esp), %edi + addl $4, %edi + xorl %eax, %eax + mov $32, %ecx + pushfl + cld + rep stosl + popfl + + /* Save guest registers */ + pop %ecx + pop %eax + pop %edi + movl %ebx, 0x0c(%edi) + movl %ecx, 0x14(%edi) + movl %edx, 0x1c(%edi) + movl %eax, 0x24(%edi) + movl %esi, 0x2c(%edi) + movl %ebp, 0x34(%edi) + /* Copy %eax and %esp from VMCB */ + movl (%edi), %esi + movl 0x5f8(%esi), %eax + movl %eax, 0x04(%edi) + movl 0x5d8(%esi), %eax + movl %eax, 0x3c(%edi) + + pop %eax + vmload + stgi + + pop %ebp + pop %esi + pop %ebx + pop %edi + ret + .section .bss.pgtables, "aw", @nobits .global kvm_pagetable diff --git a/testcases/kernel/kvm/bootstrap_x86_64.S b/testcases/kernel/kvm/bootstrap_x86_64.S index 9ddbd17ed..b02dd4d92 100644 --- a/testcases/kernel/kvm/bootstrap_x86_64.S +++ b/testcases/kernel/kvm/bootstrap_x86_64.S @@ -8,6 +8,9 @@ .set KVM_TCONF, 32 .set KVM_TEXIT, 0xff .set RESULT_ADDRESS, 0xfffff000 +.set KVM_GDT_SIZE, 32 + +.set MSR_VM_HSAVE_PA, 0xc0010117 /* * This section will be allocated at address 0x1000 and @@ -32,7 +35,7 @@ protected_mode_entry: mov %eax, %es jmp init_memlayout -.section .data.gdt32, "a", @progbits +.section .init.gdt32, "a", @progbits .macro gdt32_entry type:req l=0 d=0 dpl=0 limit=0xfffff g=1 p=1 .4byte \limit & 0xffff @@ -302,6 +305,22 @@ kvm_read_cregs: mov %rax, 24(%rdi) retq +.global kvm_read_sregs +kvm_read_sregs: + mov %cs, %ax + movw %ax, (%rdi) + mov %ds, %ax + movw %ax, 2(%rdi) + mov %es, %ax + movw %ax, 4(%rdi) + mov %fs, %ax + movw %ax, 6(%rdi) + mov %gs, %ax + movw %ax, 8(%rdi) + mov %ss, %ax + movw %ax, 10(%rdi) + retq + handle_interrupt: /* push CPU state */ push %rbp @@ -457,6 +476,93 @@ kvm_yield: hlt ret +.global kvm_svm_guest_entry +kvm_svm_guest_entry: + call *%rax +1: hlt + jmp 1b + +.global kvm_svm_vmrun +kvm_svm_vmrun: + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + clgi + + /* Save full host state */ + movq $MSR_VM_HSAVE_PA, %rcx + rdmsr + shlq $32, %rdx + orq %rdx, %rax + vmsave + pushq %rax + + /* Load guest registers */ + pushq %rdi + movq (%rdi), %rax + /* %rax is loaded by vmrun from VMCB */ + movq 0x10(%rdi), %rbx + movq 0x18(%rdi), %rcx + movq 0x20(%rdi), %rdx + movq 0x30(%rdi), %rsi + movq 0x38(%rdi), %rbp + /* %rsp is loaded by vmrun from VMCB */ + movq 0x48(%rdi), %r8 + movq 0x50(%rdi), %r9 + movq 0x58(%rdi), %r10 + movq 0x60(%rdi), %r11 + movq 0x68(%rdi), %r12 + movq 0x70(%rdi), %r13 + movq 0x78(%rdi), %r14 + movq 0x80(%rdi), %r15 + movq 0x28(%rdi), %rdi + + vmload + vmrun + vmsave + + /* Save guest registers */ + movq %rdi, %rax + popq %rdi + movq %rbx, 0x10(%rdi) + movq %rcx, 0x18(%rdi) + movq %rdx, 0x20(%rdi) + /* %rax contains guest %rdi */ + movq %rax, 0x28(%rdi) + movq %rsi, 0x30(%rdi) + movq %rbp, 0x38(%rdi) + movq %r8, 0x48(%rdi) + movq %r9, 0x50(%rdi) + movq %r10, 0x58(%rdi) + movq %r11, 0x60(%rdi) + movq %r12, 0x68(%rdi) + movq %r13, 0x70(%rdi) + movq %r14, 0x78(%rdi) + movq %r15, 0x80(%rdi) + /* copy guest %rax and %rsp from VMCB*/ + movq (%rdi), %rsi + movq 0x5f8(%rsi), %rax + movq %rax, 0x08(%rdi) + movq 0x5d8(%rsi), %rax + movq %rax, 0x40(%rdi) + + /* Reload host state */ + popq %rax + vmload + + stgi + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + retq .section .bss.pgtables, "aw", @nobits .global kvm_pagetable @@ -478,7 +584,7 @@ kvm_pgtable_l4: kvm_gdt: .8byte 0 gdt32_entry type=0x1a l=1 limit=0 g=0 /* Code segment long mode */ - .skip 16 /* TSS segment descriptor */ + .skip (KVM_GDT_SIZE-2)*8 /* TSS and other segment descriptors */ .Lgdt_end: .global kvm_gdt_desc diff --git a/testcases/kernel/kvm/include/kvm_common.h b/testcases/kernel/kvm/include/kvm_common.h index 4e81d8302..377e3f6aa 100644 --- a/testcases/kernel/kvm/include/kvm_common.h +++ b/testcases/kernel/kvm/include/kvm_common.h @@ -11,6 +11,14 @@ #define KVM_TNONE -1 /* "No result" status value */ /* + * Result value for asynchronous notifications between guest and host. + * Do not use this value directly. Call tst_signal_host() or tst_wait_host() + * in guest code. The notification must be handled by another host thread + * and then the result value must be reset to KVM_TNONE. + */ +#define KVM_TSYNC 0xfe + +/* * Result value indicating end of test. If the test program exits using * the HLT instruction with any valid result value other than KVM_TEXIT or * TBROK, KVM runner will automatically resume VM execution after printing diff --git a/testcases/kernel/kvm/include/kvm_guest.h b/testcases/kernel/kvm/include/kvm_guest.h index ec13c5845..96f246155 100644 --- a/testcases/kernel/kvm/include/kvm_guest.h +++ b/testcases/kernel/kvm/include/kvm_guest.h @@ -64,6 +64,20 @@ void tst_brk_(const char *file, const int lineno, int result, const char *message) __attribute__((noreturn)); #define tst_brk(result, msg) tst_brk_(__FILE__, __LINE__, (result), (msg)) +/* + * Send asynchronous notification to host without stopping VM execution and + * return immediately. The notification must be handled by another host thread. + * The data argument will be passed to host in test_result->file_addr and + * can be used to send additional data both ways. + */ +void tst_signal_host(void *data); + +/* + * Call tst_signal_host(data) and wait for host to call + * tst_kvm_clear_guest_signal(). + */ +void tst_wait_host(void *data); + void *tst_heap_alloc_aligned(size_t size, size_t align); void *tst_heap_alloc(size_t size); diff --git a/testcases/kernel/kvm/include/kvm_host.h b/testcases/kernel/kvm/include/kvm_host.h index 2359944fd..06bcb5d45 100644 --- a/testcases/kernel/kvm/include/kvm_host.h +++ b/testcases/kernel/kvm/include/kvm_host.h @@ -125,13 +125,29 @@ struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd); void tst_kvm_create_instance(struct tst_kvm_instance *inst, size_t ram_size); /* - * Execute the given KVM instance and print results. + * Execute the given KVM instance and print results. If ioctl(KVM_RUN) is + * expected to fail, pass the expected error code in exp_errno, otherwise + * set it to zero. Returns last value returned by ioctl(KVM_RUN). */ -void tst_kvm_run_instance(struct tst_kvm_instance *inst); +int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno); /* * Close the given KVM instance. */ void tst_kvm_destroy_instance(struct tst_kvm_instance *inst); +/* + * Wait for given VM to call tst_signal_host() or tst_wait_host(). Timeout + * value is in milliseconds. Zero means no wait, negative value means wait + * forever. Returns 0 if signal was received, KVM_TEXIT if the VM exited + * without sending a signal, or -1 if timeout was reached. + */ +int tst_kvm_wait_guest(struct tst_kvm_instance *inst, int timeout_ms); + +/* + * Clear VM signal sent by tst_signal_host(). If the VM is waiting + * in tst_wait_host(), this function will signal the VM to resume execution. + */ +void tst_kvm_clear_guest_signal(struct tst_kvm_instance *inst); + #endif /* KVM_HOST_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_x86.h b/testcases/kernel/kvm/include/kvm_x86.h index 4f3671135..bc36c0e0f 100644 --- a/testcases/kernel/kvm/include/kvm_x86.h +++ b/testcases/kernel/kvm/include/kvm_x86.h @@ -10,6 +10,9 @@ #include "kvm_test.h" +#define PAGESIZE 0x1000 +#define KVM_GDT_SIZE 32 + /* Interrupts */ #define X86_INTR_COUNT 256 @@ -38,19 +41,48 @@ #define INTR_SECURITY_ERROR 30 +/* Segment descriptor flags */ +#define SEGTYPE_LDT 0x02 +#define SEGTYPE_TSS 0x09 +#define SEGTYPE_TSS_BUSY 0x0b +#define SEGTYPE_CALL_GATE 0x0c +#define SEGTYPE_INTR_GATE 0x0e +#define SEGTYPE_TRAP_GATE 0x0f +#define SEGTYPE_RODATA 0x10 +#define SEGTYPE_RWDATA 0x12 +#define SEGTYPE_STACK 0x16 +#define SEGTYPE_CODE 0x1a +#define SEGTYPE_MASK 0x1f + +#define SEGFLAG_NSYSTEM 0x10 +#define SEGFLAG_PRESENT 0x80 +#define SEGFLAG_CODE64 0x200 +#define SEGFLAG_32BIT 0x400 +#define SEGFLAG_PAGE_LIMIT 0x800 + + /* CPUID constants */ #define CPUID_GET_INPUT_RANGE 0x80000000 #define CPUID_GET_EXT_FEATURES 0x80000001 +#define CPUID_GET_SVM_FEATURES 0x8000000a /* Model-specific CPU register constants */ #define MSR_EFER 0xc0000080 +#define MSR_VM_CR 0xc0010114 +#define MSR_VM_HSAVE_PA 0xc0010117 #define EFER_SCE (1 << 0) /* SYSCALL/SYSRET instructions enabled */ #define EFER_LME (1 << 8) /* CPU is running in 64bit mode */ #define EFER_LMA (1 << 10) /* CPU uses 64bit memory paging (read-only) */ #define EFER_NXE (1 << 11) /* Execute disable bit active */ +#define EFER_SVME (1 << 12) /* AMD SVM instructions enabled */ +#define VM_CR_DPD (1 << 0) +#define VM_CR_R_INIT (1 << 1) +#define VM_CR_DIS_A20M (1 << 2) +#define VM_CR_LOCK (1 << 3) +#define VM_CR_SVMDIS (1 << 4) /* Control register constants */ #define CR4_VME (1 << 0) @@ -91,6 +123,25 @@ struct intr_descriptor { #endif /* defined(__x86_64__) */ } __attribute__((__packed__)); +struct segment_descriptor { + unsigned int limit_lo : 16; + unsigned int baseaddr_lo : 24; + unsigned int flags_lo : 8; + unsigned int limit_hi : 4; + unsigned int flags_hi : 4; + unsigned int baseaddr_hi : 8; +} __attribute__((__packed__)); + +struct segment_descriptor64 { + unsigned int limit_lo : 16; + unsigned int baseaddr_lo : 24; + unsigned int flags_lo : 8; + unsigned int limit_hi : 4; + unsigned int flags_hi : 4; + uint64_t baseaddr_hi : 40; + uint32_t reserved; +} __attribute__((__packed__)); + struct page_table_entry_pae { unsigned int present: 1; unsigned int writable: 1; @@ -116,15 +167,36 @@ struct kvm_cregs { unsigned long cr0, cr2, cr3, cr4; }; +struct kvm_sregs { + uint16_t cs, ds, es, fs, gs, ss; +}; + +struct kvm_regs64 { + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; +}; + extern struct page_table_entry_pae kvm_pagetable[]; extern struct intr_descriptor kvm_idt[X86_INTR_COUNT]; +extern struct segment_descriptor kvm_gdt[KVM_GDT_SIZE]; /* Page table helper functions */ uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry); +/* Segment descriptor table functions */ +void kvm_set_segment_descriptor(struct segment_descriptor *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags); +void kvm_parse_segment_descriptor(struct segment_descriptor *src, + uint64_t *baseaddr, uint32_t *limit, unsigned int *flags); +int kvm_find_free_descriptor(const struct segment_descriptor *table, + size_t size); +unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, + size_t tabsize, void *stack_base); + /* Functions for querying CPU info and status */ void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf); void kvm_read_cregs(struct kvm_cregs *buf); +void kvm_read_sregs(struct kvm_sregs *buf); uint64_t kvm_rdmsr(unsigned int msr); void kvm_wrmsr(unsigned int msr, uint64_t value); diff --git a/testcases/kernel/kvm/include/kvm_x86_svm.h b/testcases/kernel/kvm/include/kvm_x86_svm.h new file mode 100644 index 000000000..b4b1b80e2 --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_x86_svm.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC <mdoucha@suse.cz> + * + * x86-specific KVM helper functions and structures for AMD SVM + */ + +#ifndef KVM_X86_SVM_H_ +#define KVM_X86_SVM_H_ + +#include "kvm_x86.h" + +/* CPUID_GET_SVM_FEATURES flags returned in EDX */ +#define SVM_CPUID_NESTED_PAGING (1 << 0) +#define SVM_CPUID_LBR_VIRT (1 << 1) +#define SVM_CPUID_LOCK (1 << 2) +#define SVM_CPUID_NRIP_SAVE (1 << 3) +#define SVM_CPUID_TSC_RATE_MSR (1 << 4) +#define SVM_CPUID_VMCB_CLEAN (1 << 5) +#define SVM_CPUID_FLUSH_ASID (1 << 6) +#define SVM_CPUID_DECODE_ASSIST (1 << 7) +#define SVM_CPUID_PAUSE_FILTER (1 << 10) +#define SVM_CPUID_PAUSE_THRESHOLD (1 << 12) +#define SVM_CPUID_AVIC (1 << 13) +#define SVM_CPUID_VMSAVE_VIRT (1 << 15) +#define SVM_CPUID_VGIF (1 << 16) +#define SVM_CPUID_GMET (1 << 17) +#define SVM_CPUID_X2AVIC (1 << 18) +#define SVM_CPUID_SSSCHECK (1 << 19) +#define SVM_CPUID_SPEC_CTRL (1 << 20) +#define SVM_CPUID_ROGPT (1 << 21) +#define SVM_CPUID_HOST_MCE_OVERRIDE (1 << 23) +#define SVM_CPUID_TLBI_CTL (1 << 24) +#define SVM_CPUID_NMI_VIRT (1 << 25) +#define SVM_CPUID_IBS_VIRT (1 << 26) + +/* SVM event intercept IDs */ +#define SVM_INTERCEPT_HLT 0x78 +#define SVM_INTERCEPT_VMRUN 0x80 +#define SVM_INTERCEPT_VMLOAD 0x82 +#define SVM_INTERCEPT_VMSAVE 0x83 +#define SVM_INTERCEPT_STGI 0x84 +#define SVM_INTERCEPT_CLGI 0x85 +#define SVM_INTERCEPT_MAX 0x95 + +/* SVM vmrun exit codes */ +#define SVM_EXIT_HLT 0x78 +#define SVM_EXIT_VMRUN 0x80 +#define SVM_EXIT_VMLOAD 0x82 +#define SVM_EXIT_VMSAVE 0x83 +#define SVM_EXIT_STGI 0x84 +#define SVM_EXIT_CLGI 0x85 +#define SVM_EXIT_AVIC_NOACCEL 0x402 +#define SVM_EXIT_INVALID ((uint64_t)-1) + +/* SVM VMCB flags */ +#define SVM_INTR_AVIC (1 << 7) + +struct kvm_vmcb_descriptor { + uint16_t selector; + uint16_t attrib; + uint32_t limit; + uint64_t base; +}; + +struct kvm_vmcb { + /* VMCB control area */ + uint8_t intercepts[20]; + uint8_t reserved1[44]; + uint64_t iopm_base_addr; + uint64_t msrpm_base_addr; + uint64_t tsc_offset; + uint32_t guest_asid; + uint32_t tlb_control; + uint8_t virtual_tpr; + uint8_t virtual_irq; + unsigned char virt_intr_prio: 4; + unsigned char virt_ignore_tpr: 4; + uint8_t virt_intr_ctl; + uint8_t virt_intr_vector; + uint8_t reserved2[3]; + uint64_t interrupt_shadow; + uint64_t exitcode; + uint64_t exitinfo1; + uint64_t exitinfo2; + uint64_t exit_int_info; + uint64_t enable_nested_paging; + uint64_t avic_bar; + uint64_t ghcb_gpa; + uint64_t event_injection; + uint64_t nested_cr3; + uint64_t virt_ext; + uint32_t vmcb_clean; + uint8_t reserved3[4]; + uint64_t next_rip; + uint8_t instr_len; + uint8_t instr_bytes[15]; + uint64_t avic_backing_page; + uint8_t reserved4[8]; + uint64_t avic_logical_ptr; + uint64_t avic_physical_ptr; + uint8_t reserved5[8]; + uint64_t vmsa_pa; + uint64_t vmgexit_rax; + uint8_t vmgexit_cpl; + uint8_t reserved6[0x2e7]; + + /* VMCB state save area */ + struct kvm_vmcb_descriptor es, cs, ss, ds, fs, gs; + struct kvm_vmcb_descriptor gdtr, ldtr, idtr, tr; + uint8_t reserved7[43]; + uint8_t cpl; + uint8_t reserved8[4]; + uint64_t efer; + uint8_t reserved9[112]; + uint64_t cr4; + uint64_t cr3; + uint64_t cr0; + uint64_t dr7; + uint64_t dr6; + uint64_t rflags; + uint64_t rip; + uint8_t reserved10[88]; + uint64_t rsp; + uint64_t s_cet; + uint64_t ssp; + uint64_t isst_addr; + uint64_t rax; + uint64_t star; + uint64_t lstar; + uint64_t cstar; + uint64_t sfmask; + uint64_t kernel_gs_base; + uint64_t sysenter_cs; + uint64_t sysenter_esp; + uint64_t sysenter_eip; + uint64_t cr2; + uint8_t reserved11[32]; + uint64_t guest_pat; + uint8_t padding[0x990]; +}; + +struct kvm_svm_vcpu { + struct kvm_vmcb *vmcb; + struct kvm_regs64 regs; +}; + +/* AMD SVM virtualization helper functions */ +int kvm_is_svm_supported(void); +int kvm_get_svm_state(void); +void kvm_set_svm_state(int enabled); + +void kvm_init_svm(void); /* Fully initialize host SVM environment */ +struct kvm_vmcb *kvm_alloc_vmcb(void); +void kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor *dst, + unsigned int gdt_id); +void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, + unsigned int state); +void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, + void *rsp, int (*guest_main)(void)); +struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), + int alloc_stack); + +void kvm_svm_vmrun(struct kvm_svm_vcpu *cpu); + +#endif /* KVM_X86_SVM_H_ */ diff --git a/testcases/kernel/kvm/kvm_svm01.c b/testcases/kernel/kvm/kvm_svm01.c new file mode 100644 index 000000000..32d15526b --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm01.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange <nstange@suse.de> + * LTP port: Martin Doucha <mdoucha@suse.cz> + */ + +/*\ + * CVE 2021-3653 + * + * Check that KVM either blocks enabling virtual interrupt controller (AVIC) + * in nested VMs or correctly sets up the required memory address translation. + * If AVIC is enabled without address translation in the host kernel, + * the nested VM will be able to read and write an arbitraty physical memory + * page specified by the parent VM. Unauthorized memory access fixed in: + * + * commit 0f923e07124df069ba68d8bb12324398f4b6b709 + * Author: Maxim Levitsky <mlevitsk@redhat.com> + * Date: Thu Jul 15 01:56:24 2021 +0300 + * + * KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653) + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +#define AVIC_REG_ADDR 0x280 +#define AVIC_TEST_VAL 0xec +#define AVIC_READ_FAIL 0x12ead + +#define AVIC_INFO_MASK ((1ULL << 32) | 0xff0) +#define AVIC_INFO_EXP ((1ULL << 32) | AVIC_REG_ADDR) + +static uint32_t * const avic_ptr = (uint32_t *)AVIC_REG_ADDR; + +static int guest_main(void) +{ + if (*avic_ptr != 0xaaaaaaaa) + return AVIC_READ_FAIL; + + *avic_ptr = AVIC_TEST_VAL; + return 0; +} + +void main(void) +{ + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_main, 1); + + /* + * Enable AVIC and set both the AVIC base address (where the nested VM + * will write) and backing page address (where the parent VM expects + * to see the changes) to 0 + */ + vcpu->vmcb->virt_intr_ctl |= SVM_INTR_AVIC; + vcpu->vmcb->avic_backing_page = 0; + vcpu->vmcb->avic_bar = 0; + memset((void *)8, 0xaa, PAGESIZE - 8); + + /* Write into AVIC backing page in the nested VM */ + kvm_svm_vmrun(vcpu); + + switch (vcpu->vmcb->exitcode) { + case SVM_EXIT_HLT: + if (vcpu->vmcb->rax == AVIC_READ_FAIL) { + tst_res(TFAIL, "Nested VM can read host memory"); + return; + } + + if (vcpu->vmcb->rax) + tst_brk(TBROK, "Unexpected guest_main() return value"); + + break; + + case SVM_EXIT_AVIC_NOACCEL: + if ((vcpu->vmcb->exitinfo1 & AVIC_INFO_MASK) == AVIC_INFO_EXP) { + tst_res(TPASS, "AVIC register write caused VMEXIT"); + break; + } + + /* unexpected exit, fall through */ + + default: + tst_brk(TBROK, "Nested VM exited unexpectedly"); + } + + if (*avic_ptr != AVIC_TEST_VAL) { + tst_res(TFAIL, "Write into AVIC ESR redirected to host memory"); + return; + } + + tst_res(TPASS, "Writes into AVIC backing page were not redirected"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "0f923e07124d"}, + {"CVE", "2021-3653"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/kvm_svm02.c b/testcases/kernel/kvm/kvm_svm02.c new file mode 100644 index 000000000..5d2e2ce37 --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm02.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange <nstange@suse.de> + * LTP port: Martin Doucha <mdoucha@suse.cz> + */ + +/*\ + * CVE 2021-3656 + * + * Check that KVM correctly intercepts VMSAVE and VMLOAD instructions + * in a nested virtual machine even when the parent guest disables + * intercepting either instruction. If KVM does not override the disabled + * intercepts, it'll give the nested VM read/write access to a few bytes + * of an arbitrary physical memory page. Unauthorized memory access fixed in: + * + * commit c7dfa4009965a9b2d7b329ee970eb8da0d32f0bc + * Author: Maxim Levitsky <mlevitsk@redhat.com> + * Date: Mon Jul 19 16:05:00 2021 +0300 + * + * KVM: nSVM: always intercept VMLOAD/VMSAVE when nested (CVE-2021-3656) + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +static void *vmsave_buf; + +/* Load FS, GS, TR and LDTR state from vmsave_buf */ +static int guest_vmload(void) +{ + asm ( + "vmload %0\n" + : + : "a" (vmsave_buf) + ); + return 0; +} + +/* Save current FS, GS, TR and LDTR state to vmsave_buf */ +static int guest_vmsave(void) +{ + asm ( + "vmsave %0\n" + : + : "a" (vmsave_buf) + ); + return 0; +} + +static int cmp_descriptor(const struct kvm_vmcb_descriptor *a, + const struct kvm_vmcb_descriptor *b) +{ + int ret; + + ret = a->selector != b->selector; + ret = ret || a->attrib != b->attrib; + ret = ret || a->limit != b->limit; + ret = ret || a->base != b->base; + return ret; +} + +/* Return non-zero if the VMCB fields touched by vmsave/vmload differ */ +static int cmp_vmcb(const struct kvm_vmcb *a, const struct kvm_vmcb *b) +{ + int ret; + + ret = cmp_descriptor(&a->fs, &b->fs); + ret = ret || cmp_descriptor(&a->gs, &b->gs); + ret = ret || cmp_descriptor(&a->tr, &b->tr); + ret = ret || cmp_descriptor(&a->ldtr, &b->ldtr); + ret = ret || a->kernel_gs_base != b->kernel_gs_base; + ret = ret || a->star != b->star; + ret = ret || a->lstar != b->lstar; + ret = ret || a->cstar != b->cstar; + ret = ret || a->sfmask != b->sfmask; + ret = ret || a->sysenter_cs != b->sysenter_cs; + ret = ret || a->sysenter_esp != b->sysenter_esp; + ret = ret || a->sysenter_eip != b->sysenter_eip; + return ret; +} + +void main(void) +{ + uint16_t ss; + uint64_t rsp; + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_vmload, 1); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMLOAD, 0); + vmsave_buf = kvm_alloc_vmcb(); + + /* Save allocated stack for later VM reinit */ + ss = vcpu->vmcb->ss.selector; + rsp = vcpu->vmcb->rsp; + + /* Load partial state from vmsave_buf and save it to vcpu->vmcb */ + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); + + if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) { + tst_res(TFAIL, "Nested VM can read host memory"); + return; + } + + /* Load state from vcpu->vmcb and save it to vmsave_buf */ + memset(vmsave_buf, 0xaa, sizeof(struct kvm_vmcb)); + kvm_init_guest_vmcb(vcpu->vmcb, 1, ss, (void *)rsp, guest_vmsave); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMSAVE, 0); + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); + + if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) { + tst_res(TFAIL, "Nested VM can overwrite host memory"); + return; + } + + tst_res(TPASS, "VMLOAD and VMSAVE were intercepted by kernel"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "c7dfa4009965"}, + {"CVE", "2021-3656"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/kvm_svm03.c b/testcases/kernel/kvm/kvm_svm03.c new file mode 100644 index 000000000..87164d013 --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm03.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange <nstange@suse.de> + * LTP port: Martin Doucha <mdoucha@suse.cz> + */ + +/*\ + * Check that KVM correctly intercepts the CLGI instruction in a nested + * virtual machine even when the parent guest disables intercept. + * If KVM does not override the disabled intercept, it'll allow the nested VM + * to hold the physical CPU indefinitely and potentially perform a denial + * of service attack against the host kernel. CPU lockup fixed in: + * + * commit 91b7130cb6606d8c6b3b77e54426b3f3a83f48b1 + * Author: Paolo Bonzini <pbonzini@redhat.com> + * Date: Fri May 22 12:28:52 2020 -0400 + * + * KVM: SVM: preserve VGIF across VMCB switch + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +/* Disable global interrupts */ +static int guest_clgi(void) +{ + int ret, *result = (int *)KVM_RESULT_BASEADDR; + + /* + * Make sure that result page is present in memory. CLGI may disable + * page fault handling on the current CPU. The actual value + * at that address is irrelevant. + */ + ret = *result; + + /* Disable global interrupts */ + asm ("clgi"); + + /* Signal host to kill the VM and wait */ + tst_wait_host(NULL); + return ret; +} + +void main(void) +{ + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_clgi, 1); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_CLGI, 0); + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +#include <pthread.h> +#include "tst_safe_pthread.h" +#include "tst_safe_clocks.h" + +static struct tst_kvm_instance test_vm = { .vm_fd = -1 }; +static pthread_mutex_t mutex; +static int mutex_init; + +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) +{ + +} + +static void *vm_thread(void *arg) +{ + SAFE_PTHREAD_MUTEX_LOCK(&mutex); + tst_kvm_run_instance(&test_vm, EINTR); + SAFE_PTHREAD_MUTEX_UNLOCK(&mutex); + return arg; +} + +static void setup(void) +{ + struct sigaction sa = { .sa_handler = sighandler }; + pthread_mutexattr_t attr; + + SAFE_PTHREAD_MUTEXATTR_INIT(&attr); + SAFE_PTHREAD_MUTEXATTR_SETTYPE(&attr, PTHREAD_MUTEX_NORMAL); + SAFE_PTHREAD_MUTEX_INIT(&mutex, &attr); + mutex_init = 1; + SAFE_PTHREAD_MUTEXATTR_DESTROY(&attr); + SAFE_SIGACTION(SIGUSR1, &sa, NULL); +} + +static void run(void) +{ + struct timespec timeout; + pthread_t tid; + int ret; + + tst_kvm_create_instance(&test_vm, DEFAULT_RAM_SIZE); + + SAFE_PTHREAD_CREATE(&tid, NULL, vm_thread, NULL); + ret = tst_kvm_wait_guest(&test_vm, 2000); + + if (ret == KVM_TEXIT) { + SAFE_PTHREAD_JOIN(tid, NULL); + tst_brk(TCONF, "Guest exited early"); + } + + if (ret) + tst_brk(TBROK, "Wait for guest initialization timed out"); + + SAFE_PTHREAD_KILL(tid, SIGUSR1); + SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 2; + + if (SAFE_PTHREAD_MUTEX_TIMEDLOCK(&mutex, &timeout)) { + tst_kvm_clear_guest_signal(&test_vm); + tst_res(TFAIL, "VM thread does not respond to signals"); + } else { + SAFE_PTHREAD_MUTEX_UNLOCK(&mutex); + tst_res(TPASS, "VM thread was interrupted by signal"); + } + + SAFE_PTHREAD_JOIN(tid, NULL); + tst_kvm_destroy_instance(&test_vm); + tst_free_all(); +} + +static void cleanup(void) +{ + /* + * If the mutex is locked, the VM is likely still running, cannot + * clean up anything + */ + if (!mutex_init || SAFE_PTHREAD_MUTEX_TRYLOCK(&mutex)) + return; + + if (!SAFE_PTHREAD_MUTEX_UNLOCK(&mutex)) + SAFE_PTHREAD_MUTEX_DESTROY(&mutex); + + tst_kvm_destroy_instance(&test_vm); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_cpus = 2, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "91b7130cb660"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/lib_guest.c b/testcases/kernel/kvm/lib_guest.c index d237293fc..f3e21d3d6 100644 --- a/testcases/kernel/kvm/lib_guest.c +++ b/testcases/kernel/kvm/lib_guest.c @@ -82,7 +82,7 @@ char *ptr2hex(char *dest, uintptr_t val) uintptr_t tmp; char *ret = dest; - for (i = 4; val >> i; i += 4) + for (i = 4, tmp = val >> 4; tmp; i += 4, tmp >>= 4) ; do { @@ -155,6 +155,22 @@ void tst_brk_(const char *file, const int lineno, int result, kvm_exit(); } +void tst_signal_host(void *data) +{ + test_result->file_addr = (uintptr_t)data; + test_result->result = KVM_TSYNC; +} + +void tst_wait_host(void *data) +{ + volatile int32_t *vres = &test_result->result; + + tst_signal_host(data); + + while (*vres != KVM_TNONE) + ; +} + void tst_handle_interrupt(struct kvm_interrupt_frame *ifrm, long vector, unsigned long errcode) { diff --git a/testcases/kernel/kvm/lib_host.c b/testcases/kernel/kvm/lib_host.c index 2782e68b0..8e3d6094e 100644 --- a/testcases/kernel/kvm/lib_host.c +++ b/testcases/kernel/kvm/lib_host.c @@ -10,6 +10,8 @@ #define TST_NO_DEFAULT_MAIN #include "tst_test.h" +#include "tst_clocks.h" +#include "tst_timer.h" #include "kvm_host.h" static struct tst_kvm_instance test_vm = { .vm_fd = -1 }; @@ -234,14 +236,28 @@ void tst_kvm_create_instance(struct tst_kvm_instance *inst, size_t ram_size) inst->result->message[0] = '\0'; } -void tst_kvm_run_instance(struct tst_kvm_instance *inst) +int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno) { struct kvm_regs regs; + int ret; while (1) { inst->result->result = KVM_TNONE; inst->result->message[0] = '\0'; - SAFE_IOCTL(inst->vcpu_fd, KVM_RUN, 0); + errno = 0; + ret = ioctl(inst->vcpu_fd, KVM_RUN, 0); + + if (ret == -1) { + if (errno == exp_errno) + return ret; + + tst_brk(TBROK | TERRNO, "ioctl(KVM_RUN) failed"); + } + + if (ret < 0) { + tst_brk(TBROK | TERRNO, + "Invalid ioctl(KVM_RUN) return value %d", ret); + } if (inst->vcpu_info->exit_reason != KVM_EXIT_HLT) { SAFE_IOCTL(inst->vcpu_fd, KVM_GET_REGS, ®s); @@ -255,6 +271,8 @@ void tst_kvm_run_instance(struct tst_kvm_instance *inst) tst_kvm_print_result(inst); } + + return ret; } void tst_kvm_destroy_instance(struct tst_kvm_instance *inst) @@ -272,6 +290,37 @@ void tst_kvm_destroy_instance(struct tst_kvm_instance *inst) memset(inst->ram, 0, sizeof(inst->ram)); } +int tst_kvm_wait_guest(struct tst_kvm_instance *inst, int timeout_ms) +{ + volatile struct tst_kvm_result *result = inst->result; + int32_t res; + struct timespec start, now; + + if (timeout_ms >= 0) + tst_clock_gettime(CLOCK_MONOTONIC, &start); + + while ((res = result->result) != KVM_TSYNC) { + if (res == KVM_TEXIT) + return res; + + if (timeout_ms >= 0) { + tst_clock_gettime(CLOCK_MONOTONIC, &now); + + if (tst_timespec_diff_ms(now, start) >= timeout_ms) + return -1; + } + + usleep(1000); + } + + return 0; +} + +void tst_kvm_clear_guest_signal(struct tst_kvm_instance *inst) +{ + inst->result->result = KVM_TNONE; +} + void tst_kvm_setup(void) { @@ -280,7 +329,7 @@ void tst_kvm_setup(void) void tst_kvm_run(void) { tst_kvm_create_instance(&test_vm, DEFAULT_RAM_SIZE); - tst_kvm_run_instance(&test_vm); + tst_kvm_run_instance(&test_vm, 0); tst_kvm_destroy_instance(&test_vm); tst_free_all(); } diff --git a/testcases/kernel/kvm/lib_x86.c b/testcases/kernel/kvm/lib_x86.c index dc2354b10..3e6656f11 100644 --- a/testcases/kernel/kvm/lib_x86.c +++ b/testcases/kernel/kvm/lib_x86.c @@ -5,7 +5,9 @@ * x86-specific KVM helper functions */ -#include "kvm_x86.h" +#include "kvm_x86_svm.h" + +void kvm_svm_guest_entry(void); struct kvm_interrupt_frame { uintptr_t eip, cs, eflags, esp, ss; @@ -110,6 +112,98 @@ uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry) return entry->address << 12; } +#ifdef __x86_64__ +static void kvm_set_segment_descriptor64(struct segment_descriptor64 *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags) +{ + + dst->baseaddr_lo = baseaddr & 0xffffff; + dst->baseaddr_hi = baseaddr >> 24; + dst->limit_lo = limit & 0xffff; + dst->limit_hi = limit >> 16; + dst->flags_lo = flags & 0xff; + dst->flags_hi = (flags >> 8) & 0xf; + dst->reserved = 0; +} +#endif + +void kvm_set_segment_descriptor(struct segment_descriptor *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags) +{ + if (limit >> 20) + tst_brk(TBROK, "Segment limit out of range"); + +#ifdef __x86_64__ + /* System descriptors have double size in 64bit mode */ + if (!(flags & SEGFLAG_NSYSTEM)) { + kvm_set_segment_descriptor64((struct segment_descriptor64 *)dst, + baseaddr, limit, flags); + return; + } +#endif + + if (baseaddr >> 32) + tst_brk(TBROK, "Segment base address out of range"); + + dst->baseaddr_lo = baseaddr & 0xffffff; + dst->baseaddr_hi = baseaddr >> 24; + dst->limit_lo = limit & 0xffff; + dst->limit_hi = limit >> 16; + dst->flags_lo = flags & 0xff; + dst->flags_hi = (flags >> 8) & 0xf; +} + +void kvm_parse_segment_descriptor(struct segment_descriptor *src, + uint64_t *baseaddr, uint32_t *limit, unsigned int *flags) +{ + if (baseaddr) { + *baseaddr = (((uint64_t)src->baseaddr_hi) << 24) | + src->baseaddr_lo; + } + + if (limit) + *limit = (((uint32_t)src->limit_hi) << 16) | src->limit_lo; + + if (flags) + *flags = (((uint32_t)src->flags_hi) << 8) | src->flags_lo; +} + +int kvm_find_free_descriptor(const struct segment_descriptor *table, + size_t size) +{ + const struct segment_descriptor *ptr; + size_t i; + + for (i = 0, ptr = table; i < size; i++, ptr++) { + if (!(ptr->flags_lo & SEGFLAG_PRESENT)) + return i; + +#ifdef __x86_64__ + /* System descriptors have double size in 64bit mode */ + if (!(ptr->flags_lo & SEGFLAG_NSYSTEM)) { + ptr++; + i++; + } +#endif + } + + return -1; +} + +unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, + size_t tabsize, void *stack_base) +{ + int ret = kvm_find_free_descriptor(table, tabsize); + + if (ret < 0) + tst_brk(TBROK, "Descriptor table is full"); + + kvm_set_segment_descriptor(table + ret, 0, + (((uintptr_t)stack_base) - 1) >> 12, SEGTYPE_STACK | + SEGFLAG_PRESENT | SEGFLAG_32BIT | SEGFLAG_PAGE_LIMIT); + return ret; +} + void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf) { asm ( @@ -148,3 +242,154 @@ uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm) { return ifrm->eip; } + +int kvm_is_svm_supported(void) +{ + struct kvm_cpuid buf; + + kvm_get_cpuid(CPUID_GET_INPUT_RANGE, 0, &buf); + + if (buf.eax < CPUID_GET_EXT_FEATURES) + return 0; + + kvm_get_cpuid(CPUID_GET_EXT_FEATURES, 0, &buf); + return buf.ecx & 0x4; +} + +int kvm_get_svm_state(void) +{ + return kvm_rdmsr(MSR_EFER) & EFER_SVME; +} + +void kvm_set_svm_state(int enabled) +{ + uint64_t value; + + if (!kvm_is_svm_supported()) + tst_brk(TCONF, "CPU does not support SVM"); + + if (kvm_rdmsr(MSR_VM_CR) & VM_CR_SVMDIS) + tst_brk(TCONF, "SVM is supported but disabled"); + + value = kvm_rdmsr(MSR_EFER); + + if (enabled) + value |= EFER_SVME; + else + value &= ~EFER_SVME; + + kvm_wrmsr(MSR_EFER, value); +} + +struct kvm_vmcb *kvm_alloc_vmcb(void) +{ + struct kvm_vmcb *ret; + + ret = tst_heap_alloc_aligned(sizeof(struct kvm_vmcb), PAGESIZE); + memset(ret, 0, sizeof(struct kvm_vmcb)); + return ret; +} + +void kvm_init_svm(void) +{ + kvm_set_svm_state(1); + kvm_wrmsr(MSR_VM_HSAVE_PA, (uintptr_t)kvm_alloc_vmcb()); +} + +void kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor *dst, + unsigned int gdt_id) +{ + uint64_t baseaddr; + uint32_t limit; + unsigned int flags; + + if (gdt_id >= KVM_GDT_SIZE) + tst_brk(TBROK, "GDT descriptor ID out of range"); + + kvm_parse_segment_descriptor(kvm_gdt + gdt_id, &baseaddr, &limit, + &flags); + + if (!(flags & SEGFLAG_PRESENT)) { + memset(dst, 0, sizeof(struct kvm_vmcb_descriptor)); + return; + } + + if (flags & SEGFLAG_PAGE_LIMIT) + limit = (limit << 12) | 0xfff; + + dst->selector = gdt_id << 3; + dst->attrib = flags; + dst->limit = limit; + dst->base = baseaddr; +} + +void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, + unsigned int state) +{ + unsigned int addr = id / 8, bit = 1 << (id % 8); + + if (id >= SVM_INTERCEPT_MAX) + tst_brk(TBROK, "Invalid SVM intercept ID"); + + if (state) + vmcb->intercepts[addr] |= bit; + else + vmcb->intercepts[addr] &= ~bit; +} + +void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, + void *rsp, int (*guest_main)(void)) +{ + struct kvm_cregs cregs; + struct kvm_sregs sregs; + + kvm_read_cregs(&cregs); + kvm_read_sregs(&sregs); + + kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_VMRUN, 1); + kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_HLT, 1); + + kvm_vmcb_copy_gdt_descriptor(&vmcb->es, sregs.es >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->cs, sregs.cs >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->ss, ss); + kvm_vmcb_copy_gdt_descriptor(&vmcb->ds, sregs.ds >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->fs, sregs.fs >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->gs, sregs.gs >> 3); + vmcb->gdtr.base = (uintptr_t)kvm_gdt; + vmcb->gdtr.limit = (KVM_GDT_SIZE*sizeof(struct segment_descriptor)) - 1; + vmcb->idtr.base = (uintptr_t)kvm_idt; + vmcb->idtr.limit = (X86_INTR_COUNT*sizeof(struct intr_descriptor)) - 1; + + vmcb->guest_asid = asid; + vmcb->efer = kvm_rdmsr(MSR_EFER); + vmcb->cr0 = cregs.cr0; + vmcb->cr3 = cregs.cr3; + vmcb->cr4 = cregs.cr4; + vmcb->rip = (uintptr_t)kvm_svm_guest_entry; + vmcb->rax = (uintptr_t)guest_main; + vmcb->rsp = (uintptr_t)rsp; + vmcb->rflags = 0x200; /* Interrupts enabled */ +} + +struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), + int alloc_stack) +{ + uint16_t ss = 0; + char *stack = NULL; + struct kvm_vmcb *vmcb; + struct kvm_svm_vcpu *ret; + + vmcb = kvm_alloc_vmcb(); + + if (alloc_stack) { + stack = tst_heap_alloc_aligned(2 * PAGESIZE, PAGESIZE); + ss = kvm_create_stack_descriptor(kvm_gdt, KVM_GDT_SIZE, stack); + stack += 2 * PAGESIZE; + } + + kvm_init_guest_vmcb(vmcb, 1, ss, stack, guest_main); + ret = tst_heap_alloc(sizeof(struct kvm_svm_vcpu)); + memset(ret, 0, sizeof(struct kvm_svm_vcpu)); + ret->vmcb = vmcb; + return ret; +} diff --git a/testcases/kernel/kvm/linker/x86.lds b/testcases/kernel/kvm/linker/x86.lds index 95edb0be0..6e69c4d0f 100644 --- a/testcases/kernel/kvm/linker/x86.lds +++ b/testcases/kernel/kvm/linker/x86.lds @@ -4,6 +4,7 @@ PHDRS { headers PT_PHDR PHDRS ; text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; bss PT_LOAD ; } @@ -18,7 +19,7 @@ SECTIONS .init.boot : { *(.init.protected_mode) - *(.data.gdt32) + *(.init.gdt32) *(.init.memlayout) } :text @@ -40,7 +41,7 @@ SECTIONS { *(.data.strings) *(.data) - } + } :data .preinit_array : { diff --git a/testcases/kernel/kvm/linker/x86_64.lds b/testcases/kernel/kvm/linker/x86_64.lds index ac372f863..9e62aa5ad 100644 --- a/testcases/kernel/kvm/linker/x86_64.lds +++ b/testcases/kernel/kvm/linker/x86_64.lds @@ -4,6 +4,7 @@ PHDRS { headers PT_PHDR PHDRS ; text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; bss PT_LOAD ; } @@ -18,7 +19,7 @@ SECTIONS .init.boot : { *(.init.protected_mode) - *(.data.gdt32) + *(.init.gdt32) *(.init.memlayout) } :text @@ -40,7 +41,7 @@ SECTIONS { *(.data.strings) *(.data) - } + } :data .preinit_array : { diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore index 06e125d03..7258489ed 100644 --- a/testcases/kernel/mem/.gitignore +++ b/testcases/kernel/mem/.gitignore @@ -33,6 +33,7 @@ /hugetlb/hugemmap/hugemmap29 /hugetlb/hugemmap/hugemmap30 /hugetlb/hugemmap/hugemmap31 +/hugetlb/hugemmap/hugemmap32 /hugetlb/hugeshmat/hugeshmat01 /hugetlb/hugeshmat/hugeshmat02 /hugetlb/hugeshmat/hugeshmat03 diff --git a/testcases/kernel/mem/hugetlb/hugemmap/Makefile b/testcases/kernel/mem/hugetlb/hugemmap/Makefile index 6f10807cd..2d651b4aa 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/Makefile +++ b/testcases/kernel/mem/hugetlb/hugemmap/Makefile @@ -8,5 +8,4 @@ include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../Makefile.inc include $(top_srcdir)/include/mk/generic_leaf_target.mk -hugemmap15: CFLAGS+=-O0 hugemmap06: CFLAGS+=-pthread diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c index 07e65a160..4d1984070 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c @@ -19,6 +19,10 @@ * remap, or because the icache happens to get flushed in the interim. */ +#if defined(__clang__) + #pragma clang optimize off +#endif + #define _GNU_SOURCE #include "hugetlb.h" @@ -27,16 +31,7 @@ defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || \ defined(__i386__) || defined(__x86_64__) || defined(__arm__) -#include <stdio.h> -#include <stdlib.h> #include <setjmp.h> -#include <unistd.h> -#include <signal.h> -#include <sys/mman.h> -#include <ucontext.h> -#include <limits.h> -#include <sys/param.h> -#include <sys/types.h> #define SUCC_JMP 1 #define FAIL_JMP 2 diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c index a465aadec..158a03010 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c @@ -23,7 +23,7 @@ static int fd = -1; static unsigned long slice_boundary; -static long hpage_size, page_size; +static unsigned long hpage_size, page_size; static int init_slice_boundary(int fd) { @@ -44,6 +44,13 @@ static int init_slice_boundary(int fd) heap = malloc(1); free(heap); + /* Avoid underflow on systems with large huge pages. + * The additionally plus heap address is to reduce the possibility + * of MAP_FIXED stomp over existing mappings. + */ + while (slice_boundary + slice_size < (unsigned long)heap + 2*hpage_size) + slice_boundary += slice_size; + /* Find 2 neighbour slices with couple huge pages free * around slice boundary. * 16 is the maximum number of slices (low/high) diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c new file mode 100644 index 000000000..d27e5b8b2 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023, IBM Corporation. + * Author: Tarun Sahu + */ + +/*\ + * [Description] + * + * Before kernel version 5.10-rc7, there was a bug that resulted in a "Bad Page + * State" error when freeing gigantic hugepages. This happened because the + * struct page entry compound_nr, which overlapped with page->mapping in the + * first tail page, was not cleared, causing the error. To ensure that this + * issue does not reoccur as struct page keeps changing and some fields are + * managed by folio, this test checks that freeing gigantic hugepages does not + * produce the above-mentioned error. + */ + +#define _GNU_SOURCE +#include <dirent.h> + +#include <stdio.h> + +#include "hugetlb.h" + +#define PATH_HUGEPAGE "/sys/kernel/mm/hugepages" +#define GIGANTIC_MIN_ORDER 10 + +static int org_g_hpages; +static char g_hpage_path[4096]; + +static void run_test(void) +{ + if (FILE_PRINTF(g_hpage_path, "%d", 1)) + tst_brk(TCONF, "Can't update the gigantic hugepages."); + SAFE_FILE_PRINTF(g_hpage_path, "%d", 0); + + if (tst_taint_check()) + tst_res(TFAIL, "Freeing Gigantic pages resulted in Bad Page State bug."); + else + tst_res(TPASS, "Successfully freed the gigantic hugepages"); +} + +static void setup(void) +{ + DIR *dir; + struct dirent *ent; + unsigned long hpage_size; + + if (access(PATH_HUGEPAGE, F_OK)) + tst_brk(TCONF, "hugetlbfs is not supported"); + + dir = SAFE_OPENDIR(PATH_HUGEPAGE); + while ((ent = SAFE_READDIR(dir))) { + if ((sscanf(ent->d_name, "hugepages-%lukB", &hpage_size) == 1) && + is_hugetlb_gigantic(hpage_size * 1024)) { + sprintf(g_hpage_path, "%s/%s/%s", PATH_HUGEPAGE, + ent->d_name, "nr_hugepages"); + break; + } + } + if (!g_hpage_path[0]) + tst_brk(TCONF, "Gigantic hugepages not supported"); + + SAFE_CLOSEDIR(dir); + + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); + SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1"); + + if (tst_available_mem() < (long long)hpage_size) { + g_hpage_path[0] = '\0'; + tst_brk(TCONF, "No enough memory for gigantic hugepage reservation"); + } + + SAFE_FILE_LINES_SCANF(g_hpage_path, "%d", &org_g_hpages); +} + +static void cleanup(void) +{ + if (g_hpage_path[0]) + SAFE_FILE_PRINTF(g_hpage_path, "%d", org_g_hpages); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "ba9c1201beaa"}, + {"linux-git", "a01f43901cfb"}, + {} + }, + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .taint_check = TST_TAINT_B, +}; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c index 50efa8a52..8ad745d5b 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c @@ -27,7 +27,6 @@ static long huge_free; static long huge_free2; -static long orig_shmmax = -1, new_shmmax; static void shared_hugepage(void); @@ -81,14 +80,13 @@ static void shared_hugepage(void) static void setup(void) { long hpage_size, orig_hugepages; + unsigned long new_shmmax; orig_hugepages = get_sys_tune("nr_hugepages"); - SAFE_FILE_SCANF(PATH_SHMMAX, "%ld", &orig_shmmax); - SAFE_FILE_PRINTF(PATH_SHMMAX, "%ld", (long)SIZE); - SAFE_FILE_SCANF(PATH_SHMMAX, "%ld", &new_shmmax); + SAFE_FILE_SCANF(PATH_SHMMAX, "%lu", &new_shmmax); if (new_shmmax < SIZE) - tst_brk(TCONF, "shmmax too low, have: %ld", new_shmmax); + tst_brk(TCONF, "shmmax too low, have: %lu", new_shmmax); hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; @@ -96,12 +94,6 @@ static void setup(void) tst_reserve_hugepages(&hp); } -static void cleanup(void) -{ - if (orig_shmmax != -1) - SAFE_FILE_PRINTF(PATH_SHMMAX, "%ld", orig_shmmax); -} - static struct tst_test test = { .tags = (const struct tst_tag[]) { {"linux-git", "c5c99429fa57"}, @@ -114,6 +106,9 @@ static struct tst_test test = { .test = test_hugeshmat, .min_mem_avail = 2048, .setup = setup, - .cleanup = cleanup, .hugepages = {1, TST_NEEDS}, + .save_restore = (const struct tst_path_val[]) { + {PATH_SHMMAX, "1073741824", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, + {} + }, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c index 11cd69050..a68b0da75 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c @@ -53,10 +53,10 @@ static void func_set(void); static void func_rmid(void); static void *set_shmat(void); -struct tcase { +static struct tcase { int cmd; - void (*func_test) (void); - void (*func_setup) (void); + void (*func_test)(void); + void (*func_setup)(void); } tcases[] = { {IPC_STAT, func_stat, stat_setup_1}, {IPC_STAT, func_stat, stat_setup_2}, @@ -90,7 +90,7 @@ static void test_hugeshmctl(unsigned int i) /* * set_shmat() - Attach the shared memory and return the pointer. */ -void *set_shmat(void) +static void *set_shmat(void) { void *rval; @@ -103,8 +103,8 @@ void *set_shmat(void) /* * stat_setup_2() - Set up for the IPC_STAT command with shmctl(). - * Attach the shared memory to parent process and - * some children will inherit the shared memory. + * Attach the shared memory to parent process and + * some children will inherit the shared memory. */ static void stat_setup_2(void) { @@ -139,7 +139,7 @@ static void stat_setup_1(void) /* now we're back - detach the memory and exit */ if (shmdt(test) == -1) tst_brk(TBROK | TERRNO, - "shmdt in stat_setup()"); + "shmdt in this function broke"); exit(0); default: @@ -220,7 +220,8 @@ static void stat_cleanup(void) /* remove the parent's shared memory if we set*/ if (attach_to_parent) { if (shmdt(attach_to_parent) == -1) - tst_res(TFAIL | TERRNO, "shmdt in stat_cleanup()"); + tst_res(TFAIL | TERRNO, + "shmdt in this function failed"); attach_to_parent = NULL; } } @@ -244,7 +245,7 @@ static void func_set(void) { /* first stat the shared memory to get the new data */ if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) { - tst_res(TFAIL | TERRNO, "shmctl in func_set()"); + tst_res(TFAIL | TERRNO, "shmctl in this function failed"); return; } @@ -268,18 +269,18 @@ static void func_rmid(void) { /* Do another shmctl() - we should get EINVAL */ if (shmctl(shm_id_1, IPC_STAT, &buf) != -1) - tst_brk(TBROK, "shmctl in func_rmid() " + tst_brk(TBROK, "shmctl in this function " "succeeded unexpectedly"); if (errno != EINVAL) - tst_res(TFAIL | TERRNO, "shmctl in func_rmid() failed " + tst_res(TFAIL | TERRNO, "shmctl in this function failed " "unexpectedly - expect errno=EINVAL, got"); else - tst_res(TPASS, "shmctl in func_rmid() failed as expected, " + tst_res(TPASS, "shmctl in this function failed as expected, " "shared memory appears to be removed"); shm_id_1 = -1; } -void setup(void) +static void setup(void) { long hpage_size; @@ -293,7 +294,7 @@ void setup(void) shmkey = getipckey(); } -void cleanup(void) +static void cleanup(void) { rm_shm(shm_id_1); } diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c index 0bc9ffd74..d3f711129 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c @@ -27,6 +27,7 @@ #include <pwd.h> #include <limits.h> #include "hugetlb.h" +#include "lapi/syscalls.h" static size_t shm_size; static int shm_id_1 = -1; @@ -34,7 +35,7 @@ static int shm_id_2 = -1; static int shm_id_3 = -1; static struct shmid_ds buf; -struct tcase { +static struct tcase { int *shmid; int cmd; struct shmid_ds *sbuf; @@ -50,9 +51,37 @@ struct tcase { {&shm_id_2, -1, &buf, EINVAL}, }; +static int libc_shmctl(int shmid, int cmd, void *buf) +{ + return shmctl(shmid, cmd, buf); +} + +static int sys_shmctl(int shmid, int cmd, void *buf) +{ + return tst_syscall(__NR_shmctl, shmid, cmd, buf); +} + +static struct test_variants +{ + int (*shmctl)(int shmid, int cmd, void *buf); + char *desc; +} variants[] = { + { .shmctl = libc_shmctl, .desc = "libc shmctl()"}, +#if (__NR_shmctl != __LTP__NR_INVALID_SYSCALL) + { .shmctl = sys_shmctl, .desc = "__NR_shmctl syscall"}, +#endif +}; + static void test_hugeshmctl(unsigned int i) { - TEST(shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf)); + struct test_variants *tv = &variants[tst_variant]; + + if (tcases[i].error == EFAULT && tv->shmctl == libc_shmctl) { + tst_res(TCONF, "EFAULT is skipped for libc variant"); + return; + } + + TEST(tv->shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf)); if (TST_RET != -1) { tst_res(TFAIL, "shmctl succeeded unexpectedly"); return; @@ -70,8 +99,11 @@ static void test_hugeshmctl(unsigned int i) static void setup(void) { + struct test_variants *tv = &variants[tst_variant]; long hpage_size; + tst_res(TINFO, "Testing variant: %s", tv->desc); + if (tst_hugepages == 0) tst_brk(TCONF, "No enough hugepages for testing."); @@ -101,6 +133,7 @@ static void cleanup(void) static struct tst_test test = { .test = test_hugeshmctl, + .test_variants = ARRAY_SIZE(variants), .tcnt = ARRAY_SIZE(tcases), .needs_root = 1, .needs_tmpdir = 1, diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c index 21ec6bf78..ec4640686 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c @@ -41,10 +41,10 @@ static size_t shm_size; static int shm_id_1 = -1; static struct shmid_ds buf; -static uid_t ltp_uid; -static char *ltp_user = "nobody"; +static uid_t test_uid; +static char *test_user = "nobody"; -struct tcase { +static struct tcase { int *shmid; int cmd; struct shmid_ds *sbuf; @@ -68,7 +68,7 @@ static void test_hugeshmctl(void) switch (pid = SAFE_FORK()) { case 0: /* set the user ID of the child to the non root user */ - SAFE_SETUID(ltp_uid); + SAFE_SETUID(test_uid); do_child(); exit(0); default: @@ -97,7 +97,7 @@ static void do_child(void) } } -void setup(void) +static void setup(void) { long hpage_size; @@ -115,10 +115,10 @@ void setup(void) tst_brk(TBROK | TERRNO, "shmget"); /* get the userid for a non root user */ - ltp_uid = getuserid(ltp_user); + test_uid = getuserid(test_user); } -void cleanup(void) +static void cleanup(void) { rm_shm(shm_id_1); } diff --git a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c index 7e72a19ca..625761f6e 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c +++ b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c @@ -84,7 +84,7 @@ static void cleanup(void) rm_shm(shm_id_arr[i]); if (orig_shmmni != -1) - FILE_PRINTF(PATH_SHMMNI, "%ld", orig_shmmni); + SAFE_FILE_PRINTF(PATH_SHMMNI, "%ld", orig_shmmni); } static struct tst_test test = { diff --git a/testcases/kernel/mem/hugetlb/lib/hugetlb.h b/testcases/kernel/mem/hugetlb/lib/hugetlb.h index 241dab708..34fe08c24 100644 --- a/testcases/kernel/mem/hugetlb/lib/hugetlb.h +++ b/testcases/kernel/mem/hugetlb/lib/hugetlb.h @@ -39,6 +39,12 @@ # endif #endif +/* Check if hugetlb page is gigantic */ +static inline int is_hugetlb_gigantic(unsigned long hpage_size) +{ + return (hpage_size / getpagesize()) >> 11; +} + /* * to get the lower nine permission bits * from shmid_ds.ipc_perm.mode diff --git a/testcases/kernel/mem/include/mem.h b/testcases/kernel/mem/include/mem.h index 776809113..cdc3ca146 100644 --- a/testcases/kernel/mem/include/mem.h +++ b/testcases/kernel/mem/include/mem.h @@ -42,7 +42,6 @@ static inline void clean_node(unsigned long *array) #define MLOCK 2 #define KSM 3 -extern long overcommit; void oom(int testcase, int lite, int retcode, int allow_sigkill); void testoom(int mempolicy, int lite, int retcode, int allow_sigkill); diff --git a/testcases/kernel/mem/ksm/ksm05.c b/testcases/kernel/mem/ksm/ksm05.c index 25f3435b2..1f58c8325 100644 --- a/testcases/kernel/mem/ksm/ksm05.c +++ b/testcases/kernel/mem/ksm/ksm05.c @@ -95,6 +95,10 @@ static struct tst_test test = { "CONFIG_KSM=y", NULL }, + .tags = (const struct tst_tag[]) { + {"CVE", "2011-2183"}, + {} + } }; #else diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c index 8ddd7adf7..fbfeef026 100644 --- a/testcases/kernel/mem/lib/mem.c +++ b/testcases/kernel/mem/lib/mem.c @@ -27,8 +27,6 @@ /* OOM */ -long overcommit = -1; - static int alloc_mem(long int length, int testcase) { char *s; diff --git a/testcases/kernel/mem/oom/oom01.c b/testcases/kernel/mem/oom/oom01.c index 9f7d76587..b13699898 100644 --- a/testcases/kernel/mem/oom/oom01.c +++ b/testcases/kernel/mem/oom/oom01.c @@ -49,22 +49,13 @@ static void verify_oom(void) testoom(0, 0, ENOMEM, 1); } -static void setup(void) -{ - overcommit = get_sys_tune("overcommit_memory"); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, - .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/oom/oom02.c b/testcases/kernel/mem/oom/oom02.c index b3719f723..8d565d12a 100644 --- a/testcases/kernel/mem/oom/oom02.c +++ b/testcases/kernel/mem/oom/oom02.c @@ -56,15 +56,6 @@ static void setup(void) { if (!is_numa(NULL, NH_MEMS, 2)) tst_brk(TCONF, "The case need a NUMA system."); - - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); } static struct tst_test test = { @@ -72,8 +63,11 @@ static struct tst_test test = { .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom03.c b/testcases/kernel/mem/oom/oom03.c index 0882c9bbe..778055d03 100644 --- a/testcases/kernel/mem/oom/oom03.c +++ b/testcases/kernel/mem/oom/oom03.c @@ -79,27 +79,21 @@ static void verify_oom(void) static void setup(void) { - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); } -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom04.c b/testcases/kernel/mem/oom/oom04.c index ad39f7e77..d27d9d9e7 100644 --- a/testcases/kernel/mem/oom/oom04.c +++ b/testcases/kernel/mem/oom/oom04.c @@ -65,9 +65,6 @@ static void setup(void) if (!is_numa(NULL, NH_MEMS, 1)) tst_brk(TCONF, "requires NUMA with at least 1 node"); - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - /* * Some nodes do not contain memory, so use * get_allowed_nodes(NH_MEMS) to get a memory @@ -82,20 +79,17 @@ static void setup(void) SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); } -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom05.c b/testcases/kernel/mem/oom/oom05.c index e31146e7a..eb1a64267 100644 --- a/testcases/kernel/mem/oom/oom05.c +++ b/testcases/kernel/mem/oom/oom05.c @@ -85,9 +85,6 @@ void setup(void) if (!is_numa(NULL, NH_MEMS, 1)) tst_brk(TCONF, "requires NUMA with at least 1 node"); - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - /* * Some nodes do not contain memory, so use * get_allowed_nodes(NH_MEMS) to get a memory @@ -104,22 +101,19 @@ void setup(void) SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); } -void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, .needs_cgroup_ctrls = (const char *const []){ "memory", "cpuset", NULL }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/thp/thp03.c b/testcases/kernel/mem/thp/thp03.c index c6062505f..839efcb0e 100644 --- a/testcases/kernel/mem/thp/thp03.c +++ b/testcases/kernel/mem/thp/thp03.c @@ -30,7 +30,6 @@ * corruption and no data corruption (nor userland nor kernel). */ -#include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> #include <fcntl.h> diff --git a/testcases/kernel/mem/thp/thp04.c b/testcases/kernel/mem/thp/thp04.c index 7cab5d76b..b5f518ac5 100644 --- a/testcases/kernel/mem/thp/thp04.c +++ b/testcases/kernel/mem/thp/thp04.c @@ -26,8 +26,6 @@ * commit 8310d48b125d("huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp"). */ -#include <sys/mman.h> - #include "tst_test.h" #include "lapi/mmap.h" #include "tst_fuzzy_sync.h" diff --git a/testcases/kernel/mem/tunable/max_map_count.c b/testcases/kernel/mem/tunable/max_map_count.c index caf8972e0..f33095473 100644 --- a/testcases/kernel/mem/tunable/max_map_count.c +++ b/testcases/kernel/mem/tunable/max_map_count.c @@ -53,26 +53,6 @@ #define MAP_COUNT_DEFAULT 1024 #define MAX_MAP_COUNT 65536L -static long old_max_map_count = -1; -static long old_overcommit = -1; - -static void setup(void) -{ - SAFE_ACCESS(PATH_SYSVM "max_map_count", F_OK); - - old_max_map_count = get_sys_tune("max_map_count"); - old_overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 0, 1); -} - -static void cleanup(void) -{ - if (old_overcommit != -1) - set_sys_tune("overcommit_memory", old_overcommit, 0); - if (old_max_map_count != -1) - set_sys_tune("max_map_count", old_max_map_count, 0); -} - /* This is a filter to exclude map entries which aren't accounted * for in the vm_area_struct's map_count. */ @@ -210,7 +190,10 @@ static void max_map_count_test(void) static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .setup = setup, - .cleanup = cleanup, .test_all = max_map_count_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "0", TST_SR_TBROK}, + {"/proc/sys/vm/max_map_count", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/tunable/min_free_kbytes.c b/testcases/kernel/mem/tunable/min_free_kbytes.c index eab6c8b2e..19da409e8 100644 --- a/testcases/kernel/mem/tunable/min_free_kbytes.c +++ b/testcases/kernel/mem/tunable/min_free_kbytes.c @@ -41,7 +41,6 @@ volatile int end; static long default_tune = -1; -static long orig_overcommit = -1; static unsigned long total_mem; static void test_tune(unsigned long overcommit_policy); @@ -217,15 +216,6 @@ static void setup(void) total_mem = SAFE_READ_MEMINFO("MemTotal:") + SAFE_READ_MEMINFO("SwapTotal:"); default_tune = get_sys_tune("min_free_kbytes"); - orig_overcommit = get_sys_tune("overcommit_memory"); -} - -static void cleanup(void) -{ - if (default_tune != -1) - set_sys_tune("min_free_kbytes", default_tune, 0); - if (orig_overcommit != -1) - set_sys_tune("overcommit_memory", orig_overcommit, 0); } static struct tst_test test = { @@ -233,6 +223,10 @@ static struct tst_test test = { .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = min_free_kbytes_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {"/proc/sys/vm/min_free_kbytes", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/tunable/overcommit_memory.c b/testcases/kernel/mem/tunable/overcommit_memory.c index 7fe8fe14c..ffb7a6d9d 100644 --- a/testcases/kernel/mem/tunable/overcommit_memory.c +++ b/testcases/kernel/mem/tunable/overcommit_memory.c @@ -70,7 +70,6 @@ #define EXPECT_FAIL 1 static char *R_opt; -static long old_overcommit_memory = -1; static long old_overcommit_ratio = -1; static long overcommit_ratio; static long sum_total; @@ -90,16 +89,11 @@ static void setup(void) long mem_total, swap_total; struct rlimit lim; - if (access(PATH_SYSVM "overcommit_memory", F_OK) == -1 || - access(PATH_SYSVM "overcommit_ratio", F_OK) == -1) - tst_brk(TCONF, "system doesn't support overcommit_memory"); - if (R_opt) overcommit_ratio = SAFE_STRTOL(R_opt, 0, LONG_MAX); else overcommit_ratio = DEFAULT_OVER_RATIO; - old_overcommit_memory = get_sys_tune("overcommit_memory"); old_overcommit_ratio = get_sys_tune("overcommit_ratio"); mem_total = SAFE_READ_MEMINFO("MemTotal:"); @@ -128,14 +122,6 @@ static void setup(void) tst_res(TINFO, "TotalBatchSize is %ld kB", total_batch_size); } -static void cleanup(void) -{ - if (old_overcommit_memory != -1) - set_sys_tune("overcommit_memory", old_overcommit_memory, 0); - if (old_overcommit_ratio != -1) - set_sys_tune("overcommit_ratio", old_overcommit_ratio, 0); -} - static void overcommit_memory_test(void) { @@ -269,6 +255,10 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, .test_all = overcommit_memory_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {"/proc/sys/vm/overcommit_ratio", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/vma/vma05.sh b/testcases/kernel/mem/vma/vma05.sh index 9ef6f0a23..c9e4becdb 100755 --- a/testcases/kernel/mem/vma/vma05.sh +++ b/testcases/kernel/mem/vma/vma05.sh @@ -30,6 +30,7 @@ setup() { ulimit -c unlimited echo "core" > /proc/sys/kernel/core_pattern + unset DEBUGINFOD_URLS } cleanup() diff --git a/testcases/kernel/numa/numa01.sh b/testcases/kernel/numa/numa01.sh index 367813ce9..0181cd8f5 100755 --- a/testcases/kernel/numa/numa01.sh +++ b/testcases/kernel/numa/numa01.sh @@ -183,7 +183,7 @@ test4() no_of_cpus=$(tst_ncpus) # not sure whether cpu's can't be in odd number run_on_cpu=$(($((no_of_cpus+1))/2)) - numactl --physcpubind=$run_on_cpu support_numa pause & #just waits for sigint + numactl --all --physcpubind=$run_on_cpu support_numa pause & #just waits for sigint pid=$! var=`awk '{ print $2 }' /proc/$pid/stat` while [ $var = '(numactl)' ]; do diff --git a/testcases/kernel/numa/support_numa.c b/testcases/kernel/numa/support_numa.c index a0afee554..6fb82f374 100644 --- a/testcases/kernel/numa/support_numa.c +++ b/testcases/kernel/numa/support_numa.c @@ -37,7 +37,6 @@ #include <string.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/mman.h> #include <fcntl.h> #include "lapi/mmap.h" diff --git a/testcases/kernel/sched/cfs-scheduler/.gitignore b/testcases/kernel/sched/cfs-scheduler/.gitignore index c5dacd6ef..3ea3f75fc 100644 --- a/testcases/kernel/sched/cfs-scheduler/.gitignore +++ b/testcases/kernel/sched/cfs-scheduler/.gitignore @@ -1,2 +1,3 @@ /hackbench -cfs_bandwidth01 +/cfs_bandwidth01 +/starvation diff --git a/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c b/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c index 8f2da4493..27fc0fc5d 100644 --- a/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c +++ b/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com> */ +/* + * Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com> + * Copyright (c) Linux Test Project, 2021-2023 + */ + /*\ - * * [Description] * * Creates a multi-level CGroup hierarchy with the cpu controller @@ -15,7 +18,8 @@ * them to be unthrottle. * * The test is known to reproduce an issue with an update to - * SLE-15-SP1 (kernel 4.12.14-197.64, bsc#1179093). + * SLE-15-SP1 (kernel 4.12.14-197.64, + * https://bugzilla.suse.com/show_bug.cgi?id=1179093). * * Also as an reproducer for another bug: * diff --git a/testcases/kernel/sched/cfs-scheduler/starvation.c b/testcases/kernel/sched/cfs-scheduler/starvation.c new file mode 100644 index 000000000..eb9fd6ff5 --- /dev/null +++ b/testcases/kernel/sched/cfs-scheduler/starvation.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright 2023 Mike Galbraith <efault-AT-gmx.de> */ +/* Copyright 2023 Wei Gao <wegao@suse.com> */ +/*\ + * + * [Description] + * + * Thread starvation test. On fauluty kernel the test timeouts. + * + * Original reproducer taken from: + * https://lore.kernel.org/lkml/9fd2c37a05713c206dcbd5866f67ce779f315e9e.camel@gmx.de/ + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <sched.h> + +#include "tst_test.h" + +static char *str_loop; +static long loop = 2000000; +static char *str_timeout; +static int timeout = 240; + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (WIFSIGNALED(status)) + return 0; + + return -1; +} + +static void setup(void) +{ + cpu_set_t mask; + + CPU_ZERO(&mask); + + CPU_SET(0, &mask); + + TST_EXP_POSITIVE(sched_setaffinity(0, sizeof(mask), &mask)); + + if (tst_parse_long(str_loop, &loop, 1, LONG_MAX)) + tst_brk(TBROK, "Invalid number of loop number '%s'", str_loop); + + if (tst_parse_int(str_timeout, &timeout, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of timeout '%s'", str_timeout); + + tst_set_max_runtime(timeout); +} + +static void handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + if (loop > 0) + --loop; +} + +static void child(void) +{ + pid_t ppid = getppid(); + + TST_CHECKPOINT_WAIT(0); + + while (1) + SAFE_KILL(ppid, SIGUSR1); +} + +static void do_test(void) +{ + pid_t child_pid; + + child_pid = SAFE_FORK(); + + if (!child_pid) + child(); + + SAFE_SIGNAL(SIGUSR1, handler); + TST_CHECKPOINT_WAKE(0); + + while (loop) + sleep(1); + + SAFE_KILL(child_pid, SIGTERM); + TST_EXP_PASS(wait_for_pid(child_pid)); +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .forks_child = 1, + .options = (struct tst_option[]) { + {"l:", &str_loop, "Number of loops (default 2000000)"}, + {"t:", &str_timeout, "Max timeout (default 240s)"}, + {} + }, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c index 9c2b03994..2a982347c 100644 --- a/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c +++ b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c @@ -115,7 +115,7 @@ static void *uffd_thread_fn(void *arg) if (ioctl(uffd, UFFDIO_CONTINUE, &uffdio) < 0) { if (errno == EEXIST) { uffdio_wake.start = (unsigned long) map; - uffdio_wake.len = 4096; + uffdio_wake.len = page_size; SAFE_IOCTL(uffd, UFFDIO_WAKE, &uffdio_wake); } } diff --git a/testcases/kernel/security/tomoyo/.gitignore b/testcases/kernel/security/tomoyo/.gitignore deleted file mode 100644 index 698646d93..000000000 --- a/testcases/kernel/security/tomoyo/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/newns -/tomoyo_accept_test -/tomoyo_file_test -/tomoyo_filesystem_test -/tomoyo_new_file_test -/tomoyo_new_test -/tomoyo_policy_io_test -/tomoyo_policy_memory_test -/tomoyo_rewrite_test diff --git a/testcases/kernel/security/tomoyo/Makefile b/testcases/kernel/security/tomoyo/Makefile deleted file mode 100644 index 00e4cc3ed..000000000 --- a/testcases/kernel/security/tomoyo/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# kernel/security/smack testcase Makefile -# -# Copyright (C) 2009, Cisco Systems Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Ngie Cooper, July 2009 -# - -top_srcdir ?= ../../../.. - -include $(top_srcdir)/include/mk/testcases.mk - -INSTALL_TARGETS := testall.sh - -include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/security/tomoyo/README b/testcases/kernel/security/tomoyo/README deleted file mode 100644 index 0cb538868..000000000 --- a/testcases/kernel/security/tomoyo/README +++ /dev/null @@ -1,58 +0,0 @@ -Always look here for latest version of these tests: -http://sourceforge.jp/projects/tomoyo/svn/view/trunk/2.3.x/tomoyo-tools/kernel_test/?root=tomoyo - -These testcases test the TOMOYO Security Module. And they are not part of -default LTP build/install/run. - -A kernel with TOMOYO configured is required to run the TOMOYO testsuite. -The securityfs filesystem must be mounted at /sys/kernel/security . - -Preparation steps are: - -1) Download tomoyo-tools package and extract and build and install. - - # wget -O tomoyo-tools.tar.gz 'http://sourceforge.jp/projects/tomoyo/svn/view/trunk/2.3.x/tomoyo-tools.tar.gz?root=tomoyo&view=tar' - # tar -zxf tomoyo-tools.tar.gz - # make -C tomoyo-tools/ install - - Programs are installed in /usr/sbin/ with prefix "tomoyo-" and - /usr/lib/tomoyo/ directory without prefix "tomoyo-". - - You can make a RPM package by "rpmbuild -bb tomoyo-tools/tomoyo-tools.spec" and - a DEB package by "alien -k" after "rpmbuild -bb". - -2) Run /usr/lib/tomoyo/init_policy . - - This will take several minutes. - - Hiding kernel source directory by "mount -t tmpfs none /usr/src/linux/" - would save some time. - - Configuration files are saved in /etc/tomoyo/ directory. - You can do "rm -fR /etc/tomoyo/" if you want to uninstall. - -3) Reboot the system with TOMOYO enabled kernel. - - To make sure TOMOYO is selected, you can add security=tomoyo to kernel's - command line. - -4) Build the tests. - - # (extract the tar ball containing the tests.) - # make autotools - # ./configure - # cd testcases/kernel/security/tomoyo/ - # make - # find `/bin/pwd` -type f -perm +100 >> /etc/tomoyo/manager.conf - # /usr/sbin/tomoyo-loadpolicy m - -Test steps are: - -1) Run the tests from the directory you ran "make". - - # ./testall.sh - - Please don't run the tests inside /tmp/ directory, for /tmp/ directory is - hidden by "newns" (a wrapper program to run the test in a new namespace). - - You can use "| grep -vF OK" to pick up only failed tests as testall.sh does. diff --git a/testcases/kernel/security/tomoyo/include.h b/testcases/kernel/security/tomoyo/include.h deleted file mode 100644 index edaf1170f..000000000 --- a/testcases/kernel/security/tomoyo/include.h +++ /dev/null @@ -1,379 +0,0 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>, 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * include.h - * - * Common functions for testing TOMOYO Linux's kernel. - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include <errno.h> -#include <fcntl.h> -#include <linux/kdev_t.h> -#include <linux/unistd.h> -#include <pty.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/timex.h> -#include <sys/types.h> -#include <sys/un.h> -#include <sys/wait.h> -#include <time.h> -#include <unistd.h> -#include <utime.h> -#include <sched.h> -#include <stdarg.h> -#include <sys/mount.h> -#include <arpa/inet.h> -#include <net/if.h> -#include <linux/ip.h> -#include <err.h> -#include "test.h" - -/* - * Some architectures like mips n32 don't have __NR_uselib defined in the - * system headers. - */ -#ifdef __NR_uselib -static inline int uselib(const char *library) -{ - return syscall(__NR_uselib, library); -} -#else -static inline int uselib(const char *library) -{ - errno = ENOSYS; - return -1; -} -#endif - -/* Is there an architecture without __NR_pivot_root defined? */ -#ifdef __NR_pivot_root -static inline int pivot_root(const char *new_root, const char *put_old) -{ - return syscall(__NR_pivot_root, new_root, put_old); -} -#else -static inline int pivot_root(const char *new_root, const char *put_old) -{ - errno = ENOSYS; - return -1; -} -#endif - -/* The sysctl() wrapper is dead and newer arches omit it now. */ -static inline int write_sysctl(const char *path, const char *value) -{ - FILE *fp = fopen(path, "w"); - if (!fp) - return 1; - fputs(value, fp); - fclose(fp); - return 0; -} - -static inline int read_sysctl(const char *path, char *value, int len) -{ - char scratch[100]; - FILE *fp = fopen(path, "r"); - if (!fp) - return 1; - if (!value) { - value = scratch; - len = sizeof(scratch); - } - if (fgets(value, len, fp)) - /* ignore */; - fclose(fp); - return 0; -} - -/* Should be a fairly benign path to bang on. */ -#define TEST_SYSCTL_PATH "/proc/sys/net/ipv4/ip_local_port_range" - -#define proc_policy_dir "/sys/kernel/security/tomoyo/" -#define proc_policy_domain_policy "/sys/kernel/security/tomoyo/domain_policy" -#define proc_policy_exception_policy "/sys/kernel/security/tomoyo/exception_policy" -#define proc_policy_profile "/sys/kernel/security/tomoyo/profile" -#define proc_policy_manager "/sys/kernel/security/tomoyo/manager" -#define proc_policy_query "/sys/kernel/security/tomoyo/query" -#define proc_policy_grant_log "/sys/kernel/security/tomoyo/grant_log" -#define proc_policy_reject_log "/sys/kernel/security/tomoyo/reject_log" -#define proc_policy_domain_status "/sys/kernel/security/tomoyo/.domain_status" -#define proc_policy_process_status "/sys/kernel/security/tomoyo/.process_status" -#define proc_policy_self_domain "/sys/kernel/security/tomoyo/self_domain" - -static FILE *profile_fp = NULL; -static FILE *domain_fp = NULL; -static FILE *exception_fp = NULL; -static char self_domain[4096] = ""; -static pid_t pid = 0; - -static void clear_status(void) -{ - static const char *keywords[] = { - "file::execute", - "file::open", - "file::create", - "file::unlink", - "file::mkdir", - "file::rmdir", - "file::mkfifo", - "file::mksock", - "file::truncate", - "file::symlink", - "file::rewrite", - "file::mkblock", - "file::mkchar", - "file::link", - "file::rename", - "file::chmod", - "file::chown", - "file::chgrp", - "file::ioctl", - "file::chroot", - "file::mount", - "file::umount", - "file::pivot_root", - NULL - }; - int i; - FILE *fp = fopen(proc_policy_profile, "r"); - static char buffer[4096]; - if (!fp) { - fprintf(stderr, "Can't open %s\n", proc_policy_profile); - exit(1); - } - for (i = 0; keywords[i]; i++) - fprintf(profile_fp, - "255-CONFIG::%s={ mode=disabled }\n", - keywords[i]); - while (memset(buffer, 0, sizeof(buffer)), - fgets(buffer, sizeof(buffer) - 10, fp)) { - const char *mode; - char *cp = strchr(buffer, '='); - if (!cp) - continue; - *cp = '\0'; - mode = cp + 1; - cp = strchr(buffer, '-'); - if (!cp) - continue; - *cp++ = '\0'; - if (strcmp(buffer, "0")) - continue; - fprintf(profile_fp, "255-%s", cp); - if (!strcmp(cp, "COMMENT")) - mode = "Profile for kernel test\n"; - else - mode = "{ mode=disabled verbose=no }\n"; - fprintf(profile_fp, "255-%s=%s", cp, mode); - } - fprintf(profile_fp, "255-PREFERENCE::learning= verbose=no\n"); - fprintf(profile_fp, "255-PREFERENCE::enforcing= verbose=no\n"); - fprintf(profile_fp, "255-PREFERENCE::permissive= verbose=no\n"); - fprintf(profile_fp, "255-PREFERENCE::disabled= verbose=no\n"); - fprintf(profile_fp, "255-PREFERENCE::learning= max_entry=2048\n"); - fflush(profile_fp); - fclose(fp); -} - -static void tomoyo_test_init(void) -{ - pid = getpid(); - if (access(proc_policy_dir, F_OK)) { - fprintf(stderr, "You can't use this program for this kernel." - "\n"); - exit(1); - } - profile_fp = fopen(proc_policy_profile, "w"); - if (!profile_fp) { - fprintf(stderr, "Can't open %s .\n", proc_policy_profile); - exit(1); - } - setlinebuf(profile_fp); - domain_fp = fopen(proc_policy_domain_policy, "w"); - if (!domain_fp) { - fprintf(stderr, "Can't open %s .\n", - proc_policy_domain_policy); - exit(1); - } - setlinebuf(domain_fp); - exception_fp = fopen(proc_policy_exception_policy, "w"); - if (!exception_fp) { - fprintf(stderr, "Can't open %s .\n", - proc_policy_exception_policy); - exit(1); - } - setlinebuf(exception_fp); - if (fputc('\n', profile_fp) != '\n' || fflush(profile_fp)) { - fprintf(stderr, "You need to register this program to %s to " - "run this program.\n", proc_policy_manager); - exit(1); - } - clear_status(); - { - FILE *fp = fopen(proc_policy_self_domain, "r"); - memset(self_domain, 0, sizeof(self_domain)); - if (!fp || !fgets(self_domain, sizeof(self_domain) - 1, fp) || - fclose(fp)) { - fprintf(stderr, "Can't open %s .\n", - proc_policy_self_domain); - exit(1); - } - } - fprintf(domain_fp, "select pid=%u\n", pid); - fprintf(domain_fp, "use_profile 255\n"); - fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/domain_policy\n"); - fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/domain_policy\n"); - fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/exception_policy\n"); - fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/exception_policy\n"); - fprintf(domain_fp, "allow_read/write /sys/kernel/security/tomoyo/profile\n"); - fprintf(domain_fp, "allow_truncate /sys/kernel/security/tomoyo/profile\n"); -} - -static void BUG(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); - -static void BUG(const char *fmt, ...) -{ - va_list args; - printf("BUG: "); - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - putchar('\n'); - fflush(stdout); - while (1) - sleep(100); -} - -int write_domain_policy(const char *policy, int is_delete) -{ - FILE *fp = fopen(proc_policy_domain_policy, "r"); - char buffer[8192]; - int domain_found = 0; - int policy_found = 0; - memset(buffer, 0, sizeof(buffer)); - if (!fp) { - BUG("Can't read %s", proc_policy_domain_policy); - return 0; - } - if (is_delete) - fprintf(domain_fp, "delete "); - fprintf(domain_fp, "%s\n", policy); - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - char *cp = strchr(buffer, '\n'); - if (cp) - *cp = '\0'; - if (!strncmp(buffer, "<kernel>", 8)) - domain_found = !strcmp(self_domain, buffer); - if (!domain_found) - continue; - /* printf("<%s>\n", buffer); */ - if (strcmp(buffer, policy)) - continue; - policy_found = 1; - break; - } - fclose(fp); - if (policy_found == is_delete) { - BUG("Can't %s %s", is_delete ? "delete" : "append", - policy); - return 0; - } - errno = 0; - return 1; - -} - -int write_exception_policy(const char *policy, int is_delete) -{ - FILE *fp = fopen(proc_policy_exception_policy, "r"); - char buffer[8192]; - int policy_found = 0; - memset(buffer, 0, sizeof(buffer)); - if (!fp) { - BUG("Can't read %s", proc_policy_exception_policy); - return 0; - } - if (is_delete) - fprintf(exception_fp, "delete "); - fprintf(exception_fp, "%s\n", policy); - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - char *cp = strchr(buffer, '\n'); - if (cp) - *cp = '\0'; - if (strcmp(buffer, policy)) - continue; - policy_found = 1; - break; - } - fclose(fp); - if (policy_found == is_delete) { - BUG("Can't %s %s", is_delete ? "delete" : "append", - policy); - return 0; - } - errno = 0; - return 1; - -} - -int set_profile(const int mode, const char *name) -{ - static const char *modes[4] = { "disabled", "learning", "permissive", - "enforcing" }; - FILE *fp = fopen(proc_policy_profile, "r"); - char buffer[8192]; - int policy_found = 0; - const int len = strlen(name); - if (!fp) { - BUG("Can't read %s", proc_policy_profile); - return 0; - } - fprintf(profile_fp, "255-CONFIG::%s=%s\n", name, modes[mode]); - while (memset(buffer, 0, sizeof(buffer)), - fgets(buffer, sizeof(buffer) - 1, fp)) { - char *cp = strchr(buffer, '\n'); - if (cp) - *cp = '\0'; - if (strncmp(buffer, "255-CONFIG::", 12) || - strncmp(buffer + 12, name, len) || - buffer[12 + len] != '=') - continue; - if (strstr(buffer + 13 + len, modes[mode])) - policy_found = 1; - break; - } - fclose(fp); - if (!policy_found) { - BUG("Can't change profile to 255-CONFIG::%s=%s", - name, modes[mode]); - return 0; - } - errno = 0; - return 1; -} diff --git a/testcases/kernel/security/tomoyo/newns.c b/testcases/kernel/security/tomoyo/newns.c deleted file mode 100644 index f888ca31f..000000000 --- a/testcases/kernel/security/tomoyo/newns.c +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>, 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/mount.h> -#include <unistd.h> -#include <sched.h> -#include <errno.h> -#include <stdlib.h> -#include "test.h" - -static int child(void *arg) -{ - char **argv = (char **)arg; - argv++; - mount("/tmp/", "/tmp/", "tmpfs", 0, NULL); - execvp(argv[0], argv); - _exit(1); -} - -int main(int argc, char *argv[]) -{ - char c = 0; - const pid_t pid = ltp_clone_quick(CLONE_NEWNS, child, (void *)argv); - while (waitpid(pid, NULL, __WALL) == EOF && errno == EINTR) - c++; /* Dummy. */ - return 0; -} diff --git a/testcases/kernel/security/tomoyo/testall.sh b/testcases/kernel/security/tomoyo/testall.sh deleted file mode 100644 index b103be6c6..000000000 --- a/testcases/kernel/security/tomoyo/testall.sh +++ /dev/null @@ -1,46 +0,0 @@ -#! /bin/sh -################################################################################ -## ## -## Copyright (c) Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>, 2009 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program 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 General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ - -cd ${0%/*} -export PATH=$PWD:${PATH} - -echo "Testing all. (All results are reported)" -newns tomoyo_accept_test -newns tomoyo_filesystem_test -newns tomoyo_file_test -newns tomoyo_rewrite_test -newns tomoyo_new_file_test -newns tomoyo_new_test -echo -echo -echo -echo "Testing all. (Only ERRORS are reported)" -newns tomoyo_accept_test | grep -vF Done -newns tomoyo_filesystem_test | grep -vF OK | grep -F '(' -newns tomoyo_file_test | grep -vF OK | grep -F '(' -newns tomoyo_rewrite_test | grep -vF OK | grep -F '(' -newns tomoyo_new_test | grep -vF OK -echo -echo -echo -echo "Testing policy I/O. (Only ERRORS are reported)" -newns tomoyo_policy_io_test | grep -vF OK -newns tomoyo_new_file_test | grep -vF OK diff --git a/testcases/kernel/security/tomoyo/tomoyo_accept_test.c b/testcases/kernel/security/tomoyo/tomoyo_accept_test.c deleted file mode 100644 index 335818a25..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_accept_test.c +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_accept_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static void set_level(const int i) -{ - set_profile(i, "file::execute"); - set_profile(i, "file::open"); - set_profile(i, "file::create"); - set_profile(i, "file::unlink"); - set_profile(i, "file::mkdir"); - set_profile(i, "file::rmdir"); - set_profile(i, "file::mkfifo"); - set_profile(i, "file::mksock"); - set_profile(i, "file::truncate"); - set_profile(i, "file::symlink"); - set_profile(i, "file::rewrite"); - set_profile(i, "file::mkblock"); - set_profile(i, "file::mkchar"); - set_profile(i, "file::link"); - set_profile(i, "file::rename"); - set_profile(i, "file::chmod"); - set_profile(i, "file::chown"); - set_profile(i, "file::chgrp"); - set_profile(i, "file::ioctl"); - set_profile(i, "file::chroot"); - set_profile(i, "file::mount"); - set_profile(i, "file::umount"); - set_profile(i, "file::pivot_root"); -} - -static void test(int rw_loop, int truncate_loop, int append_loop, - int create_loop) -{ - static const int rw_flags[4] = { 0, O_RDONLY, O_WRONLY, O_RDWR }; - static const int create_flags[3] = { 0, O_CREAT /* nonexistent */ , - O_CREAT /* existent */ - }; - static const int truncate_flags[2] = { 0, O_TRUNC }; - static const int append_flags[2] = { 0, O_APPEND }; - int level; - int flags; - int i; - int fd; - static char buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - snprintf(buffer, sizeof(buffer) - 1, "/tmp/file:a=%d:t=%d:c=%d:m=%d", - append_loop, truncate_loop, create_loop, rw_loop); - fprintf(exception_fp, "deny_rewrite %s\n", buffer); - flags = rw_flags[rw_loop] | truncate_flags[truncate_loop] | - append_flags[append_loop] | create_flags[create_loop]; - for (i = 1; i < 8; i++) - fprintf(domain_fp, "delete %d %s\n", i, buffer); - for (level = 0; level < 4; level++) { - set_level(0); - if (create_loop == 1) - unlink(buffer); - else - close(open(buffer, O_CREAT, 0644)); - set_level(level); - fd = open(buffer, flags, 0644); - if (fd != EOF) - close(fd); - else - fprintf(stderr, "%d: open(%04o) failed\n", level, - flags); - /* - fd = open(buffer, flags, 0644) - if (fd != EOF) - close(fd); - else - fprintf(stderr, "%d: open(%04o) failed\n", level, flags); - */ - /* - fd = open(buffer, flags, 0644); - if (fd != EOF) - close(fd); - else - fprintf(stderr, "%d: open(%04o) failed\n", level, flags); - */ - } - for (i = 1; i < 8; i++) - fprintf(domain_fp, "delete %d %s\n", i, buffer); - fprintf(domain_fp, "delete allow_truncate %s\n", buffer); - fprintf(domain_fp, "delete allow_create %s 0644\n", buffer); - fprintf(domain_fp, "delete allow_rewrite %s\n", buffer); - fd = open(buffer, flags, 0644); - if (fd != EOF) { - close(fd); - fprintf(stderr, "%d: open(%04o) didn't fail\n", 3, flags); - } -} - -int main(void) -{ - tomoyo_test_init(); - fprintf(profile_fp, "255-PREFERENCE::learning={ verbose=no }\n"); - fprintf(profile_fp, "255-PREFERENCE::enforcing={ verbose=no }\n"); - fprintf(profile_fp, "255-PREFERENCE::permissive={ verbose=no }\n"); - fprintf(profile_fp, "255-PREFERENCE::disabled={ verbose=no }\n"); - set_profile(0, "file"); - fprintf(profile_fp, "255-PREFERENCE::learning={ max_entry=2048 }\n"); - { - int append_loop; - for (append_loop = 0; append_loop < 2; append_loop++) { - int truncate_loop; - for (truncate_loop = 0; truncate_loop < 2; - truncate_loop++) { - int create_loop; - for (create_loop = 0; create_loop < 3; - create_loop++) { - int rw_loop; - for (rw_loop = 0; rw_loop < 4; - rw_loop++) - test(rw_loop, truncate_loop, - append_loop, create_loop); - } - } - } - } - fprintf(profile_fp, "255-CONFIG::file=disabled\n"); - printf("Done\n"); - clear_status(); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_file_test.c b/testcases/kernel/security/tomoyo/tomoyo_file_test.c deleted file mode 100644 index 003f47720..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_file_test.c +++ /dev/null @@ -1,304 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_file_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static int should_fail = 0; - -static void show_prompt(const char *str) -{ - printf("Testing %35s: (%s) ", str, - should_fail ? "must fail" : "should success"); - errno = 0; -} - -static void show_result(int result) -{ - if (should_fail) { - if (result == EOF) { - if (errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("FAILED: %s\n", strerror(errno)); - } else { - printf("BUG!\n"); - } - } else { - if (result != EOF) - printf("OK\n"); - else - printf("%s\n", strerror(errno)); - } -} - -static const char *dev_null_path = "/dev/null"; -static const char *truncate_path = "/tmp/truncate_test"; -static const char *ftruncate_path = "/tmp/ftruncate_test"; -static const char *open_creat_path = "/tmp/open_test"; -static const char *mknod_reg_path = "/tmp/mknod_reg_test"; -static const char *mknod_chr_path = "/tmp/mknod_chr_test"; -static const char *mknod_blk_path = "/tmp/mknod_blk_test"; -static const char *mknod_fifo_path = "/tmp/mknod_fifo_test"; -static const char *mknod_sock_path = "/tmp/mknod_sock_test"; -static const char *unlink_path = "/tmp/unlink_test"; -static const char *mkdir_path = "/tmp/mkdir_test"; -static const char *rmdir_path = "/tmp/rmdir_test"; -static const char *link_source_path = "/tmp/link_source_test"; -static const char *link_dest_path = "/tmp/link_dest_test"; -static const char *symlink_source_path = "/tmp/symlink_source_test"; -static const char *symlink_dest_path = "/tmp/symlink_dest_test"; -static const char *rename_source_path = "/tmp/rename_source_test"; -static const char *rename_dest_path = "/tmp/rename_dest_test"; -static const char *socket_path = "/tmp/socket_test"; - -static int ftruncate_fd = EOF; - -static void stage_file_test(void) -{ - int fd; - { - const char buffer[] = "32768 61000"; - show_prompt("sysctl(READ)"); - show_result(read_sysctl(TEST_SYSCTL_PATH, NULL, 0)); - show_prompt("sysctl(WRITE)"); - show_result(write_sysctl(TEST_SYSCTL_PATH, buffer)); - } - - /* QUESTION: Is there a file which can be passed to uselib()? */ - show_prompt("uselib()"); - show_result(uselib("/bin/true")); - - { - int pipe_fd[2] = { EOF, EOF }; - int error = 0; - fflush(stdout); - fflush(stderr); - if (pipe(pipe_fd) == -1) - err(1, "pipe"); - if (fork() == 0) { - execl("/bin/true", "/bin/true", NULL); - if (write(pipe_fd[1], &errno, sizeof(errno)) == -1) - err(1, "write"); - _exit(0); - } - close(pipe_fd[1]); - (void)read(pipe_fd[0], &error, sizeof(error)); - show_prompt("execve()"); - errno = error; - show_result(error ? EOF : 0); - } - - show_prompt("open(O_RDONLY)"); - fd = open(dev_null_path, O_RDONLY); - show_result(fd); - if (fd != EOF) - close(fd); - - show_prompt("open(O_WRONLY)"); - fd = open(dev_null_path, O_WRONLY); - show_result(fd); - if (fd != EOF) - close(fd); - - show_prompt("open(O_RDWR)"); - fd = open(dev_null_path, O_RDWR); - show_result(fd); - if (fd != EOF) - close(fd); - - show_prompt("open(O_CREAT | O_EXCL)"); - fd = open(open_creat_path, O_CREAT | O_EXCL, 0666); - show_result(fd); - if (fd != EOF) - close(fd); - - show_prompt("open(O_TRUNC)"); - fd = open(truncate_path, O_TRUNC); - show_result(fd); - if (fd != EOF) - close(fd); - - show_prompt("truncate()"); - show_result(truncate(truncate_path, 0)); - - show_prompt("ftruncate()"); - show_result(ftruncate(ftruncate_fd, 0)); - - show_prompt("mknod(S_IFREG)"); - show_result(mknod(mknod_reg_path, S_IFREG, 0)); - - show_prompt("mknod(S_IFCHR)"); - show_result(mknod(mknod_chr_path, S_IFCHR, MKDEV(1, 3))); - - show_prompt("mknod(S_IFBLK)"); - show_result(mknod(mknod_blk_path, S_IFBLK, MKDEV(1, 0))); - - show_prompt("mknod(S_IFIFO)"); - show_result(mknod(mknod_fifo_path, S_IFIFO, 0)); - - show_prompt("mknod(S_IFSOCK)"); - show_result(mknod(mknod_sock_path, S_IFSOCK, 0)); - - show_prompt("mkdir()"); - show_result(mkdir(mkdir_path, 0600)); - - show_prompt("rmdir()"); - show_result(rmdir(rmdir_path)); - - show_prompt("unlink()"); - show_result(unlink(unlink_path)); - - show_prompt("symlink()"); - show_result(symlink(symlink_dest_path, symlink_source_path)); - - show_prompt("link()"); - show_result(link(link_source_path, link_dest_path)); - - show_prompt("rename()"); - show_result(rename(rename_source_path, rename_dest_path)); - - { - struct sockaddr_un addr; - int fd; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); - fd = socket(AF_UNIX, SOCK_STREAM, 0); - show_prompt("unix_bind()"); - show_result(bind(fd, (struct sockaddr *)&addr, sizeof(addr))); - if (fd != EOF) - close(fd); - } - - printf("\n\n"); -} - -static void create_files(void) -{ - mkdir(rmdir_path, 0700); - close(creat(link_source_path, 0600)); - close(creat(rename_source_path, 0600)); - close(creat(truncate_path, 0600)); - close(creat(unlink_path, 0600)); - ftruncate_fd = open(ftruncate_path, O_WRONLY | O_CREAT, 0600); -} - -static void creanup_files(void) -{ - if (ftruncate_fd != EOF) - close(ftruncate_fd); - ftruncate_fd = EOF; - unlink(open_creat_path); - unlink(mknod_reg_path); - unlink(mknod_chr_path); - unlink(mknod_blk_path); - unlink(mknod_fifo_path); - unlink(mknod_sock_path); - rmdir(mkdir_path); - unlink(symlink_source_path); - unlink(symlink_dest_path); - unlink(link_source_path); - unlink(link_dest_path); - unlink(rename_source_path); - unlink(rename_dest_path); - unlink(truncate_path); - unlink(ftruncate_path); - unlink(socket_path); -} - -static void set_file_enforce(int enforce) -{ - if (enforce) { - set_profile(3, "file::execute"); - set_profile(3, "file::open"); - set_profile(3, "file::create"); - set_profile(3, "file::unlink"); - set_profile(3, "file::mkdir"); - set_profile(3, "file::rmdir"); - set_profile(3, "file::mkfifo"); - set_profile(3, "file::mksock"); - set_profile(3, "file::truncate"); - set_profile(3, "file::symlink"); - set_profile(3, "file::rewrite"); - set_profile(3, "file::mkblock"); - set_profile(3, "file::mkchar"); - set_profile(3, "file::link"); - set_profile(3, "file::rename"); - set_profile(3, "file::chmod"); - set_profile(3, "file::chown"); - set_profile(3, "file::chgrp"); - set_profile(3, "file::ioctl"); - set_profile(3, "file::chroot"); - set_profile(3, "file::mount"); - set_profile(3, "file::umount"); - set_profile(3, "file::pivot_root"); - } else { - set_profile(0, "file::execute"); - set_profile(0, "file::open"); - set_profile(0, "file::create"); - set_profile(0, "file::unlink"); - set_profile(0, "file::mkdir"); - set_profile(0, "file::rmdir"); - set_profile(0, "file::mkfifo"); - set_profile(0, "file::mksock"); - set_profile(0, "file::truncate"); - set_profile(0, "file::symlink"); - set_profile(0, "file::rewrite"); - set_profile(0, "file::mkblock"); - set_profile(0, "file::mkchar"); - set_profile(0, "file::link"); - set_profile(0, "file::rename"); - set_profile(0, "file::chmod"); - set_profile(0, "file::chown"); - set_profile(0, "file::chgrp"); - set_profile(0, "file::ioctl"); - set_profile(0, "file::chroot"); - set_profile(0, "file::mount"); - set_profile(0, "file::umount"); - set_profile(0, "file::pivot_root"); - } -} - -int main(void) -{ - tomoyo_test_init(); - - printf("***** Testing file hooks in enforce mode. *****\n"); - create_files(); - should_fail = 1; - set_file_enforce(1); - stage_file_test(); - set_file_enforce(0); - clear_status(); - creanup_files(); - - printf("***** Testing file hooks in permissive mode. *****\n"); - should_fail = 0; - create_files(); - set_file_enforce(0); - stage_file_test(); - creanup_files(); - - clear_status(); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_filesystem_test.c b/testcases/kernel/security/tomoyo/tomoyo_filesystem_test.c deleted file mode 100644 index e6e3bb087..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_filesystem_test.c +++ /dev/null @@ -1,633 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_filesystem_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#define _GNU_SOURCE -#include "include.h" - -static void show_prompt(const char *str, const int should_fail) -{ - printf("Testing %60s: (%s) ", str, - should_fail ? "must fail" : "should success"); - errno = 0; -} - -#ifndef MS_MOVE -#define MS_MOVE 8192 -#endif - -static const char *pivot_root_dir = "/sys/kernel/security/"; - -static int child(void *arg) -{ - errno = 0; - pivot_root(pivot_root_dir, proc_policy_dir); - return errno; -} - -static void mount2(const char *source, const char *target, - const char *filesystemtype) -{ - if (mount(source, target, filesystemtype, 0, NULL)) { - printf("BUG: mount() failed\n"); - fflush(stdout); - } -} - -static const unsigned char compressed_ext2_image_sample[1350] = { - 0x1F, 0x8B, 0x08, 0x00, 0xA8, 0xF2, 0x96, 0x4B, 0x02, 0x03, 0xED, 0xDC, - 0x3D, 0x4B, 0x5B, 0x51, 0x18, 0x07, 0xF0, 0xE7, 0xDE, 0xAB, 0x14, 0x8C, - 0xAB, 0xD5, 0x9A, 0xF8, 0x36, 0x0B, 0xA1, 0xE0, 0xE0, 0xDC, 0xD0, 0xAD, - 0xD0, 0xC5, 0xAF, 0x50, 0x9C, 0x42, 0x1D, 0x6A, 0xE6, 0xA6, 0x9B, 0x9B, - 0x8B, 0xD8, 0xA5, 0x5B, 0x97, 0x2E, 0xF9, 0x0E, 0x85, 0x4C, 0xF6, 0x23, - 0x74, 0x70, 0x55, 0x28, 0x52, 0xA8, 0xDD, 0xED, 0xB9, 0xB9, 0xB1, 0xA6, - 0xEA, 0x24, 0xA5, 0x81, 0xDE, 0xDF, 0x0F, 0x9E, 0xDC, 0xB7, 0x13, 0x2E, - 0xF7, 0xC0, 0xFF, 0x70, 0xCE, 0x85, 0x24, 0x02, 0xA8, 0xAB, 0x7E, 0xF9, - 0x31, 0x13, 0xB1, 0x95, 0x36, 0xA7, 0x45, 0x44, 0x2F, 0x6D, 0xB3, 0xC9, - 0x06, 0xEB, 0x55, 0xF5, 0xC7, 0x87, 0x9F, 0x7E, 0x1C, 0xBF, 0x88, 0x68, - 0xC5, 0xCE, 0xF7, 0x6C, 0xD4, 0x6E, 0x74, 0xFC, 0xF2, 0x62, 0x74, 0xED, - 0xFA, 0x7B, 0x8D, 0xB8, 0x69, 0x9F, 0x8F, 0xCF, 0x9F, 0x1D, 0x7E, 0x78, - 0xF7, 0x6D, 0xD8, 0x79, 0xFF, 0x71, 0xD0, 0xED, 0xBC, 0xCD, 0x9A, 0xBD, - 0x69, 0x3C, 0xEB, 0xE0, 0xCB, 0xF0, 0xA4, 0xF9, 0xF5, 0xF9, 0xCA, 0xE0, - 0xE0, 0x72, 0xBB, 0x7B, 0xD4, 0x1A, 0xE6, 0x13, 0xD7, 0xAA, 0xE7, 0x82, - 0x7A, 0x29, 0xAA, 0xF8, 0xC7, 0xEC, 0x28, 0xFF, 0xBD, 0xC8, 0x75, 0x09, - 0xD4, 0xC6, 0x55, 0x92, 0x4D, 0x71, 0xFA, 0x71, 0x05, 0x4C, 0xCF, 0xA3, - 0xBB, 0xE3, 0x01, 0x50, 0x0F, 0x93, 0xEB, 0xDF, 0xEB, 0xFA, 0x97, 0x13, - 0x80, 0x8B, 0x67, 0xD5, 0x02, 0xE4, 0xEE, 0xFD, 0x8B, 0x3F, 0xD6, 0x22, - 0x0B, 0xA6, 0x6A, 0xC0, 0x5F, 0xF6, 0xB9, 0x1C, 0x7F, 0x9E, 0xDE, 0x37, - 0xFE, 0xE4, 0xB1, 0x34, 0xD1, 0xEE, 0x71, 0xAA, 0xC5, 0x54, 0xE5, 0xB9, - 0x27, 0xA9, 0x96, 0x53, 0x35, 0xA3, 0x7C, 0x13, 0x1A, 0xB1, 0x92, 0x6A, - 0x35, 0xD5, 0xDA, 0xF8, 0x75, 0xE9, 0x86, 0x6E, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x81, - 0xCA, 0xDF, 0xD8, 0xCF, 0x47, 0x96, 0xB7, 0x7F, 0xEF, 0xE7, 0x79, 0xBB, - 0x5D, 0xFD, 0x87, 0xDF, 0x79, 0x31, 0x97, 0x77, 0xF7, 0xDE, 0xEC, 0x6F, - 0xEE, 0xEE, 0xF5, 0x5E, 0xBF, 0xD2, 0x57, 0xF0, 0xBF, 0x69, 0xDC, 0xCA, - 0xFF, 0xCF, 0xA2, 0xCA, 0x3F, 0x50, 0x13, 0x33, 0xBA, 0x00, 0xE4, 0x1F, - 0x90, 0x7F, 0x40, 0xFE, 0x01, 0xF9, 0x07, 0xE4, 0x1F, 0x90, 0x7F, 0x40, - 0xFE, 0x01, 0xF9, 0x07, 0xE4, 0x1F, 0x90, 0x7F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFA, 0xF9, 0x05, 0x34, 0xF2, - 0x14, 0x08, 0x00, 0x00, 0x10, 0x00 -}; - -int main(void) -{ - char c = 0; - tomoyo_test_init(); - - /* Test mount(). */ - { - set_profile(3, "file::mount"); - show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 1); - if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF && - errno == EPERM) - printf("OK: Permission denied.\n"); - else if (errno == ENODEV) - printf("OK: No such device.\n"); - else - printf("BUG: %s\n", strerror(errno)); - set_profile(1, "file::mount"); - show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 0); - if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF && - errno == ENOMEM) - printf("OK: Out of memory.\n"); - else if (errno == ENODEV) - printf("OK: No such device.\n"); - else - printf("BUG: %s\n", strerror(errno)); - set_profile(3, "file::mount"); - show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 0); - if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF && - errno == ENOMEM) - printf("OK: Out of memory.\n"); - else if (errno == ENODEV) - printf("OK: No such device.\n"); - else - printf("BUG: %s\n", strerror(errno)); - fprintf(domain_fp, "delete allow_mount dev\\011name / " - "fs\\011name 0\n"); - show_prompt("mount('dev\\011name', '/', 'fs\\011name') ", 1); - if (mount("dev\tname", "/", "fs\tname", 0, NULL) == EOF && - errno == EPERM) - printf("OK: Permission denied.\n"); - else if (errno == ENODEV) - printf("OK: No such device.\n"); - else - printf("BUG: %s\n", strerror(errno)); - set_profile(1, "file::mount"); - show_prompt("mount(NULL, '/', 'tmpfs') ", 0); - if (mount(NULL, "/", "tmpfs", 0, NULL)) - printf("BUG: %s\n", strerror(errno)); - else - printf("OK: Success\n"); - set_profile(3, "file::mount"); - show_prompt("mount(NULL, '/', 'tmpfs') ", 0); - if (mount(NULL, "/", "tmpfs", 0, NULL)) - printf("BUG: %s\n", strerror(errno)); - else - printf("OK: Success\n"); - show_prompt("mount('anydev', '/', 'tmpfs') ", 0); - if (mount("anydev", "/", "tmpfs", 0, NULL)) - printf("BUG: %s\n", strerror(errno)); - else - printf("OK: Success\n"); - fprintf(domain_fp, "delete allow_mount <NULL> / tmpfs 0\n"); - fprintf(domain_fp, "allow_mount anydev / tmpfs 0\n"); - show_prompt("mount(NULL, '/', 'tmpfs') ", 0); - if (mount(NULL, "/", "tmpfs", 0, NULL)) - printf("BUG: %s\n", strerror(errno)); - else - printf("OK: Success\n"); - fprintf(domain_fp, "delete allow_mount anydev / tmpfs 0\n"); - set_profile(2, "file::mount"); - show_prompt("mount(NULL, NULL, 'tmpfs') ", 1); - if (mount(NULL, NULL, "tmpfs", 0, NULL)) - printf("OK: %s\n", strerror(errno)); - else - printf("BUG: Did not fail.\n"); - show_prompt("mount(NULL, NULL, NULL) ", 1); - if (mount(NULL, NULL, NULL, 0, NULL)) - printf("OK: %s\n", strerror(errno)); - else - printf("BUG: Did not fail.\n"); - show_prompt("mount('/', NULL, NULL) ", 1); - if (mount("/", NULL, NULL, 0, NULL)) - printf("OK: %s\n", strerror(errno)); - else - printf("BUG: Did not fail.\n"); - show_prompt("mount('/', NULL, 'tmpfs') ", 1); - if (mount("/", NULL, "tmpfs", 0, NULL)) - printf("OK: %s\n", strerror(errno)); - else - printf("BUG: Did not fail.\n"); - show_prompt("mount('/', '/', 'nonexistentfs') ", 1); - if (mount("/", "/", "nonexistentfs", 0, NULL)) - printf("OK: %s\n", strerror(errno)); - else - printf("BUG: Did not fail.\n"); - set_profile(0, "file::mount"); - } - - mkdir("/tmp/mount/", 0755); - mkdir("/tmp/mount_bind/", 0755); - mkdir("/tmp/mount_move/", 0755); - - /* Test mount(). */ - { - static char buf[4096]; - char *dev_ram_path = realpath("/dev/ram0", NULL); - if (!dev_ram_path) - dev_ram_path = realpath("/dev/ram", NULL); - if (!dev_ram_path) { - dev_ram_path = "/dev/ram0"; - mknod(dev_ram_path, S_IFBLK, MKDEV(1, 0)); - } - memset(buf, 0, sizeof(buf)); - { - struct stat sbuf; - FILE *fp = NULL; - snprintf(buf, sizeof(buf) - 1, "zcat - > %s", - dev_ram_path); - if (lstat(dev_ram_path, &sbuf) == 0 && - S_ISBLK(sbuf.st_mode) && MAJOR(sbuf.st_rdev) == 1) - fp = popen(buf, "w"); - if (fp) { - if (fwrite(compressed_ext2_image_sample, 1, - sizeof(compressed_ext2_image_sample), - fp) != - sizeof(compressed_ext2_image_sample)) - err(1, "fwrite"); - pclose(fp); - } else - fprintf(stderr, "Can't write to %s .\n", - dev_ram_path); - } - set_profile(3, "file::mount"); - - /* Test standard case */ - show_prompt("mount('none', '/tmp/mount/', 'tmpfs') for " - "'/tmp/mount/'", 1); - if (mount("none", "/tmp/mount/", "tmpfs", 0, NULL) == EOF && - errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - /* Test device_name with pattern */ - snprintf(buf, sizeof(buf) - 1, "mount('%s', '/tmp/mount/', " - "'ext2') for '%s\\*'", dev_ram_path, dev_ram_path); - show_prompt(buf, 1); - if (mount(dev_ram_path, "/tmp/mount/", "ext2", MS_RDONLY, NULL) - == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - /* Test dir_name with pattern */ - show_prompt("mount('none', '/tmp/mount/', 'tmpfs') for " - "'/tmp/\\?\\?\\?\\?\\?/'", 1); - if (mount("none", "/tmp/mount/", "tmpfs", 0, NULL) == EOF && - errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - /* Test standard case */ - fprintf(domain_fp, "allow_mount none /tmp/mount/ tmpfs 0\n"); - show_prompt("mount('none', '/tmp/mount/', 'tmpfs') for " - "'/tmp/mount/'", 0); - if (mount("none", "/tmp/mount/", "tmpfs", 0, NULL) == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fprintf(domain_fp, - "delete allow_mount none /tmp/mount/ tmpfs 0\n"); - - /* Test device_name with pattern */ - fprintf(domain_fp, "allow_mount %s\\* /tmp/mount/ ext2 1\n", - dev_ram_path); - snprintf(buf, sizeof(buf) - 1, "mount('%s', '/tmp/mount/', " - "'ext2') for '%s\\*'", dev_ram_path, dev_ram_path); - show_prompt(buf, 0); - if (mount(dev_ram_path, "/tmp/mount/", "ext2", MS_RDONLY, NULL) - == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fprintf(domain_fp, "delete allow_mount %s\\* " - "/tmp/mount/ ext2 1\n", dev_ram_path); - - /* Test dir_name with pattern */ - fprintf(domain_fp, - "allow_mount none /tmp/\\?\\?\\?\\?\\?/ tmpfs 0\n"); - show_prompt("mount('none', '/tmp/mount/', 'tmpfs') for " - "'/tmp/\\?\\?\\?\\?\\?/'", 0); - if (mount("none", "/tmp/mount/", "tmpfs", 0, NULL) == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fprintf(domain_fp, "delete allow_mount none " - "/tmp/\\?\\?\\?\\?\\?/ tmpfs 0\n"); - - set_profile(0, "file::mount"); - while (umount("/tmp/mount/") == 0) - c++; /* Dummy. */ - } - - /* Test mount(). */ - { - mount2("none", "/tmp/mount/", "tmpfs"); - set_profile(3, "file::mount"); - - /* Test remount case */ - show_prompt("mount('/tmp/mount/', MS_REMOUNT)", 1); - if (mount("none", "/tmp/mount/", "tmpfs", MS_REMOUNT, NULL) - == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - show_prompt("mount('/tmp/mount/', MS_REMOUNT)", 1); - if (mount(NULL, "/tmp/mount/", NULL, MS_REMOUNT, NULL) == EOF - && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - fprintf(domain_fp, "allow_mount something /tmp/mount/ " - "--remount 0\n"); - show_prompt("mount('/tmp/mount/', MS_REMOUNT)", 0); - if (mount(NULL, "/tmp/mount/", NULL, MS_REMOUNT, NULL)) - printf("BUG: %s\n", strerror(errno)); - else - printf("OK: Success.\n"); - fprintf(domain_fp, "delete allow_mount something /tmp/mount/ " - "--remount 0\n"); - - /* Test bind case */ - show_prompt("mount('/tmp/mount/', '/tmp/mount_bind/', " - "MS_BIND)", 1); - if (mount("/tmp/mount/", "/tmp/mount_bind/", NULL, MS_BIND, - NULL) == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - /* Test move case */ - show_prompt("mount('/tmp/mount/', '/tmp/mount_move/', " - "MS_MOVE)", 1); - if (mount("/tmp/mount/", "/tmp/mount_move/", NULL, MS_MOVE, - NULL) == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - /* Test remount case */ - fprintf(domain_fp, "allow_mount any /tmp/mount/ --remount 0\n"); - show_prompt("mount('/tmp/mount/', MS_REMOUNT)", 0); - if (mount("none", "/tmp/mount/", "tmpfs", MS_REMOUNT, NULL) - == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fprintf(domain_fp, "delete allow_mount any /tmp/mount/ " - "--remount 0\n"); - - /* Test bind case */ - fprintf(domain_fp, - "allow_mount /tmp/mount/ /tmp/mount_bind/ --bind 0\n"); - show_prompt("mount('/tmp/mount/', '/tmp/mount_bind', MS_BIND)", - 0); - if (mount("/tmp/mount/", "/tmp/mount_bind/", NULL, MS_BIND, - NULL) == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - set_profile(0, "file::mount"); - umount("/tmp/mount_bind/"); - fprintf(domain_fp, "delete allow_mount /tmp/mount/ " - "/tmp/mount_bind/ --bind 0\n"); - - /* Test move case */ - set_profile(3, "file::mount"); - fprintf(domain_fp, "allow_unmount /tmp/mount/\n"); - fprintf(domain_fp, "allow_mount /tmp/mount/ /tmp/mount_move/ " - "--move 0\n"); - show_prompt("mount('/tmp/mount/', '/tmp/mount_move/', " - "MS_MOVE)", 0); - if (mount("/tmp/mount/", "/tmp/mount_move/", NULL, MS_MOVE, - NULL) == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - set_profile(0, "file::mount"); - umount("/tmp/mount_move/"); - fprintf(domain_fp, "delete allow_unmount /tmp/mount/\n"); - fprintf(domain_fp, "delete allow_mount /tmp/mount/ " - "/tmp/mount_move/ --move 0\n"); - - while (umount("/tmp/mount/") == 0) - c++; /* Dummy. */ - } - - /* Test umount(). */ - { - /* Test standard case */ - fprintf(domain_fp, "allow_unmount /tmp/mount/\n"); - - set_profile(0, "file::umount"); - mount2("none", "/tmp/mount/", "tmpfs"); - set_profile(3, "file::umount"); - show_prompt("umount('/tmp/mount/') for '/tmp/mount/'", 0); - if (umount("/tmp/mount/") == 0) - printf("OK\n"); - else - printf("BUG: %s\n", strerror(errno)); - fprintf(domain_fp, "delete allow_unmount /tmp/mount/\n"); - - set_profile(0, "file::umount"); - - mount2("none", "/tmp/mount/", "tmpfs"); - set_profile(3, "file::umount"); - show_prompt("umount('/tmp/mount/') for '/tmp/mount/'", 1); - if (umount("/tmp/mount/") == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("FAILED: %s\n", strerror(errno)); - - /* Test pattern */ - fprintf(domain_fp, "allow_unmount /tmp/\\?\\?\\?\\?\\?/\n"); - set_profile(0, "file::umount"); - mount2("none", "/tmp/mount/", "tmpfs"); - set_profile(3, "file::umount"); - show_prompt("umount('/tmp/mount/') for " - "'/tmp/\\?\\?\\?\\?\\?/'", 1); - if (umount("/tmp/mount/") == 0) - printf("OK\n"); - else - printf("BUG: %s\n", strerror(errno)); - fprintf(domain_fp, - "delete allow_unmount /tmp/\\?\\?\\?\\?\\?/\n"); - - set_profile(0, "file::umount"); - while (umount("/tmp/mount/") == 0) - c++; /* Dummy. */ - } - - /* Test chroot(). */ - { - set_profile(3, "file::chroot"); - - /* Test standard case */ - fprintf(domain_fp, "allow_chroot /tmp/mount/\n"); - show_prompt("chroot('/tmp/mount/') for '/tmp/mount/'", 0); - fflush(stdout); - if (fork() == 0) { - if (chroot("/tmp/mount/") == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fflush(stdout); - _exit(0); - } - wait(NULL); - fprintf(domain_fp, "delete allow_chroot /tmp/mount/\n"); - - show_prompt("chroot('/tmp/mount/') for '/tmp/mount/'", 1); - fflush(stdout); - if (fork() == 0) { - if (chroot("/tmp/mount/") == EOF && errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - fflush(stdout); - _exit(0); - } - wait(NULL); - - /* Test pattern */ - fprintf(domain_fp, "allow_chroot /tmp/\\?\\?\\?\\?\\?/\n"); - show_prompt("chroot('/tmp/mount/') for " - "'/tmp/\\?\\?\\?\\?\\?/'", 0); - fflush(stdout); - if (fork() == 0) { - if (chroot("/tmp/mount/") == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - fflush(stdout); - _exit(0); - } - wait(NULL); - fprintf(domain_fp, - "delete allow_chroot /tmp/\\?\\?\\?\\?\\?/\n"); - - set_profile(0, "file::chroot"); - } - - /* Test pivot_root(). */ - { - int error; - static char stack[8192]; - set_profile(3, "file::pivot_root"); - fprintf(domain_fp, "allow_pivot_root %s %s\n", - pivot_root_dir, proc_policy_dir); - snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir, - proc_policy_dir); - show_prompt(stack, 0); - { - const pid_t pid = ltp_clone_quick(CLONE_NEWNS, child, - NULL); - while (waitpid(pid, &error, __WALL) == EOF && - errno == EINTR) - c++; /* Dummy. */ - } - errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1; - if (errno == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - - fprintf(domain_fp, "delete allow_pivot_root %s %s\n", - pivot_root_dir, proc_policy_dir); - snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir, - proc_policy_dir); - show_prompt(stack, 1); - { - const pid_t pid = ltp_clone_quick(CLONE_NEWNS, child, - NULL); - while (waitpid(pid, &error, __WALL) == EOF && - errno == EINTR) - c++; /* Dummy. */ - } - errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1; - if (errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG: %s\n", strerror(errno)); - - set_profile(2, "file::pivot_root"); - snprintf(stack, 8191, "pivot_root('%s', '%s')", pivot_root_dir, - proc_policy_dir); - show_prompt(stack, 0); - { - const pid_t pid = ltp_clone_quick(CLONE_NEWNS, child, - NULL); - while (waitpid(pid, &error, __WALL) == EOF && - errno == EINTR) - c++; /* Dummy. */ - } - errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1; - if (errno == 0) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(errno)); - - set_profile(0, "file::pivot_root"); - - } - - rmdir("/tmp/mount_move/"); - rmdir("/tmp/mount_bind/"); - rmdir("/tmp/mount/"); - - clear_status(); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_new_file_test.c b/testcases/kernel/security/tomoyo/tomoyo_new_file_test.c deleted file mode 100644 index eb912d726..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_new_file_test.c +++ /dev/null @@ -1,627 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_new_file_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static const char *policy = ""; - -static void show_result(int result, char should_success) -{ - int error = errno; - printf("%s : ", policy); - if (should_success) { - if (result != EOF) - printf("OK\n"); - else - printf("FAILED: %s\n", strerror(error)); - } else { - if (result == EOF) { - if (error == EPERM) - printf("OK: Permission denied.\n"); - else - printf("FAILED: %s\n", strerror(error)); - } else { - printf("BUG: didn't fail.\n"); - } - } -} - -static void create2(const char *pathname) -{ - set_profile(0, "file::create"); - set_profile(0, "file::open"); - close(creat(pathname, 0600)); - set_profile(3, "file::create"); - set_profile(3, "file::open"); - errno = 0; -} - -static void mkdir2(const char *pathname) -{ - set_profile(0, "file::mkdir"); - mkdir(pathname, 0600); - set_profile(3, "file::mkdir"); - errno = 0; -} - -static void unlink2(const char *pathname) -{ - set_profile(0, "file::unlink"); - unlink(pathname); - set_profile(3, "file::unlink"); - errno = 0; -} - -static void rmdir2(const char *pathname) -{ - set_profile(0, "file::rmdir"); - rmdir(pathname); - set_profile(3, "file::rmdir"); - errno = 0; -} - -static void mkfifo2(const char *pathname) -{ - set_profile(0, "file::mkfifo"); - mkfifo(pathname, 0600); - set_profile(3, "file::mkfifo"); - errno = 0; -} - -static void stage_file_test(void) -{ - const char buffer[] = "32768 61000"; - int pipe_fd[2] = { EOF, EOF }; - int error = 0; - int fd; - char pbuffer[1024]; - struct stat sbuf; - struct sockaddr_un addr; - struct ifreq ifreq; - char *filename = ""; - set_profile(3, "file::execute"); - set_profile(3, "file::open"); - set_profile(3, "file::create"); - set_profile(3, "file::unlink"); - set_profile(3, "file::mkdir"); - set_profile(3, "file::rmdir"); - set_profile(3, "file::mkfifo"); - set_profile(3, "file::mksock"); - set_profile(3, "file::truncate"); - set_profile(3, "file::symlink"); - set_profile(3, "file::rewrite"); - set_profile(3, "file::mkblock"); - set_profile(3, "file::mkchar"); - set_profile(3, "file::link"); - set_profile(3, "file::rename"); - set_profile(3, "file::chmod"); - set_profile(3, "file::chown"); - set_profile(3, "file::chgrp"); - set_profile(3, "file::ioctl"); - set_profile(3, "file::chroot"); - set_profile(3, "file::mount"); - set_profile(3, "file::umount"); - set_profile(3, "file::pivot_root"); - - policy = "allow_read /proc/sys/net/ipv4/ip_local_port_range"; - write_domain_policy(policy, 0); - show_result(read_sysctl(TEST_SYSCTL_PATH, NULL, 0), 1); - write_domain_policy(policy, 1); - show_result(read_sysctl(TEST_SYSCTL_PATH, NULL, 0), 0); - - policy = "allow_write /proc/sys/net/ipv4/ip_local_port_range"; - write_domain_policy(policy, 0); - show_result(write_sysctl(TEST_SYSCTL_PATH, buffer), 1); - write_domain_policy(policy, 1); - show_result(write_sysctl(TEST_SYSCTL_PATH, buffer), 0); - - policy = "allow_read/write /proc/sys/net/ipv4/ip_local_port_range"; - write_domain_policy(policy, 0); - show_result(read_sysctl(TEST_SYSCTL_PATH, NULL, 0) && - write_sysctl(TEST_SYSCTL_PATH, buffer), 1); - write_domain_policy(policy, 1); - show_result(read_sysctl(TEST_SYSCTL_PATH, NULL, 0) && - write_sysctl(TEST_SYSCTL_PATH, buffer), 0); - - policy = "allow_read /bin/true"; - write_domain_policy(policy, 0); - show_result(uselib("/bin/true"), 1); - write_domain_policy(policy, 1); - show_result(uselib("/bin/true"), 0); - - policy = "allow_execute /bin/true"; - write_domain_policy(policy, 0); - fflush(stdout); - fflush(stderr); - if (pipe(pipe_fd) == -1) - err(1, "pipe"); - if (fork() == 0) { - execl("/bin/true", "/bin/true", NULL); - if (write(pipe_fd[1], &errno, sizeof(errno)) == -1) - err(1, "write"); - exit(0); - } - close(pipe_fd[1]); - (void)read(pipe_fd[0], &error, sizeof(error)); - close(pipe_fd[0]); - wait(NULL); - errno = error; - show_result(error ? EOF : 0, 1); - write_domain_policy(policy, 1); - fflush(stdout); - fflush(stderr); - if (pipe(pipe_fd) == -1) - err(1, "pipe"); - if (fork() == 0) { - execl("/bin/true", "/bin/true", NULL); - if (write(pipe_fd[1], &errno, sizeof(errno)) == -1) - err(1, "write"); - _exit(0); - } - close(pipe_fd[1]); - (void)read(pipe_fd[0], &error, sizeof(error)); - close(pipe_fd[0]); - wait(NULL); - errno = error; - show_result(errno ? EOF : 0, 0); - - policy = "allow_read /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - set_profile(3, "file::mkfifo"); - policy = "allow_mkfifo /tmp/mknod_fifo_test 0644"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_fifo_test"; - show_result(mknod(filename, S_IFIFO | 0644, 0), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFIFO | 0644, 0), 0); - - memset(pbuffer, 0, sizeof(pbuffer)); - memset(&sbuf, 0, sizeof(sbuf)); - filename = "/dev/null"; - stat(filename, &sbuf); - snprintf(pbuffer, sizeof(pbuffer) - 1, "allow_write %s", filename); - policy = pbuffer; - write_domain_policy(policy, 0); - fd = open(filename, O_WRONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open(filename, O_WRONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read/write /tmp/fifo"; - mkfifo2("/tmp/fifo"); - write_domain_policy(policy, 0); - fd = open("/tmp/fifo", O_RDWR); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/tmp/fifo", O_RDWR); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_write /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_WRONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_WRONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_read/write /dev/null"; - write_domain_policy(policy, 0); - fd = open("/dev/null", O_RDWR); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open("/dev/null", O_RDWR); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - policy = "allow_create /tmp/open_test 0644"; - write_domain_policy(policy, 0); - policy = "allow_write /tmp/open_test"; - write_domain_policy(policy, 0); - fd = open("/tmp/open_test", O_WRONLY | O_CREAT | O_EXCL, 0644); - show_result(fd, 1); - if (fd != EOF) - close(fd); - unlink2("/tmp/open_test"); - write_domain_policy(policy, 1); - fd = open("/tmp/open_test", O_WRONLY | O_CREAT | O_EXCL, 0644); - show_result(fd, 0); - if (fd != EOF) - close(fd); - unlink2("/tmp/open_test"); - - policy = "allow_create /tmp/open_test 0644"; - write_domain_policy(policy, 1); - - policy = "allow_write /tmp/open_test"; - write_domain_policy(policy, 0); - policy = "allow_create /tmp/open_test 0644"; - write_domain_policy(policy, 0); - fd = open("/tmp/open_test", O_WRONLY | O_CREAT | O_EXCL, 0644); - show_result(fd, 1); - if (fd != EOF) - close(fd); - unlink2("/tmp/open_test"); - write_domain_policy(policy, 1); - fd = open("/tmp/open_test", O_WRONLY | O_CREAT | O_EXCL, 0644); - show_result(fd, 0); - if (fd != EOF) - close(fd); - unlink2("/tmp/open_test"); - policy = "allow_write /tmp/open_test"; - write_domain_policy(policy, 1); - - filename = "/tmp/truncate_test"; - create2(filename); - - policy = "allow_truncate /tmp/truncate_test"; - write_domain_policy(policy, 0); - policy = "allow_write /tmp/truncate_test"; - write_domain_policy(policy, 0); - fd = open(filename, O_WRONLY | O_TRUNC); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open(filename, O_WRONLY | O_TRUNC); - show_result(fd, 0); - if (fd != EOF) - close(fd); - policy = "allow_truncate /tmp/truncate_test"; - write_domain_policy(policy, 1); - - policy = "allow_write /tmp/truncate_test"; - write_domain_policy(policy, 0); - policy = "allow_truncate /tmp/truncate_test"; - write_domain_policy(policy, 0); - fd = open(filename, O_WRONLY | O_TRUNC); - show_result(fd, 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - fd = open(filename, O_WRONLY | O_TRUNC); - show_result(fd, 0); - if (fd != EOF) - close(fd); - policy = "allow_write /tmp/truncate_test"; - write_domain_policy(policy, 1); - - policy = "allow_truncate /tmp/truncate_test"; - write_domain_policy(policy, 0); - show_result(truncate(filename, 0), 1); - write_domain_policy(policy, 1); - show_result(truncate(filename, 0), 0); - - policy = "allow_truncate /tmp/truncate_test"; - write_domain_policy(policy, 0); - set_profile(0, "file::open"); - fd = open(filename, O_WRONLY); - set_profile(3, "file::open"); - show_result(ftruncate(fd, 0), 1); - write_domain_policy(policy, 1); - show_result(ftruncate(fd, 0), 0); - if (fd != EOF) - close(fd); - - unlink2(filename); - - policy = "allow_create /tmp/mknod_reg_test 0644"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_reg_test"; - show_result(mknod(filename, S_IFREG | 0644, 0), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFREG | 0644, 0), 0); - - policy = "allow_mkchar /tmp/mknod_chr_test 0644 1 3"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_chr_test"; - show_result(mknod(filename, S_IFCHR | 0644, MKDEV(1, 3)), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFCHR | 0644, MKDEV(1, 3)), 0); - - policy = "allow_mkblock /tmp/mknod_blk_test 0644 1 0"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_blk_test"; - show_result(mknod(filename, S_IFBLK | 0644, MKDEV(1, 0)), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFBLK | 0644, MKDEV(1, 0)), 0); - - policy = "allow_mkfifo /tmp/mknod_fifo_test 0644"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_fifo_test"; - show_result(mknod(filename, S_IFIFO | 0644, 0), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFIFO | 0644, 0), 0); - - policy = "allow_mksock /tmp/mknod_sock_test 0644"; - write_domain_policy(policy, 0); - filename = "/tmp/mknod_sock_test"; - show_result(mknod(filename, S_IFSOCK | 0644, 0), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(mknod(filename, S_IFSOCK | 0644, 0), 0); - - policy = "allow_mkdir /tmp/mkdir_test/ 0600"; - write_domain_policy(policy, 0); - filename = "/tmp/mkdir_test"; - show_result(mkdir(filename, 0600), 1); - write_domain_policy(policy, 1); - rmdir2(filename); - show_result(mkdir(filename, 0600), 0); - - policy = "allow_rmdir /tmp/rmdir_test/"; - write_domain_policy(policy, 0); - filename = "/tmp/rmdir_test"; - mkdir2(filename); - show_result(rmdir(filename), 1); - write_domain_policy(policy, 1); - mkdir2(filename); - show_result(rmdir(filename), 0); - rmdir2(filename); - - policy = "allow_unlink /tmp/unlink_test"; - write_domain_policy(policy, 0); - filename = "/tmp/unlink_test"; - create2(filename); - show_result(unlink(filename), 1); - write_domain_policy(policy, 1); - create2(filename); - show_result(unlink(filename), 0); - unlink2(filename); - - policy = "allow_symlink /tmp/symlink_source_test"; - write_domain_policy(policy, 0); - filename = "/tmp/symlink_source_test"; - show_result(symlink("/tmp/symlink_dest_test", filename), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(symlink("/tmp/symlink_dest_test", filename), 0); - - policy = "allow_symlink /tmp/symlink_source_test"; - write_domain_policy(policy, 0); - filename = "/tmp/symlink_source_test"; - show_result(symlink("/tmp/symlink_dest_test", filename), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(symlink("/tmp/symlink_dest_test", filename), 0); - - policy = "allow_symlink /tmp/symlink_source_test"; - write_domain_policy(policy, 0); - filename = "/tmp/symlink_source_test"; - show_result(symlink("/tmp/symlink_dest_test", filename), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(symlink("/tmp/symlink_dest_test", filename), 0); - - policy = "allow_symlink /tmp/symlink_source_test"; - write_domain_policy(policy, 0); - filename = "/tmp/symlink_source_test"; - show_result(symlink("/tmp/symlink_dest_test", filename), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(symlink("/tmp/symlink_dest_test", filename), 0); - - policy = "allow_symlink /tmp/symlink_source_test"; - write_domain_policy(policy, 0); - filename = "/tmp/symlink_source_test"; - show_result(symlink("/tmp/symlink_dest_test", filename), 1); - write_domain_policy(policy, 1); - unlink2(filename); - show_result(symlink("/tmp/symlink_dest_test", filename), 0); - - policy = "allow_link /tmp/link_source_test /tmp/link_dest_test"; - write_domain_policy(policy, 0); - filename = "/tmp/link_source_test"; - create2(filename); - show_result(link(filename, "/tmp/link_dest_test"), 1); - write_domain_policy(policy, 1); - unlink2("/tmp/link_dest_test"); - show_result(link(filename, "/tmp/link_dest_test"), 0); - unlink2(filename); - - policy = "allow_rename /tmp/rename_source_test /tmp/rename_dest_test"; - write_domain_policy(policy, 0); - filename = "/tmp/rename_source_test"; - create2(filename); - show_result(rename(filename, "/tmp/rename_dest_test"), 1); - write_domain_policy(policy, 1); - unlink2("/tmp/rename_dest_test"); - create2(filename); - show_result(rename(filename, "/tmp/rename_dest_test"), 0); - unlink2(filename); - - policy = "allow_mksock /tmp/socket_test 0755"; - write_domain_policy(policy, 0); - filename = "/tmp/socket_test"; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, filename, sizeof(addr.sun_path) - 1); - fd = socket(AF_UNIX, SOCK_STREAM, 0); - show_result(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), 1); - if (fd != EOF) - close(fd); - write_domain_policy(policy, 1); - unlink2(filename); - fd = socket(AF_UNIX, SOCK_STREAM, 0); - show_result(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), 0); - if (fd != EOF) - close(fd); - - filename = "/tmp/rewrite_test"; - create2(filename); - policy = "allow_read/write /tmp/rewrite_test"; - write_domain_policy(policy, 0); - write_exception_policy("deny_rewrite /tmp/rewrite_test", 0); - policy = "allow_truncate /tmp/rewrite_test"; - write_domain_policy(policy, 0); - - fd = open(filename, O_RDONLY); - show_result(fd, 1); - if (fd != EOF) - close(fd); - - fd = open(filename, O_WRONLY | O_APPEND); - show_result(fd, 1); - if (fd != EOF) - close(fd); - - fd = open(filename, O_WRONLY); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - fd = open(filename, O_WRONLY | O_TRUNC); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - fd = open(filename, O_WRONLY | O_TRUNC | O_APPEND); - show_result(fd, 0); - if (fd != EOF) - close(fd); - - show_result(truncate(filename, 0), 0); - - set_profile(0, "file::open"); - fd = open(filename, O_WRONLY | O_APPEND); - set_profile(3, "file::open"); - show_result(ftruncate(fd, 0), 0); - - show_result(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_APPEND), 0); - if (fd != EOF) - close(fd); - - write_domain_policy(policy, 1); - - policy = "allow_read/write /tmp/rewrite_test"; - write_domain_policy(policy, 1); - write_exception_policy("deny_rewrite /tmp/rewrite_test", 1); - - unlink2(filename); - - policy = "allow_ioctl socket:[family=2:type=2:protocol=17] " - "35122-35124"; - write_domain_policy(policy, 0); - fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - memset(&ifreq, 0, sizeof(ifreq)); - snprintf(ifreq.ifr_name, sizeof(ifreq.ifr_name) - 1, "lo"); - show_result(ioctl(fd, 35123, &ifreq), 1); - write_domain_policy(policy, 1); - policy = "allow_ioctl " "socket:[family=2:type=2:protocol=17] 0-35122"; - write_domain_policy(policy, 0); - show_result(ioctl(fd, 35123, &ifreq), 0); - write_domain_policy(policy, 1); - if (fd != EOF) - close(fd); -} - -int main(void) -{ - tomoyo_test_init(); - fprintf(domain_fp, "%s /bin/true\n", self_domain); - fprintf(domain_fp, "use_profile 255\n"); - fprintf(domain_fp, "select pid=%u\n", pid); - fprintf(profile_fp, "255-PREFERENCE::audit={ max_reject_log=1024 }\n"); - stage_file_test(); - fprintf(domain_fp, "use_profile 0\n"); - clear_status(); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_new_test.c b/testcases/kernel/security/tomoyo/tomoyo_new_test.c deleted file mode 100644 index a1ab259e5..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_new_test.c +++ /dev/null @@ -1,652 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_new_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static int result; -static int error; - -static void show_result(const char *test, int should_success) -{ - error = errno; - printf("%s : ", test); - if (should_success) { - if (error == 0) - printf("OK (%d)\n", result); - else - printf("FAILED: %s\n", strerror(error)); - } else { - if (error == 0) - printf("BUG: Didn't fail (%d)\n", result); - else if (error == EPERM) - printf("OK: permission denied\n"); - else - printf("FAILED: %s\n", strerror(error)); - } -} - -static void test_read_etc_fstab(void) -{ - result = open("/etc/fstab", O_RDONLY); -} - -static void test_write_dev_null(void) -{ - result = open("/dev/null", O_WRONLY); -} - -static void cleanup_file_open(void) -{ - if (result != EOF) - close(result); -} - -static void test_mkdir_testdir(void) -{ - result = mkdir("/tmp/testdir", 0755); -} - -static void cleanup_mkdir_testdir(void) -{ - rmdir("/tmp/testdir"); -} - -static void setup_mkdir_testdir(void) -{ - mkdir("/tmp/testdir", 0755); -} - -static void test_rmdir_testdir(void) -{ - result = rmdir("/tmp/testdir"); -} - -static void setup_execute_bin_true(void) -{ - fprintf(domain_fp, "%s /bin/true\n", self_domain); - fprintf(domain_fp, "use_profile 0\n"); - fprintf(domain_fp, "select pid=%u\n", pid); -} - -static void cleanup_execute_bin_true(void) -{ - wait(NULL); - fprintf(domain_fp, "delete %s /bin/true\n", self_domain); - fprintf(domain_fp, "select pid=%u\n", pid); -} - -static void test_execute_bin_true(void) -{ - char *argv[] = { "/bin/true", NULL }; - char *envp[] = { "HOME=/", NULL }; - int pipe_fd[2] = { EOF, EOF }; - if (pipe(pipe_fd) == -1) - err(1, "pipe"); - switch (fork()) { - case 0: - execve("/bin/true", argv, envp); - error = errno; - if (write(pipe_fd[1], &error, sizeof(error)) == -1) - err(1, "write"); - _exit(0); - break; - case -1: - error = ENOMEM; - break; - } - close(pipe_fd[1]); - (void)read(pipe_fd[0], &error, sizeof(error)); - close(pipe_fd[0]); - result = error ? EOF : 0; - errno = error; -} - -static void test_chmod_dev_null(void) -{ - result = chmod("/dev/null", 0666); -} - -static void test_chown_dev_null(void) -{ - result = chown("/dev/null", 0, -1); -} - -static void test_chgrp_dev_null(void) -{ - result = chown("/dev/null", -1, 0); -} - -static void test_ioctl_dev_null(void) -{ - int fd = open("/dev/null", O_RDWR); - errno = 0; - result = ioctl(fd, 0x5451, NULL); - error = errno; - close(fd); - errno = error; -} - -static void setup_chmod_group(void) -{ - write_exception_policy("path_group CHMOD_TARGET /dev/null", 0); - write_exception_policy("number_group CHMOD_MODES 0666", 0); -} - -static void cleanup_chmod_group(void) -{ - write_exception_policy("path_group CHMOD_TARGET /dev/null", 1); - write_exception_policy("number_group CHMOD_MODES 0666", 1); -} - -static void setup_chown_group(void) -{ - write_exception_policy("path_group CHOWN_TARGET /dev/\\*", 0); - write_exception_policy("number_group CHOWN_IDS 0x0-0xFFFE", 0); -} - -static void cleanup_chown_group(void) -{ - write_exception_policy("path_group CHOWN_TARGET /dev/\\*", 1); - write_exception_policy("number_group CHOWN_IDS 0x0-0xFFFE", 1); -} - -static void setup_ioctl_group(void) -{ - write_exception_policy("path_group IOCTL_TARGET /dev/\\*", 0); - write_exception_policy("number_group IOCTL_NUMBERS 0x5450-0x5452", 0); -} - -static void cleanup_ioctl_group(void) -{ - write_exception_policy("path_group IOCTL_TARGET /dev/\\*", 1); - write_exception_policy("number_group IOCTL_NUMBERS 0x5450-0x5452", 1); -} - -static void setup_open_group(void) -{ - write_exception_policy("path_group READABLE /etc/\\*", 0); - write_exception_policy("number_group READABLE_IDS 0-0xFFF", 0); -} - -static void cleanup_open_group(void) -{ - cleanup_file_open(); - write_exception_policy("path_group READABLE /etc/\\*", 1); - write_exception_policy("number_group READABLE_IDS 0-0xFFF", 1); -} - -static void test_file_open_0(void) -{ - result = open("/tmp/testfile0", O_RDONLY, 0600); -} - -static void test_file_open_1(void) -{ - result = open("/tmp/testfile1", O_CREAT | O_RDONLY, 0600); -} - -static void test_file_open_2(void) -{ - result = open("/tmp/testfile2", O_TRUNC | O_RDONLY, 0600); -} - -static void test_file_open_3(void) -{ - result = open("/tmp/testfile3", O_TRUNC | O_CREAT | O_RDONLY, 0600); -} - -static void test_file_open_4(void) -{ - result = open("/tmp/testfile4", O_APPEND | O_RDONLY, 0600); -} - -static void test_file_open_5(void) -{ - result = open("/tmp/testfile5", O_APPEND | O_CREAT | O_RDONLY, 0600); -} - -static void test_file_open_6(void) -{ - result = open("/tmp/testfile6", O_APPEND | O_TRUNC | O_RDONLY, 0600); -} - -static void test_file_open_7(void) -{ - result = open("/tmp/testfile7", - O_APPEND | O_TRUNC | O_CREAT | O_RDONLY, 0600); -} - -static void test_file_open_8(void) -{ - result = open("/tmp/testfile8", O_WRONLY, 0600); -} - -static void test_file_open_9(void) -{ - result = open("/tmp/testfile9", O_CREAT | O_WRONLY, 0600); -} - -static void test_file_open_10(void) -{ - result = open("/tmp/testfile10", O_TRUNC | O_WRONLY, 0600); -} - -static void test_file_open_11(void) -{ - result = open("/tmp/testfile11", O_TRUNC | O_CREAT | O_WRONLY, 0600); -} - -static void test_file_open_12(void) -{ - result = open("/tmp/testfile12", O_APPEND | O_WRONLY, 0600); -} - -static void test_file_open_13(void) -{ - result = open("/tmp/testfile13", O_APPEND | O_CREAT | O_WRONLY, 0600); -} - -static void test_file_open_14(void) -{ - result = open("/tmp/testfile14", O_APPEND | O_TRUNC | O_WRONLY, 0600); -} - -static void test_file_open_15(void) -{ - result = open("/tmp/testfile15", - O_APPEND | O_TRUNC | O_CREAT | O_WRONLY, 0600); -} - -static void test_file_open_16(void) -{ - result = open("/tmp/testfile16", O_RDWR, 0600); -} - -static void test_file_open_17(void) -{ - result = open("/tmp/testfile17", O_CREAT | O_RDWR, 0600); -} - -static void test_file_open_18(void) -{ - result = open("/tmp/testfile18", O_TRUNC | O_RDWR, 0600); -} - -static void test_file_open_19(void) -{ - result = open("/tmp/testfile19", O_TRUNC | O_CREAT | O_RDWR, 0600); -} - -static void test_file_open_20(void) -{ - result = open("/tmp/testfile20", O_APPEND | O_RDWR, 0600); -} - -static void test_file_open_21(void) -{ - result = open("/tmp/testfile21", O_APPEND | O_CREAT | O_RDWR, 0600); -} - -static void test_file_open_22(void) -{ - result = open("/tmp/testfile22", O_APPEND | O_TRUNC | O_RDWR, 0600); -} - -static void test_file_open_23(void) -{ - result = open("/tmp/testfile23", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, - 0600); -} - -static void setup_test_file(void) -{ - int i; - char buffer[32]; - buffer[31] = '\0'; - for (i = 0; i < 24; i += 2) { - snprintf(buffer, sizeof(buffer) - 1, "/tmp/testfile%u", i); - close(open(buffer, O_WRONLY | O_CREAT, 0600)); - } - write_exception_policy("deny_rewrite /tmp/testfile\\$", 0); -} - -static void setup_test_file_truncate(void) -{ - setup_test_file(); - write_domain_policy("allow_truncate /tmp/testfile\\$", 0); - set_profile(3, "file::truncate"); -} - -static void setup_all_test_file(void) -{ - int i; - char buffer[32]; - buffer[31] = '\0'; - for (i = 0; i < 24; i++) { - snprintf(buffer, sizeof(buffer) - 1, "/tmp/testfile%u", i); - close(open(buffer, O_WRONLY | O_CREAT, 0600)); - } - write_exception_policy("deny_rewrite /tmp/testfile\\$", 0); -} - -static void setup_all_test_file_truncate(void) -{ - setup_all_test_file(); - write_domain_policy("allow_truncate /tmp/testfile\\$", 0); - set_profile(3, "file::truncate"); -} - -static void cleanup_test_file(void) -{ - int i; - char buffer[32]; - buffer[31] = '\0'; - for (i = 0; i < 24; i++) { - snprintf(buffer, sizeof(buffer) - 1, "/tmp/testfile%u", i); - unlink(buffer); - } - write_exception_policy("deny_rewrite /tmp/testfile\\$", 1); - cleanup_file_open(); -} - -static void cleanup_test_file_truncate(void) -{ - cleanup_test_file(); - write_domain_policy("allow_truncate /tmp/testfile\\$", 1); - set_profile(0, "file::truncate"); -} - -static struct test_struct { - void (*do_setup) (void); - void (*do_test) (void); - void (*do_cleanup) (void); - const char *name; - const char *policy; -} tests[] = { - { - NULL, test_read_etc_fstab, cleanup_file_open, "file::open", - "allow_read /etc/fstab"}, { - NULL, test_read_etc_fstab, cleanup_file_open, "file::open", - "allow_read /etc/fstab"}, { - NULL, test_read_etc_fstab, cleanup_file_open, "file::open", - "allow_read /etc/fstab"}, { - setup_open_group, test_read_etc_fstab, cleanup_open_group, - "file::open", "allow_read @READABLE"}, { - NULL, test_write_dev_null, cleanup_file_open, "file::open", - "allow_write /dev/null"}, { - NULL, test_write_dev_null, cleanup_file_open, "file::open", - "allow_write /dev/null"}, { - NULL, test_write_dev_null, cleanup_file_open, "file::open", - "allow_write /dev/null"}, { - cleanup_mkdir_testdir, test_mkdir_testdir, - cleanup_mkdir_testdir, "file::mkdir", - "allow_mkdir /tmp/testdir/ 0755"}, { - cleanup_mkdir_testdir, test_mkdir_testdir, - cleanup_mkdir_testdir, "file::mkdir", - "allow_mkdir /tmp/testdir/ 0755"}, { - cleanup_mkdir_testdir, test_mkdir_testdir, - cleanup_mkdir_testdir, "file::mkdir", - "allow_mkdir /tmp/testdir/ 0755"}, { - setup_mkdir_testdir, test_rmdir_testdir, cleanup_mkdir_testdir, - "file::rmdir", "allow_rmdir /tmp/testdir/"}, { - setup_mkdir_testdir, test_rmdir_testdir, cleanup_mkdir_testdir, - "file::rmdir", "allow_rmdir /tmp/testdir/"}, { - setup_mkdir_testdir, test_rmdir_testdir, cleanup_mkdir_testdir, - "file::rmdir", "allow_rmdir /tmp/testdir/"}, { - setup_execute_bin_true, test_execute_bin_true, - cleanup_execute_bin_true, "file::execute", - "allow_execute /bin/true"}, { - setup_execute_bin_true, test_execute_bin_true, - cleanup_execute_bin_true, "file::execute", - "allow_execute /bin/true"}, { - setup_execute_bin_true, test_execute_bin_true, - cleanup_execute_bin_true, "file::execute", - "allow_execute /bin/true"}, { - NULL, test_chmod_dev_null, NULL, "file::chmod", - "allow_chmod /dev/null 0666"}, { - NULL, test_chown_dev_null, NULL, "file::chown", - "allow_chown /dev/null 0"}, { - NULL, test_chgrp_dev_null, NULL, "file::chgrp", - "allow_chgrp /dev/null 0"}, { - NULL, test_ioctl_dev_null, NULL, "file::ioctl", - "allow_ioctl /dev/null 0x5451"}, { - setup_chmod_group, test_chmod_dev_null, cleanup_chmod_group, - "file::chmod", "allow_chmod @CHMOD_TARGET @CHMOD_MODES"}, { - setup_chown_group, test_chown_dev_null, cleanup_chown_group, - "file::chown", "allow_chown @CHOWN_TARGET @CHOWN_IDS"}, { - setup_chown_group, test_chgrp_dev_null, cleanup_chown_group, - "file::chgrp", "allow_chgrp @CHOWN_TARGET @CHOWN_IDS"}, { - setup_ioctl_group, test_ioctl_dev_null, cleanup_ioctl_group, - "file::ioctl", "allow_ioctl @IOCTL_TARGET @IOCTL_NUMBERS"}, - { - setup_test_file, test_file_open_0, cleanup_test_file, - "file::open", "allow_read /tmp/testfile0"}, { - setup_test_file, test_file_open_1, cleanup_test_file, - "file::open", "allow_read /tmp/testfile1"}, { - setup_test_file, test_file_open_1, cleanup_test_file, - "file::create", "allow_create /tmp/testfile1 0600"}, { - setup_test_file, test_file_open_2, cleanup_test_file, - "file::open", "allow_read /tmp/testfile2"}, { - setup_test_file, test_file_open_2, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile2"}, { - setup_test_file_truncate, test_file_open_2, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile2"}, { - setup_test_file, test_file_open_3, cleanup_test_file, - "file::open", "allow_read /tmp/testfile3"}, { - setup_test_file, test_file_open_3, cleanup_test_file, - "file::create", "allow_create /tmp/testfile3 0600"}, { - setup_test_file, test_file_open_4, cleanup_test_file, - "file::open", "allow_read /tmp/testfile4"}, { - setup_test_file, test_file_open_5, cleanup_test_file, - "file::open", "allow_read /tmp/testfile5"}, { - setup_test_file, test_file_open_5, cleanup_test_file, - "file::create", "allow_create /tmp/testfile5 0600"}, { - setup_test_file, test_file_open_6, cleanup_test_file, - "file::open", "allow_read /tmp/testfile6"}, { - setup_test_file, test_file_open_6, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile6"}, { - setup_test_file_truncate, test_file_open_6, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile6"}, { - setup_test_file, test_file_open_7, cleanup_test_file, - "file::open", "allow_read /tmp/testfile7"}, { - setup_test_file, test_file_open_7, cleanup_test_file, - "file::create", "allow_create /tmp/testfile7 0600"}, { - setup_test_file, test_file_open_8, cleanup_test_file, - "file::open", "allow_write /tmp/testfile8"}, { - setup_test_file, test_file_open_8, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile8"}, { - setup_test_file, test_file_open_9, cleanup_test_file, - "file::open", "allow_write /tmp/testfile9"}, { - setup_test_file, test_file_open_9, cleanup_test_file, - "file::create", "allow_create /tmp/testfile9 0600"}, { - setup_test_file, test_file_open_9, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile9"}, { - setup_test_file, test_file_open_10, cleanup_test_file, - "file::open", "allow_write /tmp/testfile10"}, { - setup_test_file, test_file_open_10, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile10"}, { - setup_test_file, test_file_open_10, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile10"}, { - setup_test_file, test_file_open_11, cleanup_test_file, - "file::open", "allow_write /tmp/testfile11"}, { - setup_test_file, test_file_open_11, cleanup_test_file, - "file::create", "allow_create /tmp/testfile11 0600"}, { - setup_test_file, test_file_open_11, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile11"}, { - setup_test_file, test_file_open_12, cleanup_test_file, - "file::open", "allow_write /tmp/testfile12"}, { - setup_test_file, test_file_open_13, cleanup_test_file, - "file::open", "allow_write /tmp/testfile13"}, { - setup_test_file, test_file_open_13, cleanup_test_file, - "file::create", "allow_create /tmp/testfile13 0600"}, { - setup_test_file, test_file_open_14, cleanup_test_file, - "file::open", "allow_write /tmp/testfile14"}, { - setup_test_file, test_file_open_14, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile14"}, { - setup_test_file_truncate, test_file_open_14, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile14"}, { - setup_test_file, test_file_open_15, cleanup_test_file, - "file::open", "allow_write /tmp/testfile15"}, { - setup_test_file, test_file_open_15, cleanup_test_file, - "file::create", "allow_create /tmp/testfile15 0600"}, { - setup_test_file, test_file_open_16, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile16"}, { - setup_test_file, test_file_open_16, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile16"}, { - setup_test_file, test_file_open_17, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile17"}, { - setup_test_file, test_file_open_17, cleanup_test_file, - "file::create", "allow_create /tmp/testfile17 0600"}, { - setup_test_file, test_file_open_17, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile17"}, { - setup_test_file, test_file_open_18, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile18"}, { - setup_test_file, test_file_open_18, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile18"}, { - setup_test_file, test_file_open_18, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile18"}, { - setup_test_file, test_file_open_19, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile19"}, { - setup_test_file, test_file_open_19, cleanup_test_file, - "file::create", "allow_create /tmp/testfile19 0600"}, { - setup_test_file, test_file_open_19, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile19"}, { - setup_test_file, test_file_open_20, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile20"}, { - setup_test_file, test_file_open_21, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile21"}, { - setup_test_file, test_file_open_21, cleanup_test_file, - "file::create", "allow_create /tmp/testfile21 0600"}, { - setup_test_file, test_file_open_22, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile22"}, { - setup_test_file, test_file_open_22, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile22"}, { - setup_test_file_truncate, test_file_open_22, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile22"}, { - setup_test_file, test_file_open_23, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile23"}, { - setup_test_file, test_file_open_23, cleanup_test_file, - "file::create", "allow_create /tmp/testfile23 0600"}, { - setup_all_test_file, test_file_open_0, cleanup_test_file, - "file::open", "allow_read /tmp/testfile0"}, { - setup_all_test_file, test_file_open_2, cleanup_test_file, - "file::open", "allow_read /tmp/testfile2"}, { - setup_all_test_file, test_file_open_2, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile2"}, { - setup_all_test_file_truncate, test_file_open_2, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile2"}, { - setup_all_test_file, test_file_open_4, cleanup_test_file, - "file::open", "allow_read /tmp/testfile4"}, { - setup_all_test_file, test_file_open_6, cleanup_test_file, - "file::open", "allow_read /tmp/testfile6"}, { - setup_all_test_file, test_file_open_6, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile6"}, { - setup_all_test_file_truncate, test_file_open_6, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile6"}, { - setup_all_test_file, test_file_open_8, cleanup_test_file, - "file::open", "allow_write /tmp/testfile8"}, { - setup_all_test_file, test_file_open_8, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile8"}, { - setup_all_test_file, test_file_open_10, cleanup_test_file, - "file::open", "allow_write /tmp/testfile10"}, { - setup_all_test_file, test_file_open_10, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile10"}, { - setup_all_test_file, test_file_open_10, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile10"}, { - setup_all_test_file, test_file_open_12, cleanup_test_file, - "file::open", "allow_write /tmp/testfile12"}, { - setup_all_test_file, test_file_open_14, cleanup_test_file, - "file::open", "allow_write /tmp/testfile14"}, { - setup_all_test_file, test_file_open_14, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile14"}, { - setup_all_test_file_truncate, test_file_open_14, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile14"}, { - setup_all_test_file, test_file_open_16, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile16"}, { - setup_all_test_file, test_file_open_16, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile16"}, { - setup_all_test_file, test_file_open_18, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile18"}, { - setup_all_test_file, test_file_open_18, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile18"}, { - setup_all_test_file, test_file_open_18, cleanup_test_file, - "file::rewrite", "allow_rewrite /tmp/testfile18"}, { - setup_all_test_file, test_file_open_20, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile20"}, { - setup_all_test_file, test_file_open_22, cleanup_test_file, - "file::open", "allow_read/write /tmp/testfile22"}, { - setup_all_test_file, test_file_open_22, cleanup_test_file, - "file::truncate", "allow_truncate /tmp/testfile22"}, { - setup_all_test_file_truncate, test_file_open_22, - cleanup_test_file_truncate, "file::rewrite", - "allow_rewrite /tmp/testfile22"}, { - NULL} -}; - -int main(void) -{ - int i; - tomoyo_test_init(); - for (i = 0; tests[i].do_test; i++) { - int trial; - for (trial = 0; trial < 2; trial++) { - int should_fail; - for (should_fail = 0; should_fail < 2; should_fail++) { - if (tests[i].do_setup) - tests[i].do_setup(); - if (!should_fail) - write_domain_policy(tests[i].policy, 0); - set_profile(3, tests[i].name); - tests[i].do_test(); - show_result(tests[i].policy, !should_fail); - set_profile(0, tests[i].name); - if (tests[i].do_cleanup) - tests[i].do_cleanup(); - if (!should_fail) - write_domain_policy(tests[i].policy, 1); - } - } - } - for (i = 0; tests[i].do_test; i++) { - int mode; - for (mode = 0; mode < 4; mode++) { - if (tests[i].do_setup) - tests[i].do_setup(); - set_profile(mode, tests[i].name); - tests[i].do_test(); - show_result(tests[i].name, 1); - set_profile(0, tests[i].name); - if (tests[i].do_cleanup) - tests[i].do_cleanup(); - } - } - fprintf(domain_fp, "delete %s\n", self_domain); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_policy_io_test.c b/testcases/kernel/security/tomoyo/tomoyo_policy_io_test.c deleted file mode 100644 index b1897a0fc..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_policy_io_test.c +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_policy_io_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static FILE *policy_fp = NULL; -static const char *policy_file = ""; - -static void try_io(const char *policy, const char should_success) -{ - FILE *fp = fopen(policy_file, "r"); - char buffer[8192]; - int policy_found = 0; - memset(buffer, 0, sizeof(buffer)); - printf("%s: ", policy); - fprintf(policy_fp, "%s\n", policy); - if (!fp) { - printf("BUG: policy read failed\n"); - return; - } - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - char *cp = strchr(buffer, '\n'); - if (cp) - *cp = '\0'; - if (!strcmp(buffer, policy)) { - policy_found = 1; - break; - } - } - fclose(fp); - if (should_success) { - if (policy_found) - printf("OK\n"); - else - printf("BUG: policy write failed\n"); - } else { - if (!policy_found) - printf("OK : write rejected.\n"); - else - printf("BUG: policy write not rejected.\n"); - } - fprintf(policy_fp, "delete %s\n", policy); -} - -static void stage_policy_io_test(void) -{ - int i; - policy_file = proc_policy_domain_policy; - policy_fp = domain_fp; - for (i = 0; i < 3; i++) { - try_io("allow_chroot /", 1); - try_io("allow_chroot ", 0); - try_io("allow_chroot /mnt0/", 1); - try_io("allow_chroot /var1/chroot2/", 1); - try_io("allow_chroot /mnt0/", 1); - try_io("allow_chroot /mnt0/", 1); - try_io("allow_chroot /mnt0/", 1); - try_io("allow_chroot /mnt\\?\\*/", 1); - try_io("allow_chroot /mnt\\?\\*/", 1); - try_io("allow_unmount /", 1); - try_io("allow_unmount /sys1/", 1); - try_io("allow_unmount /initrd2/", 1); - try_io("allow_unmount /initrd/dev3/", 1); - try_io("allow_unmount /initrd/\\*\\+/", 1); - try_io("allow_unmount /initrd/\\@\\*/", 1); - try_io("allow_unmount /initrd2/", 1); - try_io("allow_pivot_root / /proc3/", 1); - try_io("allow_pivot_root /sys5/ /proc3/", 1); - try_io("allow_pivot_root /sys/", 0); - try_io("allow_pivot_root *", 0); - try_io("allow_pivot_root /sys5/ /proc3/", 1); - try_io("allow_mount / / --bind 0xD", 1); - try_io("allow_mount / / --move 0xF", 1); - try_io("allow_mount / --remount", 0); - try_io("allow_mount /", 0); - try_io("allow_mount none /tmp/ tmpfs 0x1", 1); - try_io("allow_mount none /tmp/ tmpfs", 0); - try_io("allow_mount none /tmp/ nonexistent 0x0", 1); - try_io("allow_mount none /proc/ proc 0x0", 1); - try_io("allow_mount none /selinux/ selinuxfs 0x0", 1); - try_io("allow_mount /proc/bus/usb /proc/bus/usb/ usbfs 0x0", 1); - try_io("allow_mount none /dev/pts/ devpts 0x0", 1); - try_io("allow_mount any / --remount 0xC00", 1); - try_io("allow_mount /dev/sda1 /boot/ ext3 0xC00", 1); - try_io("allow_mount none /dev/shm/ tmpfs 0x0", 1); - try_io("allow_mount none /proc/sys/fs/binfmt_misc/ binfmt_misc " - "0x0", 1); - try_io("allow_mount none /proc/sys/fs/binfmt_misc/ binfmt_misc " - "0x0 0x1", 0); - try_io("allow_mount none /proc/sys/fs/binfmt_misc/ tmpfs " - "binfmt_misc 0x0", 0); - try_io("allow_mount /proc/bus/usb /proc/bus/usb/ usbfs 0x0", 1); - } - policy_file = proc_policy_exception_policy; - policy_fp = exception_fp; - for (i = 0; i < 3; i++) { - try_io("allow_read /tmp/abc", 1); - try_io("allow_read /tmp/abc\\*", 1); - try_io("allow_read abc", 1); - try_io("allow_read /tmp/abc/", 1); - try_io("allow_read", 0); - try_io("allow_read *", 1); - try_io("file_pattern /\\*\\*\\*", 1); - try_io("file_pattern /abc", 1); - try_io("file_pattern /abc /def", 0); - try_io("file_pattern abcdef", 1); - try_io("path_group TEST /", 1); - try_io("path_group TEST /boo", 1); - try_io("path_group TEST /bar", 1); - try_io("path_group TEST /\\*", 1); - try_io("path_group TEST / /", 0); - try_io("path_group TEST /boo", 1); - try_io("path_group TEST /bar", 1); - try_io("path_group TEST boo", 1); - try_io("path_group TEST boo/", 1); - try_io("path_group TEST /bar", 1); - try_io("path_group TEST3 /\\*", 1); - try_io("path_group TEST3 / /", 0); - try_io("path_group TEST3 /boo", 1); - try_io("path_group TEST3 /bar", 1); - try_io("path_group TEST3 boo", 1); - try_io("path_group TEST3 boo/", 1); - try_io("deny_rewrite /", 1); - try_io("deny_rewrite /foo", 1); - try_io("deny_rewrite /\\*", 1); - try_io("deny_rewrite /\\:", 0); - try_io("deny_rewrite / /", 0); - try_io("deny_rewrite @/TEST", 1); - try_io("aggregator /boo/\\* /BOO", 1); - try_io("aggregator /boo/\\* /BOO\\*", 0); - try_io("aggregator /boo/\\*/ /BOO", 1); - try_io("aggregator /boo/\\* /BOO/", 1); - try_io("keep_domain <kernel>", 1); - try_io("keep_domain <kernel> /sbin/init", 1); - try_io("keep_domain <kernel> foo", 0); - try_io("keep_domain <kernel> \\*", 0); - try_io("keep_domain /ssh", 1); - try_io("keep_domain /ssh /foo", 0); - try_io("keep_domain /foo from <kernel>", 1); - try_io("keep_domain /foo from <kernel> /sbin/init", 1); - try_io("keep_domain from <kernel> /sbin/init", 0); - try_io("keep_domain \\* from <kernel> /sbin/init", 0); - try_io("no_keep_domain <kernel>", 1); - try_io("no_keep_domain <kernel> /sbin/init", 1); - try_io("no_keep_domain <kernel> foo", 0); - try_io("no_keep_domain <kernel> \\*", 0); - try_io("no_keep_domain /ssh", 1); - try_io("no_keep_domain /ssh /foo", 0); - try_io("no_keep_domain /foo from <kernel>", 1); - try_io("no_keep_domain /foo from <kernel> /sbin/init", 1); - try_io("no_keep_domain from <kernel> /sbin/init", 0); - try_io("no_keep_domain \\* from <kernel> /sbin/init", 0); - try_io("initialize_domain /foo", 1); - try_io("initialize_domain /\\*", 1); - try_io("initialize_domain /foo /bar", 0); - try_io("initialize_domain /foo from /bar", 1); - try_io("initialize_domain /foo from <kernel> /bar", 1); - try_io("initialize_domain /\\* from <kernel>", 1); - try_io("initialize_domain /foo from <kernel> \\*", 0); - try_io("no_initialize_domain /foo", 1); - try_io("no_initialize_domain /\\*", 1); - try_io("no_initialize_domain /foo /bar", 0); - try_io("no_initialize_domain /foo from /bar", 1); - try_io("no_initialize_domain /foo from <kernel> /bar", 1); - try_io("no_initialize_domain /\\* from <kernel>", 1); - try_io("no_initialize_domain /foo from <kernel> \\*", 0); - } -} - -int main(void) -{ - tomoyo_test_init(); - stage_policy_io_test(); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_policy_memory_test.c b/testcases/kernel/security/tomoyo/tomoyo_policy_memory_test.c deleted file mode 100644 index a6620ba30..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_policy_memory_test.c +++ /dev/null @@ -1,358 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_policy_memory_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -/* - * Usage: Run this program using init= boot option. - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/mount.h> - -static void BUG(const char *msg) -{ - printf("%s", msg); - fflush(stdout); - while (1) - sleep(100); -} - -static const char *policy_file = NULL; -static const char *policy = NULL; - -static void get_meminfo(unsigned int *policy_memory) -{ - FILE *fp = fopen("/sys/kernel/security/tomoyo/meminfo", "r"); - if (!fp || fscanf(fp, "Policy: %u", policy_memory) != 1 || fclose(fp)) - BUG("BUG: Policy read error\n"); -} - -static void check_policy_common(const int found_expected, const int id) -{ - FILE *fp = fopen(policy_file, "r"); - char buffer[8192]; - int policy_found = 0; - memset(buffer, 0, sizeof(buffer)); - if (!fp) - BUG("BUG: Policy read error\n"); - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - char *cp = strchr(buffer, '\n'); - if (cp) - *cp = '\0'; - if (strcmp(buffer, policy)) - continue; - policy_found = 1; - break; - } - fclose(fp); - if (policy_found != found_expected) { - printf("BUG: Policy write error: %s %s at %d\n", policy, - found_expected ? "not added" : "not deleted", id); - BUG(""); - } -} - -static inline void check_policy_written(FILE * fp, const int id) -{ - fflush(fp); - check_policy_common(1, id); -} - -static inline void check_policy_deleted(FILE * fp, const int id) -{ - fflush(fp); - check_policy_common(0, id); -} - -static const char *domain_testcases[] = { - "allow_create /tmp/mknod_reg_test 0600", - "allow_create /tmp/open_test 0600", - "allow_create /tmp/open_test 0600", - "allow_create /tmp/open_test 0600", - "allow_execute /bin/true", - "allow_execute /bin/true", - "allow_execute /bin/true0", - "allow_execute /bin/true1", - "allow_execute /bin/true2", - "allow_execute /bin/true3", - "allow_execute /bin/true4", - "allow_execute /bin/true5", - "allow_execute /bin/true6", - "allow_execute /bin/true7", - "allow_execute /bin/true7", - "allow_execute /bin/true7", - "allow_execute /bin/true8", - "allow_ioctl socket:[family=2:type=2:protocol=17] 0-35122", - "allow_ioctl socket:[family=2:type=2:protocol=17] 35122-35124", - "allow_link /tmp/link_source_test /tmp/link_dest_test", - "allow_mkblock /tmp/mknod_blk_test 0600 1 0", - "allow_mkchar /tmp/mknod_chr_test 0600 1 3", - "allow_mkdir /tmp/mkdir_test/ 0755", - "allow_mkfifo /tmp/mknod_fifo_test 0600", - "allow_mkfifo /tmp/mknod_fifo_test 0600", - "allow_mksock /tmp/mknod_sock_test 0600", - "allow_mksock /tmp/socket_test 0600", - "allow_read /bin/true", - "allow_read /bin/true", - "allow_read /dev/null", - "allow_read /dev/null", - "allow_read /dev/null", - "allow_read /dev/null", - "allow_read /dev/null", - "allow_read /dev/null", - "allow_read /foo", - "allow_read /proc/sys/net/ipv4/ip_local_port_range", - "allow_read /proc/sys/net/ipv4/ip_local_port_range", - "allow_read/write /bar", - "allow_read/write /dev/null", - "allow_read/write /dev/null", - "allow_read/write /proc/sys/net/ipv4/ip_local_port_range", - "allow_read/write /proc/sys/net/ipv4/ip_local_port_range", - "allow_read/write /tmp/fifo", - "allow_read/write /tmp/fifo", - "allow_read/write /tmp/rewrite_test", - "allow_rename /tmp/rename_source_test /tmp/rename_dest_test", - "allow_rmdir /tmp/rmdir_test/", - "allow_symlink /symlink", - "allow_symlink /symlink", - "allow_symlink /symlink", - "allow_symlink /symlink", - "allow_symlink /tmp/symlink_source_test", - "allow_symlink /tmp/symlink_source_test", - "allow_symlink /tmp/symlink_source_test", - "allow_symlink /tmp/symlink_source_test", - "allow_symlink /tmp/symlink_source_test", - "allow_truncate /tmp/rewrite_test", - "allow_truncate /tmp/truncate_test", - "allow_truncate /tmp/truncate_test", - "allow_unlink /tmp/unlink_test", - "allow_write /123", - "allow_write /dev/null", - "allow_write /dev/null", - "allow_write /devfile", - "allow_write /devfile", - "allow_write /proc/sys/net/ipv4/ip_local_port_range", - "allow_write /proc/sys/net/ipv4/ip_local_port_range", - "allow_write /tmp/open_test", - "allow_write /tmp/open_test", - "allow_write /tmp/open_test", - "allow_write /tmp/truncate_test", - "allow_write /tmp/truncate_test", - "allow_rewrite /tmp/rewrite_test", - "allow_rewrite /tmp/rewrite_test", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 0x123", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 123", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 0123", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 0x123", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 123", - "allow_mount /dev/sda1 /mnt/sda1/ ext3 0123", - "allow_chroot /", - "allow_chroot /", - "allow_chroot /mnt/", - "allow_pivot_root / /proc/", - "allow_pivot_root /mnt/ /proc/mnt/", - "allow_unmount /", - "allow_unmount /proc/", - NULL -}; - -static void domain_policy_test(const unsigned int before) -{ - unsigned int after; - int j; - policy_file = "/sys/kernel/security/tomoyo/domain_policy"; - for (j = 0; domain_testcases[j]; j++) { - int i; - FILE *fp = fopen(policy_file, "w"); - if (!fp) - BUG("BUG: Policy write error\n"); - fprintf(fp, "<kernel>\n"); - policy = domain_testcases[j]; - printf("Processing: %s\n", policy); - for (i = 0; i < 100; i++) { - fprintf(fp, "%s\n", policy); - if (!i) - check_policy_written(fp, 1); - fprintf(fp, "delete %s\n", policy); - } - check_policy_deleted(fp, 1); - for (i = 0; i < 100; i++) - fprintf(fp, "%s\n", policy); - check_policy_written(fp, 2); - fprintf(fp, "delete %s\n", policy); - check_policy_deleted(fp, 2); - fclose(fp); - for (i = 0; i < 30; i++) { - usleep(100000); - get_meminfo(&after); - if (before == after) - break; - } - if (before != after) { - printf("Policy: %d\n", after - before); - BUG("Policy read/write test: Fail\n"); - } - } - for (j = 0; j < 10; j++) { - int i; - FILE *fp = fopen(policy_file, "w"); - if (!fp) - BUG("BUG: Policy write error\n"); - fprintf(fp, "<kernel> /sbin/init\n"); - for (i = 0; domain_testcases[i]; i++) - fprintf(fp, "%s\n", domain_testcases[i]); - fprintf(fp, "delete <kernel> /sbin/init\n"); - fclose(fp); - for (i = 0; i < 50; i++) { - usleep(100000); - get_meminfo(&after); - if (before == after) - break; - } - if (before != after) { - printf("Policy: %d\n", after - before); - BUG("Policy read/write test: Fail\n"); - } - } -} - -static const char *exception_testcases[] = { - "allow_read /tmp/mknod_reg_test", - "allow_env HOME", - "path_group PG1 /", - "path_group PG2 /", - "address_group AG3 0.0.0.0", - "address_group AG3 1.2.3.4-5.6.7.8", - "address_group AG3 f:ee:ddd:cccc:b:aa:999:8888", - "address_group AG4 0:1:2:3:4:5:6:7-8:90:a00:b000:c00:d0:e:f000", - "number_group NG1 1000", - "number_group NG2 10-0x100000", - "number_group NG3 01234567-0xABCDEF89", - "deny_autobind 1024", - "deny_autobind 32668-65535", - "deny_autobind 0-1023", - "initialize_domain /usr/sbin/sshd", - "no_initialize_domain /usr/sbin/sshd", - "initialize_domain /usr/sbin/sshd from /bin/bash", - "no_initialize_domain /usr/sbin/sshd from /bin/bash", - "initialize_domain /usr/sbin/sshd from " - "<kernel> /bin/mingetty/bin/bash", - "no_initialize_domain /usr/sbin/sshd from " - "<kernel> /bin/mingetty/bin/bash", - "keep_domain <kernel> /usr/sbin/sshd /bin/bash", - "no_keep_domain <kernel> /usr/sbin/sshd /bin/bash", - "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash", - "no_keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash", - "keep_domain /bin/pwd from /bin/bash", - "no_keep_domain /bin/pwd from /bin/bash", - "file_pattern /proc/\\$/task/\\$/environ", - "file_pattern /proc/\\$/task/\\$/auxv", - "allow_read /etc/ld.so.cache", - "allow_read /proc/meminfo", - "allow_read /proc/sys/kernel/version", - "allow_read /etc/localtime", - "allow_read /proc/self/task/\\$/attr/current", - "allow_read /proc/self/task/\\$/oom_score", - "allow_read /proc/self/wchan", - "allow_read /lib/ld-2.5.so", - "file_pattern pipe:[\\$]", - "file_pattern socket:[\\$]", - "file_pattern /var/cache/logwatch/logwatch.\\*/", - "file_pattern /var/cache/logwatch/logwatch.\\*/\\*", - "deny_rewrite /var/log/\\*", - "deny_rewrite /var/log/\\*/\\*", - "aggregator /etc/rc.d/rc\\?.d/\\?\\+\\+smb /etc/rc.d/init.d/smb", - "aggregator /etc/rc.d/rc\\?.d/\\?\\+\\+crond /etc/rc.d/init.d/crond", - NULL -}; - -static void exception_policy_test(const unsigned int before) -{ - unsigned int after; - int j; - policy_file = "/sys/kernel/security/tomoyo/exception_policy"; - for (j = 0; exception_testcases[j]; j++) { - int i; - FILE *fp = fopen(policy_file, "w"); - if (!fp) - BUG("BUG: Policy write error\n"); - policy = exception_testcases[j]; - printf("Processing: %s\n", policy); - for (i = 0; i < 100; i++) { - fprintf(fp, "%s\n", policy); - if (!i) - check_policy_written(fp, 1); - fprintf(fp, "delete %s\n", policy); - } - check_policy_deleted(fp, 1); - for (i = 0; i < 100; i++) - fprintf(fp, "%s\n", policy); - check_policy_written(fp, 2); - fprintf(fp, "delete %s\n", policy); - check_policy_deleted(fp, 2); - fclose(fp); - for (i = 0; i < 30; i++) { - usleep(100000); - get_meminfo(&after); - if (before == after) - break; - } - if (before != after) { - printf("Policy: %d\n", after - before); - BUG("Policy read/write test: Fail\n"); - } - } - for (j = 0; j < 10; j++) { - int i; - FILE *fp = fopen(policy_file, "w"); - if (!fp) - BUG("BUG: Policy write error\n"); - for (i = 0; exception_testcases[i]; i++) - fprintf(fp, "%s\n", exception_testcases[i]); - for (i = 0; exception_testcases[i]; i++) - fprintf(fp, "delete %s\n", exception_testcases[i]); - fclose(fp); - for (i = 0; i < 50; i++) { - usleep(100000); - get_meminfo(&after); - if (before == after) - break; - } - if (before != after) { - printf("Policy: %d\n", after - before); - BUG("Policy read/write test: Fail\n"); - } - } -} - -int main(void) -{ - unsigned int before; - mount("/proc", "/proc/", "proc", 0, NULL); - get_meminfo(&before); - domain_policy_test(before); - exception_policy_test(before); - BUG("Policy read/write test: Success\n"); - return 0; -} diff --git a/testcases/kernel/security/tomoyo/tomoyo_rewrite_test.c b/testcases/kernel/security/tomoyo/tomoyo_rewrite_test.c deleted file mode 100644 index 7bc22c39b..000000000 --- a/testcases/kernel/security/tomoyo/tomoyo_rewrite_test.c +++ /dev/null @@ -1,169 +0,0 @@ -/******************************************************************************/ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * tomoyo_rewrite_test.c - * - * Testing program for security/tomoyo/ - * - * Copyright (C) 2005-2010 NTT DATA CORPORATION - */ -#include "include.h" - -static int should_fail = 0; - -static void show_prompt(const char *str) -{ - printf("Testing %35s: (%s) ", str, - should_fail ? "must fail" : "must success"); - errno = 0; -} - -static void show_result(int result) -{ - if (should_fail) { - if (result == EOF) { - if (errno == EPERM) - printf("OK: Permission denied.\n"); - else - printf("BUG!\n"); - } else { - printf("BUG!\n"); - } - } else { - if (result != EOF) - printf("OK\n"); - else - printf("BUG!\n"); - } -} - -#define REWRITE_PATH "/tmp/rewrite_test" - -static void stage_rewrite_test(void) -{ - int fd; - - /* Start up */ - write_domain_policy("allow_read/write " REWRITE_PATH, 0); - write_domain_policy("allow_truncate " REWRITE_PATH, 0); - write_domain_policy("allow_create " REWRITE_PATH " 0600", 0); - write_domain_policy("allow_unlink " REWRITE_PATH, 0); - write_exception_policy("deny_rewrite " REWRITE_PATH, 0); - set_profile(3, "file::open"); - set_profile(3, "file::create"); - set_profile(3, "file::truncate"); - set_profile(3, "file::rewrite"); - set_profile(3, "file::unlink"); - close(open(REWRITE_PATH, O_WRONLY | O_APPEND | O_CREAT, 0600)); - - /* Enforce mode */ - should_fail = 0; - - show_prompt("open(O_RDONLY)"); - fd = open(REWRITE_PATH, O_RDONLY); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_APPEND)"); - fd = open(REWRITE_PATH, O_WRONLY | O_APPEND); - show_result(fd); - close(fd); - - should_fail = 1; - show_prompt("open(O_WRONLY)"); - fd = open(REWRITE_PATH, O_WRONLY); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_TRUNC)"); - fd = open(REWRITE_PATH, O_WRONLY | O_TRUNC); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_TRUNC | O_APPEND)"); - fd = open(REWRITE_PATH, O_WRONLY | O_TRUNC | O_APPEND); - show_result(fd); - close(fd); - - show_prompt("truncate()"); - show_result(truncate(REWRITE_PATH, 0)); - - fd = open(REWRITE_PATH, O_WRONLY | O_APPEND); - show_prompt("ftruncate()"); - show_result(ftruncate(fd, 0)); - - show_prompt("fcntl(F_SETFL, ~O_APPEND)"); - show_result(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_APPEND)); - close(fd); - - /* Permissive mode */ - set_profile(2, "file::open"); - set_profile(2, "file::create"); - set_profile(2, "file::truncate"); - set_profile(2, "file::rewrite"); - set_profile(2, "file::unlink"); - should_fail = 0; - - show_prompt("open(O_RDONLY)"); - fd = open(REWRITE_PATH, O_RDONLY); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_APPEND)"); - fd = open(REWRITE_PATH, O_WRONLY | O_APPEND); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY)"); - fd = open(REWRITE_PATH, O_WRONLY); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_TRUNC)"); - fd = open(REWRITE_PATH, O_WRONLY | O_TRUNC); - show_result(fd); - close(fd); - - show_prompt("open(O_WRONLY | O_TRUNC | O_APPEND)"); - fd = open(REWRITE_PATH, O_WRONLY | O_TRUNC | O_APPEND); - show_result(fd); - close(fd); - - show_prompt("truncate()"); - show_result(truncate(REWRITE_PATH, 0)); - - fd = open(REWRITE_PATH, O_WRONLY | O_APPEND); - show_prompt("ftruncate()"); - show_result(ftruncate(fd, 0)); - - show_prompt("fcntl(F_SETFL, ~O_APPEND)"); - show_result(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_APPEND)); - close(fd); - - /* Clean up */ - unlink(REWRITE_PATH); - write_exception_policy("deny_rewrite " REWRITE_PATH, 0); - printf("\n\n"); -} - -int main(void) -{ - tomoyo_test_init(); - stage_rewrite_test(); - clear_status(); - return 0; -} diff --git a/testcases/kernel/sound/snd_timer01.c b/testcases/kernel/sound/snd_timer01.c index 123d1a2cb..310169b0f 100644 --- a/testcases/kernel/sound/snd_timer01.c +++ b/testcases/kernel/sound/snd_timer01.c @@ -8,7 +8,7 @@ * * The test performs several ioctl() parallel with readv() on the same * file descriptor to /dev/snd/timer. A buggy kernel will leak memory - * to the process, which may contain information from the the kernel or + * to the process, which may contain information from the kernel or * any other process on the system. * * The issue was fixed with diff --git a/testcases/kernel/syscalls/access/access01.c b/testcases/kernel/syscalls/access/access01.c index c9a076dfe..391c8d44b 100644 --- a/testcases/kernel/syscalls/access/access01.c +++ b/testcases/kernel/syscalls/access/access01.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske + * Copyright (c) Linux Test Project, 2003-2023 + * Author: William Roske */ -/* + +/*\ + * [Description] + * * Basic test for access(2) using F_OK, R_OK, W_OK and X_OK */ + #include <errno.h> #include <unistd.h> #include <sys/types.h> diff --git a/testcases/kernel/syscalls/access/access02.c b/testcases/kernel/syscalls/access/access02.c index bf636f9f4..c8fe0d0dc 100644 --- a/testcases/kernel/syscalls/access/access02.c +++ b/testcases/kernel/syscalls/access/access02.c @@ -1,21 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Guangwen Feng <fenggw-fnst@cn.fujitsu.com>, 2016 + * Copyright (c) Linux Test Project, 2002-2023 + * Ported to LTP: Wayne Boyer */ -/* - * Test Description: - * Verify that access() succeeds to check the existence or read/write/execute - * permissions on a file if the mode argument passed was F_OK/R_OK/W_OK/X_OK. +/*\ + * [Description] * - * Also verify that, access() succeeds to test the accessibility of the file - * referred to by symbolic link if the pathname points to a symbolic link. + * Test access(2) syscall * - * As well as verify that, these test files can be - * stat/read/written/executed indeed as root and nobody respectively. - * - * Ported to LTP: Wayne Boyer - * 06/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * - check the existence or read/write/execute permissions on a file (mode argument: F_OK/R_OK/W_OK/X_OK) + * - test the accessibility of the file referred to by symbolic link if the pathname points to a symbolic link + * - file can be stat/read/written/executed as root and nobody */ #include <sys/types.h> diff --git a/testcases/kernel/syscalls/access/access03.c b/testcases/kernel/syscalls/access/access03.c index ae3f676b1..7cae1ec2e 100644 --- a/testcases/kernel/syscalls/access/access03.c +++ b/testcases/kernel/syscalls/access/access03.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 */ -/* +/*\ + * [Description] + * * access(2) test for errno(s) EFAULT as root and nobody respectively. */ diff --git a/testcases/kernel/syscalls/access/access04.c b/testcases/kernel/syscalls/access/access04.c index 2d6dd70e8..b5764a5dd 100644 --- a/testcases/kernel/syscalls/access/access04.c +++ b/testcases/kernel/syscalls/access/access04.c @@ -2,26 +2,27 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2013 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 + * Ported to LTP: Wayne Boyer + * 11/2013 Ported by Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> + * 11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ -/* - * Verify that, - * 1) access() fails with -1 return value and sets errno to EINVAL - * if the specified access mode argument is invalid. - * 2) access() fails with -1 return value and sets errno to ENOENT - * if the specified file doesn't exist (or pathname is NULL). - * 3) access() fails with -1 return value and sets errno to ENAMETOOLONG - * if the pathname size is > PATH_MAX characters. - * 4) access() fails with -1 return value and sets errno to ENOTDIR - * if a component used as a directory in pathname is not a directory. - * 5) access() fails with -1 return value and sets errno to ELOOP - * if too many symbolic links were encountered in resolving pathname. - * 6) access() fails with -1 return value and sets errno to EROFS - * if write permission was requested for files on a read-only file system. +/*\ + * [Description] * - * Ported to LTP: Wayne Boyer - * 11/2013 Ported by Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> - * 11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * - access() fails with -1 return value and sets errno to EINVAL + * if the specified access mode argument is invalid. + * - access() fails with -1 return value and sets errno to ENOENT + * if the specified file doesn't exist (or pathname is NULL). + * - access() fails with -1 return value and sets errno to ENAMETOOLONG + * if the pathname size is > PATH_MAX characters. + * - access() fails with -1 return value and sets errno to ENOTDIR + * if a component used as a directory in pathname is not a directory. + * - access() fails with -1 return value and sets errno to ELOOP + * if too many symbolic links were encountered in resolving pathname. + * - access() fails with -1 return value and sets errno to EROFS + * if write permission was requested for files on a read-only file system. */ #include <errno.h> @@ -39,26 +40,32 @@ #define SNAME1 "symlink1" #define SNAME2 "symlink2" #define MNT_POINT "mntpoint" +#define LONGPATHSIZE (PATH_MAX + 2) static uid_t uid; -static char longpathname[PATH_MAX + 2]; +static char *longpathname; +static char *fname1; +static char *fname2; +static char *sname1; +static char *empty_fname; +static char *mnt_point; static struct tcase { - const char *pathname; + char **pathname; int mode; int exp_errno; } tcases[] = { - {FNAME1, -1, EINVAL}, - {"", W_OK, ENOENT}, - {longpathname, R_OK, ENAMETOOLONG}, - {FNAME2, R_OK, ENOTDIR}, - {SNAME1, R_OK, ELOOP}, - {MNT_POINT, W_OK, EROFS} + {&fname1, -1, EINVAL}, + {&empty_fname, W_OK, ENOENT}, + {&longpathname, R_OK, ENAMETOOLONG}, + {&fname2, R_OK, ENOTDIR}, + {&sname1, R_OK, ELOOP}, + {&mnt_point, W_OK, EROFS} }; static void access_test(struct tcase *tc, const char *user) { - TST_EXP_FAIL(access(tc->pathname, tc->mode), tc->exp_errno, + TST_EXP_FAIL(access(*tc->pathname, tc->mode), tc->exp_errno, "access as %s", user); } @@ -86,7 +93,8 @@ static void setup(void) uid = pw->pw_uid; - memset(longpathname, 'a', sizeof(longpathname) - 1); + memset(longpathname, 'a', LONGPATHSIZE - 1); + longpathname[LONGPATHSIZE-1] = 0; SAFE_TOUCH(FNAME1, 0333, NULL); SAFE_TOUCH(DNAME, 0644, NULL); @@ -103,4 +111,13 @@ static struct tst_test test = { .mntpoint = MNT_POINT, .setup = setup, .test = verify_access, + .bufs = (struct tst_buffers []) { + {&fname1, .str = FNAME1}, + {&fname2, .str = FNAME2}, + {&sname1, .str = SNAME1}, + {&empty_fname, .str = ""}, + {&longpathname, .size = LONGPATHSIZE}, + {&mnt_point, .str = MNT_POINT}, + {} + } }; diff --git a/testcases/kernel/syscalls/acct/acct01.c b/testcases/kernel/syscalls/acct/acct01.c index 254d7b503..52c4d41da 100644 --- a/testcases/kernel/syscalls/acct/acct01.c +++ b/testcases/kernel/syscalls/acct/acct01.c @@ -27,17 +27,25 @@ #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ S_IXGRP|S_IROTH|S_IXOTH) #define FILE_EISDIR "." -#define FILE_EACCES "/dev/null" +#define FILE_EACCESS "/dev/null" #define FILE_ENOENT "/tmp/does/not/exist" #define FILE_ENOTDIR "./tmpfile/" -#define TEST_TMPFILE "./tmpfile" -#define TEST_ELOOP "test_file_eloop1" -#define TEST_ENAMETOOLONG nametoolong -#define TEST_EROFS "mntpoint/file" +#define FILE_TMPFILE "./tmpfile" +#define FILE_ELOOP "test_file_eloop1" +#define FILE_EROFS "ro_mntpoint/file" -static char nametoolong[PATH_MAX+2]; static struct passwd *ltpuser; +static char *file_eisdir; +static char *file_eaccess; +static char *file_enoent; +static char *file_enotdir; +static char *file_tmpfile; +static char *file_eloop; +static char *file_enametoolong; +static char *file_erofs; +static char *file_null; + static void setup_euid(void) { SAFE_SETEUID(ltpuser->pw_uid); @@ -49,21 +57,21 @@ static void cleanup_euid(void) } static struct test_case { - char *filename; - char *exp_errval; + char **filename; + char *desc; int exp_errno; void (*setupfunc) (); void (*cleanfunc) (); } tcases[] = { - {FILE_EISDIR, "EISDIR", EISDIR, NULL, NULL}, - {FILE_EACCES, "EACCES", EACCES, NULL, NULL}, - {FILE_ENOENT, "ENOENT", ENOENT, NULL, NULL}, - {FILE_ENOTDIR, "ENOTDIR", ENOTDIR, NULL, NULL}, - {TEST_TMPFILE, "EPERM", EPERM, setup_euid, cleanup_euid}, - {NULL, "EPERM", EPERM, setup_euid, cleanup_euid}, - {TEST_ELOOP, "ELOOP", ELOOP, NULL, NULL}, - {TEST_ENAMETOOLONG, "ENAMETOOLONG", ENAMETOOLONG, NULL, NULL}, - {TEST_EROFS, "EROFS", EROFS, NULL, NULL}, + {&file_eisdir, FILE_EISDIR, EISDIR, NULL, NULL}, + {&file_eaccess, FILE_EACCESS, EACCES, NULL, NULL}, + {&file_enoent, FILE_ENOENT, ENOENT, NULL, NULL}, + {&file_enotdir, FILE_ENOTDIR, ENOTDIR, NULL, NULL}, + {&file_tmpfile, FILE_TMPFILE, EPERM, setup_euid, cleanup_euid}, + {&file_null, "NULL", EPERM, setup_euid, cleanup_euid}, + {&file_eloop, FILE_ELOOP, ELOOP, NULL, NULL}, + {&file_enametoolong, "aaaa...", ENAMETOOLONG, NULL, NULL}, + {&file_erofs, FILE_EROFS, EROFS, NULL, NULL}, }; static void setup(void) @@ -76,10 +84,10 @@ static void setup(void) ltpuser = SAFE_GETPWNAM("nobody"); - fd = SAFE_CREAT(TEST_TMPFILE, 0777); + fd = SAFE_CREAT(FILE_TMPFILE, 0777); SAFE_CLOSE(fd); - TEST(acct(TEST_TMPFILE)); + TEST(acct(FILE_TMPFILE)); if (TST_RET == -1) tst_brk(TBROK | TTERRNO, "acct failed unexpectedly"); @@ -89,11 +97,11 @@ static void setup(void) tst_brk(TBROK | TTERRNO, "acct(NULL) failed"); /* ELOOP SETTING */ - SAFE_SYMLINK(TEST_ELOOP, "test_file_eloop2"); - SAFE_SYMLINK("test_file_eloop2", TEST_ELOOP); + SAFE_SYMLINK(FILE_ELOOP, "test_file_eloop2"); + SAFE_SYMLINK("test_file_eloop2", FILE_ELOOP); - /* ENAMETOOLONG SETTING */ - memset(nametoolong, 'a', PATH_MAX+1); + memset(file_enametoolong, 'a', PATH_MAX+1); + file_enametoolong[PATH_MAX+1] = 0; } static void verify_acct(unsigned int nr) @@ -103,31 +111,29 @@ static void verify_acct(unsigned int nr) if (tcase->setupfunc) tcase->setupfunc(); - TEST(acct(tcase->filename)); + TST_EXP_FAIL(acct(*tcase->filename), tcase->exp_errno, + "acct(%s)", tcase->desc); if (tcase->cleanfunc) tcase->cleanfunc(); - - if (TST_RET != -1) { - tst_res(TFAIL, "acct(%s) succeeded unexpectedly", - tcase->filename); - return; - } - - if (TST_ERR == tcase->exp_errno) { - tst_res(TPASS | TTERRNO, "acct() failed as expected"); - } else { - tst_res(TFAIL | TTERRNO, - "acct() failed, expected: %s", - tst_strerrno(tcase->exp_errno)); - } } static struct tst_test test = { .needs_root = 1, - .mntpoint = "mntpoint", + .mntpoint = "ro_mntpoint", .needs_rofs = 1, .tcnt = ARRAY_SIZE(tcases), .setup = setup, .test = verify_acct, + .bufs = (struct tst_buffers []) { + {&file_eisdir, .str = FILE_EISDIR}, + {&file_eaccess, .str = FILE_EACCESS}, + {&file_enoent, .str = FILE_ENOENT}, + {&file_enotdir, .str = FILE_ENOTDIR}, + {&file_tmpfile, .str = FILE_TMPFILE}, + {&file_eloop, .str = FILE_ELOOP}, + {&file_enametoolong, .size = PATH_MAX+2}, + {&file_erofs, .str = FILE_EROFS}, + {} + } }; diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex02.c b/testcases/kernel/syscalls/adjtimex/adjtimex02.c index dab640ff3..e66ba2a5c 100644 --- a/testcases/kernel/syscalls/adjtimex/adjtimex02.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex02.c @@ -14,11 +14,6 @@ * - EFAULT with SET_MODE and invalid timex pointer * - EINVAL with ADJ_TICK greater than max tick * - EINVAL with ADJ_TICK smaller than min tick - * - * On kernels older than 2.6.26: - * - * - EINVAL with AJD_OFFSET smaller than min offset - * - EINVAL with AJD_OFFSET greater than max offset */ #include <errno.h> @@ -57,8 +52,6 @@ static struct test_case { {.modes = SET_MODE, .exp_err = EFAULT}, {.modes = ADJ_TICK, .lowlimit = 900000, .delta = 1, .exp_err = EINVAL}, {.modes = ADJ_TICK, .highlimit = 1100000, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .highlimit = 512000L, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .lowlimit = -512000L, .delta = -1, .exp_err = EINVAL}, }; static struct test_variants @@ -93,12 +86,6 @@ static void verify_adjtimex(unsigned int i) if (tc[i].highlimit) buf->tick = tc[i].highlimit + tc[i].delta; } - if (tc[i].modes == ADJ_OFFSET) { - if (tc[i].lowlimit || tc[i].highlimit) { - tst_res(TCONF, "Newer kernels normalize offset value outside range"); - return; - } - } } if (tc[i].exp_err == EFAULT) { diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex03.c b/testcases/kernel/syscalls/adjtimex/adjtimex03.c index 333cabf11..7056973cc 100644 --- a/testcases/kernel/syscalls/adjtimex/adjtimex03.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex03.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd, 2020. All Rights Reserved. - * Email: <code@zilogic.com> + * Copyright (c) Zilogic Systems Pvt. Ltd <code@zilogic.com>, 2020 + * Copyright (c) Linux Test Project, 2021-2023 * * Based on testcases/kernel/syscalls/adjtimex/adjtimex01.c * Copyright (c) Wipro Technologies Ltd, 2002. + */ + +/*\ + * [Description] * - * CVE-2018-11508 - * - * Test 4-byte kernel data leak via adjtimex + * CVE-2018-11508: Test 4-byte kernel data leak via adjtimex. * * On calling the adjtimex() function call with invalid mode (let's say * 0x8000), ideally all the parameters should return with null data. But, @@ -64,6 +66,7 @@ void verify_adjtimex(void) break; } } + if (data_leak != 0) tst_res(TFAIL, "Data leak observed"); else diff --git a/testcases/kernel/syscalls/alarm/alarm02.c b/testcases/kernel/syscalls/alarm/alarm02.c index b2fde03c8..fcf70c5f3 100644 --- a/testcases/kernel/syscalls/alarm/alarm02.c +++ b/testcases/kernel/syscalls/alarm/alarm02.c @@ -9,6 +9,7 @@ * [Description] * * Verify that alarm() returns: + * * - zero when there was no previously scheduled alarm * - number of seconds remaining until any previously scheduled alarm */ diff --git a/testcases/kernel/syscalls/bind/bind03.c b/testcases/kernel/syscalls/bind/bind03.c index 37a040b29..8c95cd799 100644 --- a/testcases/kernel/syscalls/bind/bind03.c +++ b/testcases/kernel/syscalls/bind/bind03.c @@ -43,8 +43,12 @@ static void run(void) * locks the socket and does all the checks and the node is not removed * in the error path. For now we will unlink the node here so that the * test works fine when the run() function is executed in a loop. + * From v5.14-rc1 the kernel has fix above issue. */ - unlink(SNAME_B); + if (tst_kvercmp(5, 14, 0) >= 0) + TST_EXP_FAIL(unlink(SNAME_B), ENOENT, "check exist of SNAME_B"); + else + unlink(SNAME_B); } static void setup(void) diff --git a/testcases/kernel/syscalls/bpf/bpf_common.h b/testcases/kernel/syscalls/bpf/bpf_common.h index 39764ba1f..a0800d19b 100644 --- a/testcases/kernel/syscalls/bpf/bpf_common.h +++ b/testcases/kernel/syscalls/bpf/bpf_common.h @@ -13,6 +13,7 @@ #include "lapi/socket.h" #define BPF_MEMLOCK_ADD (2*1024*1024) +#define BUFSIZE 8192 /* map[array_indx] = reg_to_save * diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c index e2fc80a9f..de4f68cef 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog01.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c @@ -63,7 +63,7 @@ int load_prog(int fd) BPF_EXIT_INSN(), /* return r0 */ }; - bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZ); + bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZE); return bpf_load_prog(attr, log); } diff --git a/testcases/kernel/syscalls/bpf/bpf_prog02.c b/testcases/kernel/syscalls/bpf/bpf_prog02.c index b40ea0f1d..fd3e535c1 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog02.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog02.c @@ -64,7 +64,7 @@ static int load_prog(int fd) BPF_EXIT_INSN(), /* 26: return r0 */ }; - bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZ); + bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZE); return bpf_load_prog(attr, log); } @@ -117,7 +117,7 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&key, .size = sizeof(*key)}, {&val, .size = sizeof(*val)}, - {&log, .size = BUFSIZ}, + {&log, .size = BUFSIZE}, {&attr, .size = sizeof(*attr)}, {&msg, .size = sizeof(MSG)}, {}, diff --git a/testcases/kernel/syscalls/bpf/bpf_prog04.c b/testcases/kernel/syscalls/bpf/bpf_prog04.c index ebee26cbc..cf3bb1254 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog04.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog04.c @@ -28,7 +28,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 #define CHECK_BPF_RET(x) ((x) >= 0 || ((x) == -1 && errno != EACCES)) static const char MSG[] = "Ahoj!"; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog05.c b/testcases/kernel/syscalls/bpf/bpf_prog05.c index 2be5a2cc9..742beab0b 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog05.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog05.c @@ -52,8 +52,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog06.c b/testcases/kernel/syscalls/bpf/bpf_prog06.c index c38dd8239..cee9616cf 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog06.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog06.c @@ -46,8 +46,6 @@ #include "lapi/bpf.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog07.c b/testcases/kernel/syscalls/bpf/bpf_prog07.c index 50ff6eed0..dab5bb8ad 100644 --- a/testcases/kernel/syscalls/bpf/bpf_prog07.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog07.c @@ -46,8 +46,6 @@ #include "lapi/bpf.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/capset/capset01.c b/testcases/kernel/syscalls/capset/capset01.c index a323fc5be..25db8112c 100644 --- a/testcases/kernel/syscalls/capset/capset01.c +++ b/testcases/kernel/syscalls/capset/capset01.c @@ -1,12 +1,20 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com> + * Author: Saji Kumar.V.R <saji.kumar@wipro.com> * - * CHANGES: - * 2005/01/01: add an hint to a possible solution when test fails - * - Ricky Ng-Adam <rngadam@yahoo.com> + * 2005/01/01: add an hint to a possible solution when test fails + * Ricky Ng-Adam <rngadam@yahoo.com> + * + * Copyright (c) Linux Test Project, 2003-2023 */ + +/*\ + * [Description] + * + * Test capset() with with LINUX_CAPABILITY_VERSION_{1,2,3}. + */ + #include <sys/types.h> #include <unistd.h> #include "tst_test.h" diff --git a/testcases/kernel/syscalls/capset/capset02.c b/testcases/kernel/syscalls/capset/capset02.c index 5173be09b..989f3e4ce 100644 --- a/testcases/kernel/syscalls/capset/capset02.c +++ b/testcases/kernel/syscalls/capset/capset02.c @@ -2,21 +2,27 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Author: Saji Kumar.V.R <saji.kumar@wipro.com> - * + * Copyright (c) Linux Test Project, 2003-2023 + */ + +/*\ + * [Description] * Tests basic error handling of the capset syscall. - * 1) capset() fails with errno set to EFAULT if an invalid address + * + * 1. capset() fails with errno set to EFAULT if an invalid address * is given for header. - * 2) capset() fails with errno set to EFAULT if an invalid address + * 2. capset() fails with errno set to EFAULT if an invalid address * is given for data. - * 3) capset() fails with errno set to EINVAL if an invalid value + * 3. capset() fails with errno set to EINVAL if an invalid value * is given for header->version. - * 4) capset() fails with errno set to EPERM if the new_Effective is + * 4. capset() fails with errno set to EPERM if the new_Effective is * not a subset of the new_Permitted. - * 5) capset() fails with errno set to EPERM if the new_Permitted is + * 5. capset() fails with errno set to EPERM if the new_Permitted is * not a subset of the old_Permitted. - * 6) capset() fails with errno set ot EPERM if the new_Inheritable is + * 6. capset() fails with errno set ot EPERM if the new_Inheritable is * not a subset of the old_Inheritable and bounding set. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/capset/capset03.c b/testcases/kernel/syscalls/capset/capset03.c index 074ab1f50..2b83e6ce9 100644 --- a/testcases/kernel/syscalls/capset/capset03.c +++ b/testcases/kernel/syscalls/capset/capset03.c @@ -1,11 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. - * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com + * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2020-2023 + * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] * * capset() fails with errno set or EPERM if the new_Inheritable is * not a subset of old_Inheritable and old_Permitted without CAP_SETPCAP. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/capset/capset04.c b/testcases/kernel/syscalls/capset/capset04.c index f929be555..13477a4a9 100644 --- a/testcases/kernel/syscalls/capset/capset04.c +++ b/testcases/kernel/syscalls/capset/capset04.c @@ -1,12 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2020-2023 * Author: Saji Kumar.V.R <saji.kumar@wipro.com> + */ + +/*\ + * [Description] * - * Tests whether we can use capset() to modify the capabilities of a thread + * Test whether capset() can be used to modify the capabilities of a thread * other than itself. Now, most linux distributions with kernel supporting * VFS capabilities, this should be never permitted. */ + #include <stdlib.h> #include <sys/types.h> #include <unistd.h> diff --git a/testcases/kernel/syscalls/chdir/chdir01.c b/testcases/kernel/syscalls/chdir/chdir01.c index e4080e3f4..d50a8f50c 100644 --- a/testcases/kernel/syscalls/chdir/chdir01.c +++ b/testcases/kernel/syscalls/chdir/chdir01.c @@ -31,18 +31,27 @@ static char *workdir; static int skip_symlinks, skip_blocked; static struct passwd *ltpuser; +static char *file_name; +static char *blocked_name; +static char *dir_name; +static char *cwd_name; +static char *parent_name; +static char *root_name; +static char *missing_name; +static char *link_name; + static struct test_case { - const char *name; + char **name; int root_ret, root_err, nobody_ret, nobody_err; } testcase_list[] = { - {FILE_NAME, -1, ENOTDIR, -1, ENOTDIR}, - {BLOCKED_NAME, 0, 0, -1, EACCES}, - {DIR_NAME, 0, 0, 0, 0}, - {".", 0, 0, 0, 0}, - {"..", 0, 0, 0, 0}, - {"/", 0, 0, 0, 0}, - {"missing", -1, ENOENT, -1, ENOENT}, - {LINK_NAME1, -1, ELOOP, -1, ELOOP}, + {&file_name, -1, ENOTDIR, -1, ENOTDIR}, + {&blocked_name, 0, 0, -1, EACCES}, + {&dir_name, 0, 0, 0, 0}, + {&cwd_name, 0, 0, 0, 0}, + {&parent_name, 0, 0, 0, 0}, + {&root_name, 0, 0, 0, 0}, + {&missing_name, -1, ENOENT, -1, ENOENT}, + {&link_name, -1, ELOOP, -1, ELOOP}, }; static void setup(void) @@ -53,8 +62,6 @@ static void setup(void) umask(0); - SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); - cwd = SAFE_GETCWD(NULL, 0); workdir = SAFE_MALLOC(strlen(cwd) + strlen(MNTPOINT) + 2); sprintf(workdir, "%s/%s", cwd, MNTPOINT); @@ -109,7 +116,7 @@ static void run(unsigned int n) { struct test_case *tc = testcase_list + n; - tst_res(TINFO, "Testing '%s'", tc->name); + tst_res(TINFO, "Testing '%s'", *tc->name); if (tc->root_err == ELOOP && skip_symlinks) { tst_res(TCONF, "Skipping symlink loop test, not supported"); @@ -119,8 +126,8 @@ static void run(unsigned int n) /* Reset current directory to mountpoint */ SAFE_CHDIR(workdir); - TEST(chdir(tc->name)); - check_result("root", tc->name, tc->root_ret, tc->root_err); + TEST(chdir(*tc->name)); + check_result("root", *tc->name, tc->root_ret, tc->root_err); if (tc->nobody_err == EACCES && skip_blocked) { tst_res(TCONF, "Skipping unprivileged permission test, " @@ -130,25 +137,35 @@ static void run(unsigned int n) SAFE_CHDIR(workdir); SAFE_SETEUID(ltpuser->pw_uid); - TEST(chdir(tc->name)); + TEST(chdir(*tc->name)); SAFE_SETEUID(0); - check_result(TESTUSER, tc->name, tc->nobody_ret, tc->nobody_err); + check_result(TESTUSER, *tc->name, tc->nobody_ret, tc->nobody_err); } static void cleanup(void) { SAFE_CHDIR(".."); - tst_umount(workdir); free(workdir); } static struct tst_test test = { .needs_root = 1, - .format_device = 1, + .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, .test = run, .tcnt = ARRAY_SIZE(testcase_list), .setup = setup, - .cleanup = cleanup + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&blocked_name, .str = BLOCKED_NAME}, + {&dir_name, .str = DIR_NAME}, + {&cwd_name, .str = "."}, + {&parent_name, .str = ".."}, + {&root_name, .str = "/"}, + {&missing_name, .str = "does_not_exist"}, + {&link_name, .str = LINK_NAME1}, + {} + } }; diff --git a/testcases/kernel/syscalls/chmod/chmod01.c b/testcases/kernel/syscalls/chmod/chmod01.c index 9f5ec4c67..b3b828ac3 100644 --- a/testcases/kernel/syscalls/chmod/chmod01.c +++ b/testcases/kernel/syscalls/chmod/chmod01.c @@ -19,13 +19,16 @@ static int modes[] = {0, 07, 070, 0700, 0777, 02777, 04777, 06777}; +static char *test_dir; +static char *test_file; + static struct variant { - char *name; + char **name; unsigned int mode_mask; char *desc; } variants[] = { - {TESTFILE, S_IFREG, "verify permissions of file"}, - {TESTDIR, S_IFDIR, "verify permissions of directory"}, + {&test_file, S_IFREG, "verify permissions of file"}, + {&test_dir, S_IFDIR, "verify permissions of directory"}, }; static void verify_chmod(unsigned int n) @@ -34,21 +37,21 @@ static void verify_chmod(unsigned int n) int mode = modes[n]; struct variant *tc = &variants[tst_variant]; - TST_EXP_PASS(chmod(tc->name, mode), "chmod(%s, %04o)", - tc->name, mode); + TST_EXP_PASS(chmod(*tc->name, mode), "chmod(%s, %04o)", + *tc->name, mode); if (!TST_PASS) return; - SAFE_STAT(tc->name, &stat_buf); + SAFE_STAT(*tc->name, &stat_buf); stat_buf.st_mode &= ~tc->mode_mask; if (stat_buf.st_mode == (unsigned int)mode) { tst_res(TPASS, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } else { tst_res(TFAIL, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } } @@ -57,9 +60,9 @@ static void setup(void) tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); if (tst_variant) - SAFE_MKDIR(variants[tst_variant].name, MODE); + SAFE_MKDIR(*variants[tst_variant].name, MODE); else - SAFE_TOUCH(variants[tst_variant].name, MODE, NULL); + SAFE_TOUCH(*variants[tst_variant].name, MODE, NULL); } static struct tst_test test = { @@ -68,4 +71,9 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(modes), .test = verify_chmod, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&test_dir, .str = TESTDIR}, + {} + } }; diff --git a/testcases/kernel/syscalls/chown/chown02.c b/testcases/kernel/syscalls/chown/chown02.c index 7c96832a4..467185831 100644 --- a/testcases/kernel/syscalls/chown/chown02.c +++ b/testcases/kernel/syscalls/chown/chown02.c @@ -9,6 +9,7 @@ * [Description] * * Verify that chown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/chroot/chroot03.c b/testcases/kernel/syscalls/chroot/chroot03.c index ba8c1e9ac..87faec316 100644 --- a/testcases/kernel/syscalls/chroot/chroot03.c +++ b/testcases/kernel/syscalls/chroot/chroot03.c @@ -25,41 +25,42 @@ #include <stdio.h> #include "tst_test.h" -static char fname[255]; -static char nonexistent_dir[100] = "testdir"; -static char bad_dir[] = "abcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz"; -static char symbolic_dir[] = "sym_dir1"; +#define FILE_NAME "test_file" +#define LOOP_DIR "sym_dir1" +#define NONEXISTENT_DIR "does_not_exist" + +static char *longname_dir; +static char *file_name; +static char *nonexistent_dir; +static char *bad_ptr; +static char *loop_dir; static struct tcase { - char *dir; + char **dir; int error; char *desc; } tcases[] = { - {bad_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, - {fname, ENOTDIR, "chroot(not a directory)"}, - {nonexistent_dir, ENOENT, "chroot(does not exists)"}, - {(char *)-1, EFAULT, "chroot(an invalid address)"}, - {symbolic_dir, ELOOP, "chroot(symlink loop)"} + {&longname_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, + {&file_name, ENOTDIR, "chroot(not a directory)"}, + {&nonexistent_dir, ENOENT, "chroot(does not exists)"}, + {&bad_ptr, EFAULT, "chroot(an invalid address)"}, + {&loop_dir, ELOOP, "chroot(symlink loop)"} }; static void verify_chroot(unsigned int n) { struct tcase *tc = &tcases[n]; - TST_EXP_FAIL(chroot(tc->dir), tc->error, "%s", tc->desc); + TST_EXP_FAIL(chroot(*tc->dir), tc->error, "%s", tc->desc); } static void setup(void) { - unsigned int i; - - (void)sprintf(fname, "tfile_%d", getpid()); - SAFE_TOUCH(fname, 0666, NULL); + SAFE_TOUCH(FILE_NAME, 0666, NULL); + bad_ptr = tst_get_bad_addr(NULL); - for (i = 0; i < ARRAY_SIZE(tcases); i++) { - if (tcases[i].error == EFAULT) - tcases[3].dir = tst_get_bad_addr(NULL); - } + memset(longname_dir, 'a', PATH_MAX + 1); + longname_dir[PATH_MAX+1] = 0; SAFE_SYMLINK("sym_dir1/", "sym_dir2"); SAFE_SYMLINK("sym_dir2/", "sym_dir1"); @@ -70,4 +71,11 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_chroot, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&nonexistent_dir, .str = NONEXISTENT_DIR}, + {&loop_dir, .str = LOOP_DIR}, + {&longname_dir, .size = PATH_MAX+2}, + {} + } }; diff --git a/testcases/kernel/syscalls/clone/clone04.c b/testcases/kernel/syscalls/clone/clone04.c index 7af4fedd3..74347e2b4 100644 --- a/testcases/kernel/syscalls/clone/clone04.c +++ b/testcases/kernel/syscalls/clone/clone04.c @@ -2,6 +2,7 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2012 Wanlong Gao <gaowanlong@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2003-2023 */ /*\ @@ -44,4 +45,8 @@ static void verify_clone(unsigned int nr) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_clone, + .tags = (const struct tst_tag[]) { + {"musl-git", "fa4a8abd06a4"}, + {} + }, }; diff --git a/testcases/kernel/syscalls/clone3/.gitignore b/testcases/kernel/syscalls/clone3/.gitignore index 604cb903e..10369954b 100644 --- a/testcases/kernel/syscalls/clone3/.gitignore +++ b/testcases/kernel/syscalls/clone3/.gitignore @@ -1,2 +1,3 @@ clone301 clone302 +clone303 diff --git a/testcases/kernel/syscalls/clone3/clone302.c b/testcases/kernel/syscalls/clone3/clone302.c index b1b4ccebb..48b831554 100644 --- a/testcases/kernel/syscalls/clone3/clone302.c +++ b/testcases/kernel/syscalls/clone3/clone302.c @@ -12,6 +12,7 @@ #define _GNU_SOURCE #include <stdlib.h> +#include <assert.h> #include "tst_test.h" #include "lapi/sched.h" @@ -34,7 +35,7 @@ static struct tcase { } tcases[] = { {"invalid args", &invalid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"zero size", &valid_args, 0, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, - {"short size", &valid_args, sizeof(*valid_args) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, + {"short size", &valid_args, sizeof(struct clone_args_minimal) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"extra size", &valid_args, sizeof(*valid_args) + 1, 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"sighand-no-VM", &valid_args, sizeof(*valid_args), CLONE_SIGHAND, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"thread-no-sighand", &valid_args, sizeof(*valid_args), CLONE_THREAD, NULL, SIGCHLD, 0, 0, 0, EINVAL}, @@ -59,6 +60,8 @@ static void setup(void) { clone3_supported_by_kernel(); + TST_EXP_EQ_SZ(sizeof(struct clone_args_minimal), 64); + void *p = tst_get_bad_addr(NULL); invalid_args = p; diff --git a/testcases/kernel/syscalls/clone3/clone303.c b/testcases/kernel/syscalls/clone3/clone303.c new file mode 100644 index 000000000..04c41942a --- /dev/null +++ b/testcases/kernel/syscalls/clone3/clone303.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC <wegao@suse.com> + */ + +/*\ + * [Description] + * + * This test case check clone3 CLONE_INTO_CGROUP flag + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> + +#include "tst_test.h" +#include "lapi/sched.h" +#include "lapi/pidfd.h" + +#define BUF_LEN 20 + +static struct tst_cg_group *cg_child_test_simple; +static int fd; +static struct tst_clone_args *args; + +static pid_t clone_into_cgroup(int cgroup_fd) +{ + + args->flags = CLONE_INTO_CGROUP; + args->exit_signal = SIGCHLD; + args->cgroup = cgroup_fd; + + return tst_clone(args); +} + +static void run(void) +{ + pid_t pid; + + pid = clone_into_cgroup(fd); + + if (!pid) { + TST_CHECKPOINT_WAIT(0); + return; + } + + char buf[BUF_LEN]; + + SAFE_CG_READ(cg_child_test_simple, "cgroup.procs", buf, BUF_LEN); + + if (atoi(buf) == pid) + tst_res(TPASS, "clone3 case pass!"); + else + tst_brk(TFAIL | TTERRNO, "clone3() failed !"); + + TST_CHECKPOINT_WAKE(0); + + SAFE_WAITPID(pid, NULL, 0); + +} + +static void setup(void) +{ + clone3_supported_by_kernel(); + + cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple"); + + fd = tst_cg_group_unified_dir_fd(cg_child_test_simple); + + if (fd < 0) + tst_brk(TBROK, "get dir fd failed!"); +} + +static void cleanup(void) +{ + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_cgroup_ctrls = (const char *const []){ "base", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_checkpoints = 1, + .min_kver = "5.7", + .bufs = (struct tst_buffers []) { + {&args, .size = sizeof(*args)}, + {}, + } +}; diff --git a/testcases/kernel/syscalls/delete_module/delete_module01.c b/testcases/kernel/syscalls/delete_module/delete_module01.c index 476551233..90d8b5289 100644 --- a/testcases/kernel/syscalls/delete_module/delete_module01.c +++ b/testcases/kernel/syscalls/delete_module/delete_module01.c @@ -2,38 +2,39 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2018 Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2002-2023 + * Author: Madhu T L <madhu.tarikere@wipro.com> */ -/* - * AUTHOR: Madhu T L <madhu.tarikere@wipro.com> +/*\ + * [Description] + * + * Basic test for delete_module(2). * - * DESCRIPTION: - * Basic tests for delete_module(2) - * 1) insmod dummy_del_mod.ko - * 2) call delete_module(2) to remove dummy_del_mod.ko + * Install dummy_del_mod.ko and delete it with delete_module(2). */ -#include <errno.h> #include "tst_test.h" #include "tst_module.h" #include "lapi/syscalls.h" #define MODULE_NAME "dummy_del_mod" -#define MODULE_NAME_KO "dummy_del_mod.ko" +#define MODULE_NAME_KO MODULE_NAME ".ko" static int module_loaded; static void do_delete_module(void) { - if (module_loaded == 0) { + if (!module_loaded) { tst_module_load(MODULE_NAME_KO, NULL); module_loaded = 1; } TEST(tst_syscall(__NR_delete_module, MODULE_NAME, 0)); if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "delete_module() failed to " - "remove module entry for %s ", MODULE_NAME); + tst_res(TFAIL | TTERRNO, + "delete_module() failed to remove module entry for %s", + MODULE_NAME); return; } @@ -43,14 +44,15 @@ static void do_delete_module(void) static void cleanup(void) { - if (module_loaded == 1) + if (module_loaded) tst_module_unload(MODULE_NAME_KO); } static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .cleanup = cleanup, .test_all = do_delete_module, }; diff --git a/testcases/kernel/syscalls/delete_module/delete_module03.c b/testcases/kernel/syscalls/delete_module/delete_module03.c index 863d36188..7e92fc2af 100644 --- a/testcases/kernel/syscalls/delete_module/delete_module03.c +++ b/testcases/kernel/syscalls/delete_module/delete_module03.c @@ -72,8 +72,9 @@ static void cleanup(void) static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .setup = setup, .cleanup = cleanup, .test_all = do_delete_module, diff --git a/testcases/kernel/syscalls/dup/dup01.c b/testcases/kernel/syscalls/dup/dup01.c index 74e24cc02..f5cd058e8 100644 --- a/testcases/kernel/syscalls/dup/dup01.c +++ b/testcases/kernel/syscalls/dup/dup01.c @@ -7,27 +7,32 @@ * */ +/*\ + * [Description] + * + * Verify that dup(2) syscall executes successfully and allocates + * a new file descriptor which refers to the same open file as oldfd. + */ + #include "tst_test.h" static int fd; +static struct stat buf1, buf2; static void verify_dup(void) { - TEST(dup(fd)); - - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - } else if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup(%d) Failed", fd); - } else { - tst_res(TPASS, "dup(%d) returned %ld", fd, TST_RET); - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd)); + + SAFE_FSTAT(TST_RET, &buf2); + TST_EXP_EQ_LU(buf1.st_ino, buf2.st_ino); + + SAFE_CLOSE(TST_RET); } static void setup(void) { fd = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); + SAFE_FSTAT(fd, &buf1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/dup/dup02.c b/testcases/kernel/syscalls/dup/dup02.c index 528bcdbc1..5391738a4 100644 --- a/testcases/kernel/syscalls/dup/dup02.c +++ b/testcases/kernel/syscalls/dup/dup02.c @@ -2,24 +2,21 @@ /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2020 SUSE LLC - * * 03/30/1992 AUTHOR: Richard Logan CO-PILOT: William Roske - * */ + /*\ * [Description] - * Negative test for dup(2) with bad fds. * - * [Algorithm] - * Call dup(2) with invalid argument and make sure it returns -1 with errno set - * to EBADF. + * Verify that dup(2) syscall fails with errno EBADF when called with + * invalid value for oldfd argument. */ #include "tst_test.h" static struct tcase { int fd; - int expected_errno; + int exp_err; } tcases[] = { {-1, EBADF}, {1500, EBADF}, @@ -29,27 +26,10 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(dup(tc->fd)); - - if (TST_RET < -1) { - tst_res(TFAIL | TTERRNO, "Invalid dup() return value %ld", - TST_RET); - return; - } - - if (TST_RET == -1) { - if (tc->expected_errno == TST_ERR) { - tst_res(TPASS | TTERRNO, "dup(%d) failed as expected", - tc->fd); - } else { - tst_res(TFAIL | TTERRNO, "dup(%d) failed unexpectedly", - tc->fd); - } - return; - } + TST_EXP_FAIL2(dup(tc->fd), tc->exp_err, "dup(%d)", tc->fd); - tst_res(TFAIL, "dup(%d) succeeded unexpectedly", tc->fd); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/dup/dup03.c b/testcases/kernel/syscalls/dup/dup03.c index 0e99813f4..d59e61f2b 100644 --- a/testcases/kernel/syscalls/dup/dup03.c +++ b/testcases/kernel/syscalls/dup/dup03.c @@ -6,48 +6,30 @@ */ /*\ * [Description] - * Negative test for dup(2) (too many fds). * - * [Algorithm] - * Open the maximum allowed number of file descriptors and then try to call - * dup() once more and verify it fails with EMFILE. + * Verify that dup(2) syscall fails with errno EMFILE when the per-process + * limit on the number of open file descriptors has been reached. */ #include <stdlib.h> #include "tst_test.h" -int *fd; -int nfds; +static int *fd; +static int nfds; static void run(void) { - TEST(dup(fd[0])); + TST_EXP_FAIL2(dup(fd[0]), EMFILE, "dup(%d)", fd[0]); - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - return; - } - - if (TST_RET == -1) { - if (TST_ERR == EMFILE) - tst_res(TPASS | TTERRNO, "dup() failed as expected"); - else - tst_res(TFAIL | TTERRNO, "dup() failed unexpectedly"); - return; - } - - tst_res(TFAIL, "dup() succeeded unexpectedly"); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static void setup(void) { long maxfds; - maxfds = sysconf(_SC_OPEN_MAX); - if (maxfds == -1) - tst_brk(TBROK, "sysconf(_SC_OPEN_MAX) failed"); - + maxfds = SAFE_SYSCONF(_SC_OPEN_MAX); fd = SAFE_MALLOC(maxfds * sizeof(int)); fd[0] = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); diff --git a/testcases/kernel/syscalls/dup/dup04.c b/testcases/kernel/syscalls/dup/dup04.c index 8d45f7a9c..053fb40c2 100644 --- a/testcases/kernel/syscalls/dup/dup04.c +++ b/testcases/kernel/syscalls/dup/dup04.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * * Basic test for dup(2) of a system pipe descriptor. */ @@ -17,38 +17,18 @@ #include "tst_test.h" -int fd[2]; +static int fd[2]; static void run(void) { - TEST(dup(fd[0])); - - if (TST_RET == -1) - tst_res(TFAIL | TTERRNO, - "dup of read side of pipe failed"); - else { - tst_res(TPASS, - "dup(%d) read side of syspipe returned %ld", - fd[0], TST_RET); - - SAFE_CLOSE(TST_RET); - } - - TEST(dup(fd[1])); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, - "dup of write side of pipe failed"); - } else { - tst_res(TPASS, - "dup(%d) write side of syspipe returned %ld", - fd[1], TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd[0]), "dup(%d) read end of the pipe", fd[0]); + SAFE_CLOSE(TST_RET); + + TST_EXP_FD(dup(fd[1]), "dup(%d) write end of the pipe", fd[1]); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { fd[0] = -1; @@ -56,7 +36,7 @@ void setup(void) } static struct tst_test test = { - .test_all = run, - .setup = setup, - .needs_tmpdir = 1, + .test_all = run, + .setup = setup, + .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/dup/dup05.c b/testcases/kernel/syscalls/dup/dup05.c index 362f3e170..619b4861e 100644 --- a/testcases/kernel/syscalls/dup/dup05.c +++ b/testcases/kernel/syscalls/dup/dup05.c @@ -1,55 +1,43 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2012-2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * - * Basic test for dup(2) of a named pipe descriptor + * Basic test for dup(2) of a named pipe descriptor. */ -#include <stdio.h> + #include "tst_test.h" -char Fname[255]; -int fd; +#define FNAME "dupfile" + +static int fd = -1; static void run(void) { - TEST(dup(fd)); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup failed"); - } else { - tst_res(TPASS, "dup returned %ld", - TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd), "dup(%d)", fd); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { - fd = -1; - - sprintf(Fname, "dupfile"); - SAFE_MKFIFO(Fname, 0777); - if ((fd = open(Fname, O_RDWR, 0700)) == -1) - tst_brk(TBROK, "open failed"); + SAFE_MKFIFO(FNAME, 0777); + fd = SAFE_OPEN(FNAME, O_RDWR, 0700); } -void cleanup(void) +static void cleanup(void) { if (fd != -1) - if (close(fd) == -1) - tst_res(TWARN | TERRNO, "close failed"); + SAFE_CLOSE(fd); } static struct tst_test test = { - .test_all = run, - .setup = setup, - .cleanup = cleanup, + .test_all = run, + .setup = setup, + .cleanup = cleanup, .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c index fe16ad1cb..dcf74bf77 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c @@ -67,7 +67,7 @@ static void setup(void) events[1].data.fd = fd[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[0], &events[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) @@ -85,7 +85,7 @@ static void cleanup(void) static void verify_epoll_ctl(unsigned int n) { TST_EXP_FAIL(epoll_ctl(*tc[n].epfd, tc[n].opt, *tc[n].fd, tc[n].event), - tc[n].exp_err, "epoll_clt(...) if %s", tc[n].desc); + tc[n].exp_err, "epoll_ctl(...) if %s", tc[n].desc); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c index c92b0b62e..f617295cc 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c @@ -55,7 +55,7 @@ static void setup(void) events.data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c index 5173755f7..bc015c01b 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c @@ -36,7 +36,7 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); epfd = new_epfd; } @@ -59,7 +59,7 @@ static void verify_epoll_ctl(void) events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events), EINVAL, - "epoll_clt(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); + "epoll_ctl(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); SAFE_CLOSE(new_epfd); } diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c index d03009cf3..71e300daa 100644 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c @@ -40,12 +40,12 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } events.data.fd = fd[0]; if (epoll_ctl(origin_epfd, EPOLL_CTL_DEL, fd[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_DEL, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_DEL, ...)"); } static void cleanup(void) @@ -61,7 +61,7 @@ static void verify_epoll_ctl(void) { events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(origin_epfd, EPOLL_CTL_ADD, epfd, &events), - ELOOP, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + ELOOP, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c index f4a55e008..928d57803 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c @@ -102,7 +102,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c index 7914f1c50..2ae32519f 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c @@ -42,7 +42,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c index 2ad1a6abc..aa08daa1b 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c @@ -50,7 +50,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c index 54b9be975..4be33488d 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c @@ -38,7 +38,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); bad_addr = tst_get_bad_addr(NULL); diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c index 4c4aeb77d..ed8f3e4f8 100644 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c @@ -46,7 +46,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } diff --git a/testcases/kernel/syscalls/epoll_wait/.gitignore b/testcases/kernel/syscalls/epoll_wait/.gitignore index 222955dd2..66ac18ae2 100644 --- a/testcases/kernel/syscalls/epoll_wait/.gitignore +++ b/testcases/kernel/syscalls/epoll_wait/.gitignore @@ -2,3 +2,6 @@ epoll_wait01 epoll_wait02 epoll_wait03 epoll_wait04 +epoll_wait05 +epoll_wait06 +epoll_wait07 diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c index d2c0b6ef4..93ada1cf3 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c @@ -50,7 +50,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c index 4b21aba4c..d31e49864 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c @@ -57,7 +57,7 @@ static void setup(void) epevs[0].data.fd = fds[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void verify_epoll_wait(unsigned int n) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c index dc62e9202..bd8baca22 100644 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c @@ -49,7 +49,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c new file mode 100644 index 000000000..d06a024ff --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that epoll receives EPOLLRDHUP event when we hang a reading + * half-socket we are polling on. + */ + +#include "tst_test.h" +#include "tst_net.h" +#include "tst_epoll.h" + +static int epfd; +static int sockfd_client; +static int sockfd_server; +static in_port_t *sock_port; + +static void create_server(void) +{ + int sockfd_server; + socklen_t len; + struct sockaddr_in serv_addr; + struct sockaddr_in sin; + + tst_init_sockaddr_inet_bin(&serv_addr, INADDR_ANY, 0); + + sockfd_server = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_BIND(sockfd_server, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + SAFE_LISTEN(sockfd_server, 10); + + len = sizeof(sin); + memset(&sin, 0, sizeof(struct sockaddr_in)); + SAFE_GETSOCKNAME(sockfd_server, (struct sockaddr *)&sin, &len); + + *sock_port = ntohs(sin.sin_port); + + tst_res(TINFO, "Listening on port %d", *sock_port); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + SAFE_CLOSE(sockfd_server); +} + +static void run(void) +{ + struct sockaddr_in client_addr; + struct epoll_event evt_req; + struct epoll_event evt_rec; + int ret; + + if (!SAFE_FORK()) { + create_server(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Connecting to port %d", *sock_port); + + sockfd_client = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + + tst_init_sockaddr_inet(&client_addr, "127.0.0.1", *sock_port); + + SAFE_CONNECT(sockfd_client, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + + tst_res(TINFO, "Polling on socket"); + + epfd = SAFE_EPOLL_CREATE1(0); + evt_req.events = EPOLLRDHUP; + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, sockfd_client, &evt_req); + + tst_res(TINFO, "Hang socket"); + + TST_EXP_PASS_SILENT(shutdown(sockfd_client, SHUT_RD)); + ret = SAFE_EPOLL_WAIT(epfd, &evt_rec, 1, 2000); + if (ret != 1) { + tst_res(TFAIL, "Wrong number of events reported %i", ret); + goto exit; + } + + if (evt_rec.events & EPOLLRDHUP) + tst_res(TPASS, "Received EPOLLRDHUP"); + else + tst_res(TFAIL, "EPOLLRDHUP has not been received"); + +exit: + SAFE_CLOSE(epfd); + SAFE_CLOSE(sockfd_client); + + TST_CHECKPOINT_WAKE(0); +} + +static void setup(void) +{ + sock_port = SAFE_MMAP(NULL, sizeof(in_port_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (sock_port) + SAFE_MUNMAP(sock_port, sizeof(in_port_t)); + + if (fcntl(sockfd_client, F_GETFD) > 0) + SAFE_CLOSE(sockfd_client); + + if (fcntl(sockfd_server, F_GETFD) > 0) + SAFE_CLOSE(sockfd_server); + + if (fcntl(epfd, F_GETFD) > 0) + SAFE_CLOSE(epfd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c new file mode 100644 index 000000000..f35e0423a --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that edge triggering is correctly handled by epoll, for both EPOLLIN + * and EPOLLOUT. + * + * [Algorithm] + * + * - The file descriptors for non-blocking pipe are registered on an epoll + * instance. + * - A pipe writer writes data on the write side of the pipe. + * - A call to epoll_wait() is done that will return a EPOLLIN event. + * - The pipe reader reads half of data from rfd. + * - A call to epoll_wait() should hang because there's data left to read. + * - The pipe reader reads remaining data from rfd. + * - A call to epoll_wait() should return a EPOLLOUT event. + */ + +#define _GNU_SOURCE + +#include <fcntl.h> +#include "tst_test.h" +#include "tst_epoll.h" + +static size_t write_size; +static size_t read_size; +static int fds[2]; +static int epfd; + +static void setup(void) +{ + write_size = getpagesize(); + read_size = write_size / 2; + + SAFE_PIPE2(fds, O_NONBLOCK); + + /* EPOLLOUT will be raised when buffer became empty after becoming full */ + SAFE_FCNTL(fds[1], F_SETPIPE_SZ, write_size); +} + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + char buff[write_size]; + struct epoll_event evt_receive; + + tst_res(TINFO, "Polling on channel with EPOLLET"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLET, + .data.fd = fds[0], + })); + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[1], &((struct epoll_event) { + .events = EPOLLOUT | EPOLLET, + .data.fd = fds[1], + })); + + tst_res(TINFO, "Write bytes on channel: %zu bytes", write_size); + + memset(buff, 'a', write_size); + SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buff, write_size); + TST_EXP_FAIL(write(fds[1], buff, write_size), EAGAIN, "write() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + + tst_res(TINFO, "Read half bytes from channel: %zu bytes", read_size); + + memset(buff, 0, write_size); + SAFE_READ(1, fds[0], buff, read_size); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 0); + + tst_res(TINFO, "Read remaining bytes from channel: %zu bytes", read_size); + + SAFE_READ(1, fds[0], buff + read_size, read_size); + TST_EXP_FAIL(read(fds[0], buff, read_size), EAGAIN, "read() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[1]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLOUT, EPOLLOUT); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c new file mode 100644 index 000000000..dfabd0d87 --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify that EPOLLONESHOT is correctly handled by epoll_wait. + * We open a channel, write in it two times and verify that EPOLLIN has been + * received only once. + */ + +#include <poll.h> +#include <sys/epoll.h> +#include "tst_test.h" +#include "tst_epoll.h" + +static int fds[2]; +static int epfd; + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + struct epoll_event evt_receive; + char buff = 'a'; + + SAFE_PIPE(fds); + + tst_res(TINFO, "Polling on channel with EPOLLONESHOT"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLONESHOT, + .data.fd = fds[0], + })); + + tst_res(TINFO, "Write channel for the 1st time. EPOLLIN expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 1); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + + SAFE_READ(1, fds[0], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + tst_res(TINFO, "Write channel for the 2nd time. No events expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + SAFE_CLOSE(epfd); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd/.gitignore b/testcases/kernel/syscalls/eventfd/.gitignore index db45c67cf..4f577370c 100644 --- a/testcases/kernel/syscalls/eventfd/.gitignore +++ b/testcases/kernel/syscalls/eventfd/.gitignore @@ -1 +1,6 @@ /eventfd01 +/eventfd02 +/eventfd03 +/eventfd04 +/eventfd05 +/eventfd06 diff --git a/testcases/kernel/syscalls/eventfd/eventfd01.c b/testcases/kernel/syscalls/eventfd/eventfd01.c index 9b60434a2..b66d6a55c 100644 --- a/testcases/kernel/syscalls/eventfd/eventfd01.c +++ b/testcases/kernel/syscalls/eventfd/eventfd01.c @@ -1,738 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> - * Copyright (c) Linux Test Project, 2008-2022 - * - * Based on testcases/kernel/syscalls/waitpid/waitpid01.c - * Original copyright message: - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * NAME - * eventfd01.c - * - * DESCRIPTION - * Test cases for eventfd syscall. +/*\ + * [Description] * - * USAGE: <for command-line> - * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * - * History - * 07/2008 Vijay Kumar - * Initial Version. - * - * Restrictions - * None - */ - -#include "config.h" - -#include <sys/types.h> -#include <sys/select.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <poll.h> -#include <signal.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -#include "test.h" -#define CLEANUP cleanup -#include "lapi/syscalls.h" - -TCID_DEFINE(eventfd01); -int TST_TOTAL = 15; - -#ifdef HAVE_LIBAIO -#include <libaio.h> - -static void setup(void); - -static int myeventfd(unsigned int initval, int flags) -{ - /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */ - return tst_syscall(__NR_eventfd, initval); -} - -/* - * clear_counter() - clears the counter by performing a dummy read - * @fd: the eventfd + * Verify read operation for eventfd fail with: * - * RETURNS: - * 0 on success, and -1 on failure - */ -static int clear_counter(int fd) -{ - uint64_t dummy; - int ret; - - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1) { - if (errno != EAGAIN) { - tst_resm(TINFO | TERRNO, "error clearing counter"); - return -1; - } - } - - return 0; -} - -/* - * set_counter() - sets the count to specified value - * @fd: the eventfd - * @val: the value to be set - * - * Clears the counter and sets the counter to @val. - * - * RETURNS: - * 0 on success, -1 on failure - */ -static int set_counter(int fd, uint64_t val) -{ - int ret; - - ret = clear_counter(fd); - if (ret == -1) - return -1; - - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TINFO | TERRNO, "error setting counter value"); - return -1; - } - - return 0; -} - -/* - * Test whether the current value of the counter matches @required. - */ -static void read_test(int fd, uint64_t required) -{ - int ret; - uint64_t val; - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == required) - tst_resm(TPASS, "counter value matches required"); - else - tst_resm(TFAIL, "counter value mismatch: " - "required: %" PRIu64 ", got: %" PRIu64, required, val); -} - -/* - * Test whether read returns with error EAGAIN when counter is at 0. - */ -static void read_eagain_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "read failed with EAGAIN as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} - -/* - * Test whether writing to counter works. + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes */ -static void write_test(int fd) -{ - int ret; - uint64_t val; - - val = 12; - ret = set_counter(fd, val); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, val); - return; - } +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" - read_test(fd, val); -} +#define EVENT_COUNT 10 -/* - * Test whether write returns with error EAGAIN when counter is at - * (UINT64_MAX - 1). - */ -static void write_eagain_test(int fd) +static void run(void) { - int ret; + int fd; uint64_t val; - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - val = 1; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "write failed with EAGAIN as expected"); - else - tst_resm(TFAIL, "write failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} - -/* - * Test whether read returns with error EINVAL, if buffer size is less - * than 8 bytes. - */ -static void read_einval_test(int fd) -{ uint32_t invalid; - int ret; - ret = read(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "read failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} + fd = TST_EXP_FD(eventfd(EVENT_COUNT, EFD_NONBLOCK)); -/* - * Test whether write returns with error EINVAL, if buffer size is - * less than 8 bytes. - */ -static void write_einval_test(int fd) -{ - uint32_t invalid; - int ret; + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, EVENT_COUNT); - ret = write(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} + TST_EXP_FAIL(read(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(read(fd, &invalid, sizeof(invalid)), EINVAL); -/* - * Test wheter write returns with error EINVAL, when the written value - * is 0xFFFFFFFFFFFFFFFF. - */ -static void write_einval2_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - val = 0xffffffffffffffffLL; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else { - tst_resm(TFAIL, "write returned with %d", ret); - } + SAFE_CLOSE(fd); } -/* - * Test whether readfd is set by select when counter value is - * non-zero. - */ -static void readfd_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - uint64_t non_zero = 10; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = set_counter(fd, non_zero); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_zero); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is set in readfds"); - else - tst_resm(TFAIL, "fd is not set in readfds"); -} - -/* - * Test whether readfd is not set by select when counter value is - * zero. - */ -static void readfd_not_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (!FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is not set in readfds"); - else - tst_resm(TFAIL, "fd is set in readfds"); -} - -/* - * Test whether writefd is set by select when counter value is not the - * maximum counter value. - */ -static void writefd_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - uint64_t non_max = 10; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, non_max); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_max); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is set in writefds"); - else - tst_resm(TFAIL, "fd is not set in writefds"); -} - -/* - * Test whether writefd is not set by select when counter value is at - * (UINT64_MAX - 1). - */ -static void writefd_not_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (!FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is not set in writefds"); - else - tst_resm(TFAIL, "fd is set in writefds"); -} - -/* - * Test whether counter update in child is reflected in the parent. - */ -static void child_inherit_test(int fd) -{ - uint64_t val; - pid_t cpid; - int ret; - int status; - uint64_t to_parent = 0xdeadbeef; - uint64_t dummy; - - cpid = fork(); - if (cpid == -1) - tst_resm(TBROK | TERRNO, "fork failed"); - else if (cpid != 0) { - ret = wait(&status); - if (ret == -1) { - tst_resm(TBROK, "error getting child exit status"); - return; - } - - if (WEXITSTATUS(status) == 1) { - tst_resm(TBROK, "counter value write not " - "successful in child"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == to_parent) - tst_resm(TPASS, "counter value write from " - "child successful"); - else - tst_resm(TFAIL, "counter value write in child " - "failed"); - } else { - /* Child */ - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1 && errno != EAGAIN) { - tst_resm(TWARN | TERRNO, "error clearing counter"); - exit(1); - } - - ret = write(fd, &to_parent, sizeof(to_parent)); - if (ret == -1) { - tst_resm(TWARN | TERRNO, "error writing eventfd"); - exit(1); - } - - exit(0); - } -} - -#ifdef HAVE_IO_SET_EVENTFD -/* - * Test whether counter overflow is detected and handled correctly. - * - * It is not possible to directly overflow the counter using the - * write() syscall. Overflows occur when the counter is incremented - * from kernel space, in an irq context, when it is not possible to - * block the calling thread of execution. - * - * The AIO subsystem internally uses eventfd mechanism for - * notification of completion of read or write requests. In this test - * we trigger a counter overflow, by setting the counter value to the - * max possible value initially. When the AIO subsystem notifies - * through the eventfd counter, the counter overflows. - * - * NOTE: If the the counter starts from an initial value of 0, it will - * take decades for an overflow to occur. But since we set the initial - * value to the max possible counter value, we are able to cause it to - * overflow with a single increment. - * - * When the counter overflows, the following are tested - * 1. Check whether POLLERR event occurs in poll() for the eventfd. - * 2. Check whether readfd_set/writefd_set is set in select() for the - eventfd. - * 3. The counter value is UINT64_MAX. - */ -static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) -{ - int ret; - struct iocb iocb; - struct iocb *iocbap[1]; - struct io_event ioev; - static char buf[4 * 1024]; - - *ctx = 0; - ret = io_setup(16, ctx); - if (ret < 0) { - errno = -ret; - if (errno == ENOSYS) { - tst_brkm(TCONF | TERRNO, cleanup, - "io_setup(): AIO not supported by kernel"); - } - - tst_resm(TINFO | TERRNO, "io_setup error"); - return -1; - } - - *fd = open("testfile", O_RDWR | O_CREAT, 0644); - if (*fd == -1) { - tst_resm(TINFO | TERRNO, "open(testfile) failed"); - goto err_io_destroy; - } - - ret = set_counter(evfd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); - goto err_close_file; - } - - io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); - io_set_eventfd(&iocb, evfd); - - iocbap[0] = &iocb; - ret = io_submit(*ctx, 1, iocbap); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error submitting iocb"); - goto err_close_file; - } - - ret = io_getevents(*ctx, 1, 1, &ioev, NULL); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error waiting for event"); - goto err_close_file; - } - - return 0; - -err_close_file: - close(*fd); - -err_io_destroy: - io_destroy(*ctx); - - return -1; -} - -static void cleanup_overflow(int fd, io_context_t ctx) -{ - close(fd); - io_destroy(ctx); -} - -static void overflow_select_test(int evfd) -{ - struct timeval timeout = { 10, 0 }; - fd_set readfds; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - FD_ZERO(&readfds); - FD_SET(evfd, &readfds); - ret = select(evfd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) - tst_resm(TBROK | TERRNO, - "error getting evfd status with select"); - else { - if (FD_ISSET(evfd, &readfds)) - tst_resm(TPASS, "read fd set as expected"); - else - tst_resm(TFAIL, "read fd not set"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_poll_test(int evfd) -{ - struct pollfd pollfd; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - pollfd.fd = evfd; - pollfd.events = POLLIN; - pollfd.revents = 0; - ret = poll(&pollfd, 1, 10000); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error getting evfd status with poll"); - else { - if (pollfd.revents & POLLERR) - tst_resm(TPASS, "POLLERR occurred as expected"); - else - tst_resm(TFAIL, "POLLERR did not occur"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_read_test(int evfd) -{ - uint64_t count; - io_context_t ctx; - int fd; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - ret = read(evfd, &count, sizeof(count)); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error reading eventfd"); - else { - - if (count == UINT64_MAX) - tst_resm(TPASS, "overflow occurred as expected"); - else - tst_resm(TFAIL, "overflow did not occur"); - } - cleanup_overflow(fd, ctx); -} -#else -static void overflow_select_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} - -static void overflow_poll_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} - -static void overflow_read_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} -#endif - -int main(int argc, char **argv) -{ - int lc; - int fd; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int ret; - uint64_t einit = 10; - - tst_count = 0; - - fd = myeventfd(einit, 0); - if (fd == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error creating eventfd"); - - ret = fcntl(fd, F_SETFL, O_NONBLOCK); - if (ret == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error setting non-block mode"); - - read_test(fd, einit); - read_eagain_test(fd); - write_test(fd); - write_eagain_test(fd); - read_einval_test(fd); - write_einval_test(fd); - write_einval2_test(fd); - readfd_set_test(fd); - readfd_not_set_test(fd); - writefd_set_test(fd); - writefd_not_set_test(fd); - child_inherit_test(fd); - overflow_select_test(fd); - overflow_poll_test(fd); - overflow_read_test(fd); - - close(fd); - } - - cleanup(); - - tst_exit(); -} - -static void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - TEST_PAUSE; -} - -static void cleanup(void) -{ - tst_rmdir(); -} - -#else -int main(void) -{ - tst_brkm(TCONF, NULL, "test requires libaio and it's development packages"); -} -#endif +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd02.c b/testcases/kernel/syscalls/eventfd/eventfd02.c new file mode 100644 index 000000000..f028961c7 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd02.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Verify write operation for eventfd fail with: + * + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes, or if an attempt is made to + * write the value 0xffffffffffffffff + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val = 12; + uint64_t buf; + uint32_t invalid; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + SAFE_WRITE(0, fd, &val, sizeof(val)); + SAFE_READ(0, fd, &buf, sizeof(buf)); + TST_EXP_EQ_LI(buf, val); + + val = UINT64_MAX - 1; + SAFE_WRITE(0, fd, &val, sizeof(val)); + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(write(fd, &invalid, sizeof(invalid)), EINVAL); + + val = 0xffffffffffffffffLL; + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EINVAL); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd03.c b/testcases/kernel/syscalls/eventfd/eventfd03.c new file mode 100644 index 000000000..452264cad --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd03.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether readfd is set by select() when eventfd() counter value is + * non-zero, then check if readfd is not set when eventfd() counter value is + * zero. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + fd_set readfds; + uint64_t non_zero = 10; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + SAFE_WRITE(0, fd, &non_zero, sizeof(non_zero)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd04.c b/testcases/kernel/syscalls/eventfd/eventfd04.c new file mode 100644 index 000000000..c7186ae64 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd04.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether writefd is set by select() when eventfd() counter value is + * not the maximum value, then check if writefd is not set when eventfd() + * counter value is maximum value. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + fd_set writefds; + uint64_t val; + uint64_t non_max = 10; + uint64_t max = UINT64_MAX - 1; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + SAFE_WRITE(0, fd, &non_max, sizeof(non_max)); + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + SAFE_WRITE(0, fd, &max, sizeof(max)); + + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd05.c b/testcases/kernel/syscalls/eventfd/eventfd05.c new file mode 100644 index 000000000..6ea2c4138 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd05.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether eventfd() counter update in child is reflected in the parent. + */ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + uint64_t to_parent = 0xdeadbeef; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + if (!SAFE_FORK()) { + SAFE_WRITE(0, fd, &to_parent, sizeof(to_parent)); + exit(0); + } + + tst_reap_children(); + + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, to_parent); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd06.c b/testcases/kernel/syscalls/eventfd/eventfd06.c new file mode 100644 index 000000000..7339dd471 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd06.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Test whether counter overflow is detected and handled correctly. + * + * It is not possible to directly overflow the counter using the + * write() syscall. Overflows occur when the counter is incremented + * from kernel space, in an IRQ context, when it is not possible to + * block the calling thread of execution. + * + * The AIO subsystem internally uses eventfd mechanism for + * notification of completion of read or write requests. In this test + * we trigger a counter overflow, by setting the counter value to the + * max possible value initially. When the AIO subsystem notifies + * through the eventfd counter, the counter overflows. + * + * If the counter starts from an initial value of 0, it will + * take decades for an overflow to occur. But since we set the initial + * value to the max possible counter value, we are able to cause it to + * overflow with a single increment. + * + * When the counter overflows, the following is tested: + * + * - POLLERR event occurs in poll() for the eventfd + * - readfd_set/writefd_set is set in select() for the eventfd + * - the counter value is UINT64_MAX + */ + +#include "tst_test.h" + +#ifdef HAVE_LIBAIO +#ifdef HAVE_IO_SET_EVENTFD + +#include <poll.h> +#include <libaio.h> +#include <stdlib.h> +#include <sys/eventfd.h> + +#define MAXEVENTS 16 +#define BUFSIZE 1024 + +static int fd; +static int evfd; +static io_context_t ctx; + +static void async_write(void) +{ + struct iocb iocb; + struct iocb *iocbap[1]; + struct io_event ioev; + static char buf[BUFSIZE]; + + memset(buf, 1, BUFSIZE); + + io_prep_pwrite(&iocb, fd, buf, sizeof(buf), 0); + io_set_eventfd(&iocb, evfd); + + iocbap[0] = &iocb; + TEST(io_submit(ctx, 1, iocbap)); + if (TST_RET < 0) + tst_brk(TBROK, "io_submit() failed: %s", tst_strerrno(-TST_RET)); + + TEST(io_getevents(ctx, 1, 1, &ioev, NULL)); + if (TST_RET < 0) + tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-TST_RET)); +} + +static void clear_counter(void) +{ + uint64_t val; + uint64_t max = UINT64_MAX - 1; + + TEST(read(evfd, &val, sizeof(val))); + if (TST_RET == -1 && TST_ERR != EAGAIN) + tst_brk(TBROK | TERRNO, "read"); + + SAFE_WRITE(0, evfd, &max, sizeof(max)); +} + +static void test_select(void) +{ + fd_set readfds; + uint64_t count; + struct timeval timeout = { 10, 0 }; + + clear_counter(); + async_write(); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + tst_res(TINFO, "Checking if select() detects counter overflow"); + + TEST(select(fd + 1, NULL, &readfds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void test_poll(void) +{ + uint64_t count; + struct pollfd pollfd; + + clear_counter(); + async_write(); + + pollfd.fd = evfd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + tst_res(TINFO, "Checking if poll() detects counter overflow"); + + TEST(poll(&pollfd, 1, 10000)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "poll"); + + TST_EXP_EQ_LI(pollfd.revents & POLLERR, POLLERR); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void setup(void) +{ + TEST(io_setup(MAXEVENTS, &ctx)); + if (TST_RET < 0) + tst_brk(TBROK, "io_setup() failed: %s", tst_strerrno(-TST_RET)); + + fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644); + evfd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); +} + +static void cleanup(void) +{ + SAFE_CLOSE(evfd); + io_destroy(ctx); +} + +static void run(void) +{ + test_select(); + test_poll(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; + +#else /* HAVE_IO_SET_EVENTFD */ +TST_TEST_TCONF("eventfd support is not available in AIO subsystem"); +#endif +#else /* HAVE_LIBAIO */ +TST_TEST_TCONF("libaio is not available"); +#endif diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2.h b/testcases/kernel/syscalls/eventfd2/eventfd2.h new file mode 100644 index 000000000..5350820b8 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd2/eventfd2.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +#include "tst_test.h" +#include "lapi/syscalls.h" + +static inline int eventfd2(unsigned int count, unsigned int flags) +{ + int ret; + + ret = tst_syscall(__NR_eventfd2, count, flags); + if (ret == -1) + tst_brk(TBROK | TERRNO, "eventfd2"); + + return ret; +} diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c index 85ad86d42..3a80379a3 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c @@ -1,119 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_01.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b087498eb5605673b0f260a7620d91818cd72304 */ -/* says: */ -/* This patch adds the new eventfd2 syscall. It extends the old eventfd */ -/* syscall by one parameter which is meant to hold a flag value. In this */ -/* patch the only flag support is EFD_CLOEXEC which causes the close-on-exec */ -/* flag for the returned file descriptor to be set. A new name EFD_CLOEXEC is */ -/* introduced which in this implementation must have the same value as */ -/* O_CLOEXEC. The following test must be adjusted for architectures other than*/ -/* x86 and x86-64 and in case the syscall numbers changed. */ -/* */ -/* Usage: <for command-line> */ -/* eventfd2_01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_01 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 08 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 08 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ -#include <stdio.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_CLOEXEC O_CLOEXEC - -char *TCID = "eventfd2_01"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set FD_CLOEXEC flag on file when + * EFD_CLOEXEC flag is used. + */ + +#include <fcntl.h> +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - tst_rmdir(); -} + int fd, flags; -void setup(void) -{ - TEST_PAUSE; - tst_tmpdir(); -} + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR(!(flags & FD_CLOEXEC), "FD_CLOEXEC is not set"); + SAFE_CLOSE(fd); -int main(int argc, char *argv[]) -{ - int fd, coe; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - fd = tst_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (coe & FD_CLOEXEC) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) set close-on-exec flag"); - } - close(fd); - - fd = tst_syscall(__NR_eventfd2, 1, EFD_CLOEXEC); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_CLOEXEC) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((coe & FD_CLOEXEC) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_CLOEXEC) does not set close-on-exec flag"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_CLOEXEC) Passed"); - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_CLOEXEC); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR((flags & FD_CLOEXEC), "FD_CLOEXEC is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c index 5f3b6ee67..430cdb33c 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c @@ -1,118 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_02.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e7d476dfdf0bcfed478a207aecfdc84f81efecaf */ -/* which says: */ -/* This patch adds support for the EFD_NONBLOCK flag to eventfd2. The */ -/* additional changes needed are minimal. The following test must be adjusted */ -/* or architectures other than x86 and x86-64 and in case the syscall numbers */ -/* changed. */ -/* */ -/* Usage: <for command-line> */ -/* eventfd2_02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_02 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ -#include <stdio.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_NONBLOCK O_NONBLOCK - -char *TCID = "eventfd2_02"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) -{ - tst_rmdir(); -} - -void setup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set O_NONBLOCK flag on file when + * EFD_NONBLOCK flag is used. + */ + +#include <fcntl.h> +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - TEST_PAUSE; - tst_tmpdir(); -} - -int main(int argc, char *argv[]) -{ - int fd, fl; - - tst_parse_opts(argc, argv, NULL, NULL); + int fd, flags; - setup(); + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR(!(flags & O_NONBLOCK), "O_NONBLOCK is not set"); + SAFE_CLOSE(fd); - tst_count = 0; - fd = tst_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (fl & O_NONBLOCK) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) sets non-blocking mode"); - } - close(fd); - - fd = tst_syscall(__NR_eventfd2, 1, EFD_NONBLOCK); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_NONBLOCK) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((fl & O_NONBLOCK) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_NONBLOCK) didn't set non-blocking mode"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_NONBLOCK) PASSED"); - - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_NONBLOCK); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR((flags & O_NONBLOCK), "O_NONBLOCK is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c index 909004edb..e1949fd32 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c @@ -1,139 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * eventfd-sem by Davide Libenzi (Simple test for eventfd sempahore) - * Copyright (C) 2009 Davide Libenzi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Davide Libenzi <davidel@xmailserver.org> - * Reference: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=bcd0b235bf3808dec5115c381cd55568f63b85f0 - * Reference: http://www.xmailserver.org/eventfd-sem.c - * eventfd: testing improved support for semaphore-like behavior in linux-2.6.30 + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] * + * This test verifies that eventfd2 semaphore-like support is properly working. */ -#include <sys/types.h> -#include <sys/syscall.h> -#include <sys/stat.h> -#include <sys/wait.h> #include <fcntl.h> #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <inttypes.h> - -#include "test.h" -#include "lapi/syscalls.h" - -char *TCID = "eventfd2_03"; -int TST_TOTAL = 1; - -#ifndef EFD_SEMLIKE -#define EFD_SEMLIKE (1 << 0) -#endif - -/* Dummy function as syscall from linux_syscall_numbers.h uses cleanup(). */ -void cleanup(void) -{ -} - -static int eventfd2(int count, int flags) -{ - return tst_syscall(__NR_eventfd2, count, flags); -} +#include <sys/eventfd.h> +#include "tst_test.h" +#include "eventfd2.h" static void xsem_wait(int fd) { u_int64_t cntr; - if (read(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("reading eventfd"); - exit(1); - } - fprintf(stdout, "[%u] wait completed on %d: count=%" PRIu64 "\n", - getpid(), fd, cntr); + SAFE_READ(0, fd, &cntr, sizeof(cntr)); } static void xsem_post(int fd, int count) { u_int64_t cntr = count; - if (write(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("writing eventfd"); - exit(1); - } + SAFE_WRITE(0, fd, &cntr, sizeof(cntr)); } static void sem_player(int fd1, int fd2) { - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); - xsem_post(fd1, 1); + pid_t pid = getpid(); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); - xsem_wait(fd2); - - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 1 on fd=%d", pid, fd1); xsem_post(fd1, 1); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting on fd=%d", pid, fd2); xsem_wait(fd2); - fprintf(stdout, "[%u] posting 5 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 5 on fd=%d", pid, fd1); xsem_post(fd1, 5); - fprintf(stdout, "[%u] waiting 5 times on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting 5 times on fd=%d", pid, fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); -} -static void usage(char const *prg) -{ - fprintf(stderr, "use: %s [-h]\n", prg); + tst_res(TPASS, "[%u] received all events", pid); } -int main(int argc, char **argv) +static void run(void) { - int c, fd1, fd2, status; pid_t cpid_poster, cpid_waiter; + int fd1, fd2; - while ((c = getopt(argc, argv, "h")) != -1) { - switch (c) { - default: - usage(argv[0]); - return 1; - } - } - if ((fd1 = eventfd2(0, EFD_SEMLIKE)) == -1 || - (fd2 = eventfd2(0, EFD_SEMLIKE)) == -1) { - perror("eventfd2"); - return 1; - } - if ((cpid_poster = fork()) == 0) { + fd1 = eventfd2(0, EFD_SEMAPHORE); + fd2 = eventfd2(0, EFD_SEMAPHORE); + + cpid_poster = SAFE_FORK(); + if (!cpid_poster) { sem_player(fd1, fd2); exit(0); } - if ((cpid_waiter = fork()) == 0) { + + cpid_waiter = SAFE_FORK(); + if (!cpid_waiter) { sem_player(fd2, fd1); exit(0); } - waitpid(cpid_poster, &status, 0); - waitpid(cpid_waiter, &status, 0); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/execve/execve01.c b/testcases/kernel/syscalls/execve/execve01.c index 2b12c7666..53f0475e3 100644 --- a/testcases/kernel/syscalls/execve/execve01.c +++ b/testcases/kernel/syscalls/execve/execve01.c @@ -34,7 +34,7 @@ static void verify_execve(void) pid = SAFE_FORK(); if (pid == 0) { execve(path, args, envp); - tst_brk(TFAIL | TERRNO, "Failed to execute execl01_child"); + tst_brk(TFAIL | TERRNO, "Failed to execute execve01_child"); } } diff --git a/testcases/kernel/syscalls/execve/execve06.c b/testcases/kernel/syscalls/execve/execve06.c index afbfcfa9e..a00089265 100644 --- a/testcases/kernel/syscalls/execve/execve06.c +++ b/testcases/kernel/syscalls/execve/execve06.c @@ -35,7 +35,7 @@ static void verify_execve(void) pid = SAFE_FORK(); if (pid == 0) { execve(path, argv, envp); - tst_brk(TFAIL | TERRNO, "Failed to execute execl01_child"); + tst_brk(TFAIL | TERRNO, "Failed to execute execve06_child"); } } diff --git a/testcases/kernel/syscalls/faccessat/.gitignore b/testcases/kernel/syscalls/faccessat/.gitignore index 9551ab97e..276caca45 100644 --- a/testcases/kernel/syscalls/faccessat/.gitignore +++ b/testcases/kernel/syscalls/faccessat/.gitignore @@ -1 +1,2 @@ /faccessat01 +/faccessat02 diff --git a/testcases/kernel/syscalls/faccessat/faccessat01.c b/testcases/kernel/syscalls/faccessat/faccessat01.c index d11e8cf12..557d7eb4c 100644 --- a/testcases/kernel/syscalls/faccessat/faccessat01.c +++ b/testcases/kernel/syscalls/faccessat/faccessat01.c @@ -1,151 +1,88 @@ -/****************************************************************************** +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] * - * Copyright (c) International Business Machines Corp., 2006 + * Check the basic functionality of the faccessat() system call. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * - faccessat() passes if dir_fd is file descriptor to the directory + * where the file is located and pathname is relative path of the file. * - * This program 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 General Public License for more details. + * - faccessat() passes if dir_fd is a bad file descriptor and pathname is + * absolute path of the file. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NAME - * faccessat01.c - * - * DESCRIPTION - * This test case will verify basic function of faccessat - * added by kernel 2.6.16 or up. - * - * Author - * Yi Yang <yyangcdl@cn.ibm.com> - * - * History - * 08/28/2006 Created first by Yi Yang <yyangcdl@cn.ibm.com> - * - *****************************************************************************/ - -#define _GNU_SOURCE + * - faccessat() passes if dir_fd is AT_FDCWD and pathname is interpreted + * relative to the current working directory of the calling process. + */ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> #include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/syscalls.h" - -#define TEST_CASES 6 -#ifndef AT_FDCWD -#define AT_FDCWD -100 -#endif -void setup(); -void cleanup(); - -char *TCID = "faccessat01"; -int TST_TOTAL = TEST_CASES; -static char pathname[256]; -static char testfile[256]; -static char testfile2[256]; -static char testfile3[256]; -static int fds[TEST_CASES]; -static char *filenames[TEST_CASES]; -static int expected_errno[TEST_CASES] = { 0, 0, ENOTDIR, EBADF, 0, 0 }; - -int myfaccessat(int dirfd, const char *filename, int mode) +#include <stdio.h> +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int atcwd_fd = AT_FDCWD; +static char *abs_path; +static char *test_file; +static char *file_path; + +static struct tcase { + int *fd; + char **filename; + int exp_errno; +} tcases[] = { + {&dir_fd, &test_file, 0}, + {&dir_fd, &abs_path, 0}, + {&atcwd_fd, &file_path, 0}, +}; + +static void verify_faccessat(unsigned int i) { - return tst_syscall(__NR_faccessat, dirfd, filename, mode); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - /* - * Call faccessat - */ - for (i = 0; i < TST_TOTAL; i++) { - TEST(myfaccessat(fds[i], filenames[i], R_OK)); - - /* check return code */ - if (TEST_ERRNO == expected_errno[i]) { - tst_resm(TPASS, - "faccessat() returned the expected errno %d: %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, - "faccessdat() Failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } - } - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(faccessat(*tc->fd, *tc->filename, R_OK, 0), + "faccessat(%d, %s, R_OK, 0)", + *tc->fd, *tc->filename); } -void setup(void) +static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - char *abs_path = tst_get_tmpdir(); - int p = getpid(); - - /* Initialize test dir and file names */ - sprintf(pathname, "faccessattestdir%d", p); - sprintf(testfile, "faccessattestfile%d.txt", p); - sprintf(testfile2, "%s/faccessattestfile%d.txt", abs_path, p); - sprintf(testfile3, "faccessattestdir%d/faccessattestfile%d.txt", p, p); - - free(abs_path); + char *tmpdir_path = tst_get_tmpdir(); - SAFE_MKDIR(cleanup, pathname, 0700); + abs_path = tst_aprintf("%s/%s", tmpdir_path, FILEPATH); + free(tmpdir_path); - fds[0] = SAFE_OPEN(cleanup, pathname, O_DIRECTORY); - fds[1] = fds[4] = fds[0]; - - SAFE_FILE_PRINTF(cleanup, testfile, "%s", testfile); - SAFE_FILE_PRINTF(cleanup, testfile2, "%s", testfile2); - - fds[2] = SAFE_OPEN(cleanup, testfile3, O_CREAT | O_RDWR, 0600); - - fds[3] = 100; - fds[5] = AT_FDCWD; - - filenames[0] = filenames[2] = filenames[3] = filenames[4] = testfile; - filenames[1] = testfile2; - filenames[5] = testfile3; - - TEST_PAUSE; + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); } -void cleanup(void) +static void cleanup(void) { - if (fds[0] > 0) - close(fds[0]); - if (fds[2] > 0) - close(fds[2]); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (file_fd > -1) + SAFE_CLOSE(file_fd); } + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&file_path, .str = FILEPATH}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat/faccessat02.c b/testcases/kernel/syscalls/faccessat/faccessat02.c new file mode 100644 index 000000000..1add695c1 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat/faccessat02.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] + * + * - faccessat() fails with ENOTDIR if dir_fd is file descriptor to the file + * and pathname is relative path of the file. + * + * - faccessat() fails with EBADF if dir_fd is invalid. + */ + +#include <stdlib.h> +#include <stdio.h> +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int bad_fd = -1; + +static struct tcase { + int *fd; + int exp_errno; +} tcases[] = { + {&file_fd, ENOTDIR}, + {&bad_fd, EBADF}, +}; + +static void verify_faccessat(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_FAIL(faccessat(*tc->fd, TESTFILE, R_OK, 0), + tc->exp_errno, "faccessat(%d, TESTFILE, R_OK, 0)", + *tc->fd); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/.gitignore b/testcases/kernel/syscalls/faccessat2/.gitignore new file mode 100644 index 000000000..f58f045f4 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/.gitignore @@ -0,0 +1,2 @@ +/faccessat201 +/faccessat202 diff --git a/testcases/kernel/syscalls/faccessat2/Makefile b/testcases/kernel/syscalls/faccessat2/Makefile new file mode 100644 index 000000000..aaac6b703 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. +# Author: Yang Xu <xuyang2018.jy@fujitsu.com> + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/faccessat2/faccessat201.c b/testcases/kernel/syscalls/faccessat2/faccessat201.c new file mode 100644 index 000000000..012091752 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat201.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * Check the basic functionality of faccessat2(). + * + * Minimum Linux version required is v5.8. + */ + +#include <stdlib.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTDIR "faccessat2dir" +#define TESTFILE "faccessat2file" +#define RELPATH "faccessat2dir/faccessat2file" +#define TESTSYMLINK "faccessat2symlink" + +static int dir_fd, bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *testfile; +static char *abs_path; +static char *rel_path; +static char *sym_path; + +static struct tcase { + int *fd; + char **filename; + int flags; +} tcases[] = { + {&dir_fd, &testfile, 0}, + {&bad_fd, &abs_path, 0}, + {&atcwd_fd, &rel_path, 0}, + {&dir_fd, &testfile, AT_EACCESS}, + {&bad_fd, &abs_path, AT_EACCESS}, + {&atcwd_fd, &rel_path, AT_EACCESS}, + {&atcwd_fd, &sym_path, AT_SYMLINK_NOFOLLOW}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_PASS(faccessat2(*tc->fd, *tc->filename, R_OK, tc->flags), + "faccessat2(%d, %s, R_OK, %d)", + *tc->fd, *tc->filename, tc->flags); +} + +static void setup(void) +{ + char *tmpdir_path = tst_get_tmpdir(); + + abs_path = tst_aprintf("%s/%s", tmpdir_path, RELPATH); + free(tmpdir_path); + + SAFE_MKDIR(TESTDIR, 0777); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + SAFE_TOUCH(abs_path, 0444, NULL); + SAFE_SYMLINK(abs_path, TESTSYMLINK); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testfile, .str = TESTFILE}, + {&rel_path, .str = RELPATH}, + {&sym_path, .str = TESTSYMLINK}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/faccessat202.c b/testcases/kernel/syscalls/faccessat2/faccessat202.c new file mode 100644 index 000000000..a60db2bf8 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat202.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * Test basic error handling of faccessat2 syscall: + * + * - faccessat2() fails with EFAULT if pathname is a bad pathname point. + * - faccessat2() fails with EINVAL if flags is -1. + * - faccessat2() fails with EINVAL if mode is -1. + * - faccessat2() fails with EBADF if dirfd is -1. + * - faccessat2() fails with ENOTDIR if pathname is relative path to a + * file and dir_fd is file descriptor for this file. + * - faccessat2() fails with EACCES if flags is AT_EACCESS and not using + * the effective user and group IDs. + * + * Minimum Linux version required is v5.8. + */ + +#include <pwd.h> + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTUSER "nobody" +#define TESTDIR "faccessat2dir" +#define RELPATH "faccessat2dir/faccessat2file" + +static int fd; +static int bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *bad_path; +static char *rel_path; + +static struct passwd *ltpuser; + +static struct tcase { + int *fd; + char **filename; + int mode; + int flags; + int exp_errno; + const char *desc; +} tcases[] = { + {&atcwd_fd, &bad_path, R_OK, 0, EFAULT, "invalid address"}, + {&atcwd_fd, &rel_path, R_OK, -1, EINVAL, "invalid flags"}, + {&atcwd_fd, &rel_path, -1, 0, EINVAL, "invalid mode"}, + {&bad_fd, &rel_path, R_OK, 0, EBADF, "invalid fd"}, + {&fd, &rel_path, R_OK, 0, ENOTDIR, "fd pointing to file"}, + {&atcwd_fd, &rel_path, R_OK, AT_EACCESS, EACCES, + "AT_EACCESS and unprivileged EUID"}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(ltpuser->pw_uid); + + TST_EXP_FAIL(faccessat2(*tc->fd, *tc->filename, tc->mode, tc->flags), + tc->exp_errno, "faccessat2() with %s", tc->desc); + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(0); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0666); + SAFE_TOUCH(RELPATH, 0444, NULL); + + fd = SAFE_OPEN(RELPATH, O_RDONLY); + bad_path = tst_get_bad_addr(NULL); + + ltpuser = SAFE_GETPWNAM(TESTUSER); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&rel_path, .str = RELPATH}, + {}, + }, + .needs_tmpdir = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index 51078103e..75a081dc9 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -72,6 +72,10 @@ static inline int safe_fanotify_mark(const char *file, const int lineno, #define MAX_HANDLE_SZ 128 #endif +#ifndef AT_HANDLE_FID +#define AT_HANDLE_FID 0x200 +#endif + /* * Helper function used to obtain fsid and file_handle for a given path. * Used by test files correlated to FAN_REPORT_FID functionality. @@ -260,10 +264,27 @@ static inline int fanotify_mark_supported_by_kernel(uint64_t flag) return rval; } +static inline int fanotify_handle_supported_by_kernel(int flag) +{ + /* + * On Kernel that does not support AT_HANDLE_FID this will result + * with EINVAL. On older kernels, this will result in EBADF. + */ + if (name_to_handle_at(-1, "", NULL, NULL, AT_EMPTY_PATH | flag)) { + if (errno == EINVAL) + return -1; + } + return 0; +} + #define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) \ fanotify_init_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \ fanotify_mark_supported_by_kernel(mark_type)) +#define REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(handle_type) \ + fanotify_init_flags_err_msg(#handle_type, __FILE__, __LINE__, tst_brk_, \ + fanotify_handle_supported_by_kernel(handle_type)) + #define REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(init_flags, mark_type, mask, fname) do { \ if (mark_type) \ REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type); \ diff --git a/testcases/kernel/syscalls/fanotify/fanotify13.c b/testcases/kernel/syscalls/fanotify/fanotify13.c index c3daaf3a2..a25a360fd 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify13.c +++ b/testcases/kernel/syscalls/fanotify/fanotify13.c @@ -25,6 +25,7 @@ #include <sys/statfs.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/mount.h> #include <errno.h> #include <unistd.h> #include "tst_test.h" @@ -37,7 +38,7 @@ #define DIR_ONE "dir_one" #define FILE_ONE "file_one" #define FILE_TWO "file_two" -#define MOUNT_PATH "mntpoint" +#define MOUNT_PATH "tstmnt" #define EVENT_MAX ARRAY_SIZE(objects) #define DIR_PATH_ONE MOUNT_PATH"/"DIR_ONE #define FILE_PATH_ONE MOUNT_PATH"/"FILE_ONE @@ -88,6 +89,8 @@ static struct test_case_t { } }; +static int ovl_mounted; +static int bind_mounted; static int nofid_fd; static int fanotify_fd; static int filesystem_mark_unsupported; @@ -143,8 +146,13 @@ static void do_test(unsigned int number) struct fanotify_mark_type *mark = &tc->mark; tst_res(TINFO, - "Test #%d: FAN_REPORT_FID with mark flag: %s", - number, mark->name); + "Test #%d.%d: FAN_REPORT_FID with mark flag: %s", + number, tst_variant, mark->name); + + if (tst_variant && !ovl_mounted) { + tst_res(TCONF, "overlayfs not supported on %s", tst_device->fs_type); + return; + } if (filesystem_mark_unsupported && mark->flag & FAN_MARK_FILESYSTEM) { tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?"); @@ -160,6 +168,15 @@ static void do_test(unsigned int number) if (setup_marks(fanotify_fd, tc) != 0) goto out; + /* Variant #1: watching upper fs - open files on overlayfs */ + if (tst_variant == 1) { + if (mark->flag & FAN_MARK_MOUNT) { + tst_res(TCONF, "overlayfs upper fs cannot be watched with mount mark"); + goto out; + } + SAFE_MOUNT(OVL_MNT, MOUNT_PATH, "none", MS_BIND, NULL); + } + /* Generate sequence of FAN_OPEN events on objects */ for (i = 0; i < ARRAY_SIZE(objects); i++) fds[i] = SAFE_OPEN(objects[i].path, O_RDONLY); @@ -174,6 +191,9 @@ static void do_test(unsigned int number) SAFE_CLOSE(fds[i]); } + if (tst_variant == 1) + SAFE_UMOUNT(MOUNT_PATH); + /* Read events from event queue */ len = SAFE_READ(0, fanotify_fd, events_buf, BUF_SIZE); @@ -261,7 +281,32 @@ out: static void do_setup(void) { - REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MOUNT_PATH); + const char *mnt; + + /* + * Bind mount to either base fs or to overlayfs over base fs: + * Variant #0: watch base fs - open files on base fs + * Variant #1: watch upper fs - open files on overlayfs + * + * Variant #1 tests a bug whose fix bc2473c90fca ("ovl: enable fsnotify + * events on underlying real files") in kernel 6.5 is not likely to be + * backported to older kernels. + * To avoid waiting for events that won't arrive when testing old kernels, + * require that kernel supports encoding fid with new flag AT_HADNLE_FID, + * also merged to 6.5 and not likely to be backported to older kernels. + */ + if (tst_variant) { + REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(AT_HANDLE_FID); + ovl_mounted = TST_MOUNT_OVERLAY(); + mnt = OVL_UPPER; + } else { + mnt = OVL_BASE_MNTPOINT; + + } + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, mnt); + SAFE_MKDIR(MOUNT_PATH, 0755); + SAFE_MOUNT(mnt, MOUNT_PATH, "none", MS_BIND, NULL); + bind_mounted = 1; filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); @@ -287,19 +332,27 @@ static void do_cleanup(void) SAFE_CLOSE(nofid_fd); if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (bind_mounted) { + SAFE_UMOUNT(MOUNT_PATH); + SAFE_RMDIR(MOUNT_PATH); + } + if (ovl_mounted) + SAFE_UMOUNT(OVL_MNT); } static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(test_cases), + .test_variants = 2, .setup = do_setup, .cleanup = do_cleanup, .needs_root = 1, .mount_device = 1, - .mntpoint = MOUNT_PATH, + .mntpoint = OVL_BASE_MNTPOINT, .all_filesystems = 1, .tags = (const struct tst_tag[]) { {"linux-git", "c285a2f01d69"}, + {"linux-git", "bc2473c90fca"}, {} } }; diff --git a/testcases/kernel/syscalls/fanotify/fanotify14.c b/testcases/kernel/syscalls/fanotify/fanotify14.c index bfa0349fe..4596511f0 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify14.c +++ b/testcases/kernel/syscalls/fanotify/fanotify14.c @@ -19,6 +19,9 @@ * * ceaf69f8eadc fanotify: do not allow setting dirent events in mask of non-dir * 8698e3bab4dd fanotify: refine the validation checks on non-dir inode mask + * + * The pipes test cases are regression tests for commit: + * 69562eb0bd3e fanotify: disallow mount/sb marks on kernel internal pseudo fs */ #define _GNU_SOURCE @@ -40,6 +43,7 @@ #define FLAGS_DESC(flags) {(flags), (#flags)} +static int pipes[2] = {-1, -1}; static int fanotify_fd; static int fan_report_target_fid_unsupported; static int ignore_mark_unsupported; @@ -60,94 +64,179 @@ static struct test_case_t { /* when mask.flags == 0, fanotify_init() is expected to fail */ struct test_case_flags_t mask; int expected_errno; + int *pfd; } test_cases[] = { /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ - {FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ - {FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, /* INODE_EVENTS in mask without class FAN_REPORT_FID are not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(0), FLAGS_DESC(INODE_EVENTS), - EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, /* INODE_EVENTS in mask with FAN_MARK_MOUNT are not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID), - FLAGS_DESC(FAN_MARK_MOUNT), FLAGS_DESC(INODE_EVENTS), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME), {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME), {}, - {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_TARGET_FID without FAN_REPORT_FID is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME), - {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME), + .expected_errno = EINVAL, + }, /* FAN_REPORT_TARGET_FID without FAN_REPORT_NAME is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID), - {}, {}, EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID), + .expected_errno = EINVAL, + }, /* FAN_RENAME without FAN_REPORT_NAME is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID), FLAGS_DESC(0), - FLAGS_DESC(FAN_RENAME), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = EINVAL, + }, /* With FAN_MARK_ONLYDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(FAN_MARK_ONLYDIR), - FLAGS_DESC(FAN_OPEN), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_ONLYDIR), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_DELETE on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_DELETE), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_RENAME on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_RENAME), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_ONDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_OPEN | FAN_ONDIR), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, + }, /* With FAN_REPORT_TARGET_FID, FAN_EVENT_ON_CHILD on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), - FLAGS_DESC(0), FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_DELETE on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), FLAGS_DESC(FAN_DELETE), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_RENAME on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), FLAGS_DESC(FAN_RENAME), - ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_ONDIR on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), - FLAGS_DESC(FAN_OPEN | FAN_ONDIR), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE_SURV with FAN_EVENT_ON_CHILD on non-dir is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), - FLAGS_DESC(FAN_MARK_IGNORE_SURV), - FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), ENOTDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on directory is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), FLAGS_DESC(FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EISDIR}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EISDIR, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on mount mark is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), - FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, + }, /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on filesystem mark is not valid */ - {FLAGS_DESC(FAN_CLASS_NOTIF), - FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE), - FLAGS_DESC(FAN_OPEN), EINVAL}, + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, + }, + /* mount mark on anonymous pipe is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, + }, + /* filesystem mark on anonymous pipe is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, + }, }; static void do_test(unsigned int number) @@ -185,11 +274,17 @@ static void do_test(unsigned int number) /* Set mark on non-dir only when expecting error ENOTDIR */ const char *path = tc->expected_errno == ENOTDIR ? FILE1 : MNTPOINT; + int dirfd = AT_FDCWD; + + if (tc->pfd) { + dirfd = tc->pfd[0]; + path = NULL; + } - tst_res(TINFO, "Testing fanotify_mark(FAN_MARK_ADD | %s, %s)", + tst_res(TINFO, "Testing %s with %s", tc->mark.desc, tc->mask.desc); TST_EXP_FD_OR_FAIL(fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark.flags, - tc->mask.flags, AT_FDCWD, path), + tc->mask.flags, dirfd, path), tc->expected_errno); /* @@ -231,12 +326,18 @@ static void do_setup(void) /* Create temporary test file to place marks on */ SAFE_FILE_PRINTF(FILE1, "0"); + /* Create anonymous pipes to place marks on */ + SAFE_PIPE2(pipes, O_CLOEXEC); } static void do_cleanup(void) { if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (pipes[0] != -1) + SAFE_CLOSE(pipes[0]); + if (pipes[1] != -1) + SAFE_CLOSE(pipes[1]); } static struct tst_test test = { @@ -251,6 +352,7 @@ static struct tst_test test = { .tags = (const struct tst_tag[]) { {"linux-git", "ceaf69f8eadc"}, {"linux-git", "8698e3bab4dd"}, + {"linux-git", "69562eb0bd3e"}, {} } }; diff --git a/testcases/kernel/syscalls/fanotify/fanotify22.c b/testcases/kernel/syscalls/fanotify/fanotify22.c index 6596a69c9..a654e8912 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify22.c +++ b/testcases/kernel/syscalls/fanotify/fanotify22.c @@ -41,6 +41,7 @@ #define MOUNT_PATH "test_mnt" #define BASE_DIR "internal_dir" #define BAD_DIR BASE_DIR"/bad_dir" +#define BAD_LINK BASE_DIR"/bad_link" #ifdef HAVE_NAME_TO_HANDLE_AT @@ -50,6 +51,7 @@ static int fd_notify; /* These expected FIDs are common to multiple tests */ static struct fanotify_fid_t null_fid; static struct fanotify_fid_t bad_file_fid; +static struct fanotify_fid_t bad_link_fid; static void trigger_fs_abort(void) { @@ -64,7 +66,7 @@ static void do_debugfs_request(const char *dev, char *request) SAFE_CMD(cmd, NULL, NULL); } -static void tcase2_trigger_lookup(void) +static void trigger_bad_file_lookup(void) { int ret; @@ -75,15 +77,27 @@ static void tcase2_trigger_lookup(void) ret, BAD_DIR, errno, EUCLEAN); } +static void trigger_bad_link_lookup(void) +{ + int ret; + + /* SAFE_OPEN cannot be used here because we expect it to fail. */ + ret = open(MOUNT_PATH"/"BAD_LINK, O_RDONLY, 0); + if (ret != -1 && errno != EUCLEAN) + tst_res(TFAIL, "Unexpected open result(%d) of %s (%d!=%d)", + ret, BAD_LINK, errno, EUCLEAN); +} + + static void tcase3_trigger(void) { - trigger_fs_abort(); - tcase2_trigger_lookup(); + trigger_bad_link_lookup(); + trigger_bad_file_lookup(); } static void tcase4_trigger(void) { - tcase2_trigger_lookup(); + trigger_bad_file_lookup(); trigger_fs_abort(); } @@ -103,7 +117,7 @@ static struct test_case { }, { .name = "Lookup of inode with invalid mode", - .trigger_error = &tcase2_trigger_lookup, + .trigger_error = &trigger_bad_file_lookup, .error_count = 1, .error = EFSCORRUPTED, .fid = &bad_file_fid, @@ -112,8 +126,8 @@ static struct test_case { .name = "Multiple error submission", .trigger_error = &tcase3_trigger, .error_count = 2, - .error = ESHUTDOWN, - .fid = &null_fid, + .error = EFSCORRUPTED, + .fid = &bad_link_fid, }, { .name = "Multiple error submission 2", @@ -247,6 +261,9 @@ static void do_test(unsigned int i) FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH); check_event(event_buf, read_len, tcase); + /* Unmount and mount the filesystem to get it out of the error state */ + SAFE_UMOUNT(MOUNT_PATH); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } static void pre_corrupt_fs(void) @@ -255,9 +272,11 @@ static void pre_corrupt_fs(void) SAFE_MKDIR(MOUNT_PATH"/"BAD_DIR, 0777); fanotify_save_fid(MOUNT_PATH"/"BAD_DIR, &bad_file_fid); + fanotify_save_fid(MOUNT_PATH"/"BASE_DIR, &bad_link_fid); SAFE_UMOUNT(MOUNT_PATH); do_debugfs_request(tst_device->dev, "sif " BAD_DIR " mode 0xff"); + do_debugfs_request(tst_device->dev, "ln <1> " BAD_LINK); SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify23.c b/testcases/kernel/syscalls/fanotify/fanotify23.c index 89fd4f36a..fb812c51e 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify23.c +++ b/testcases/kernel/syscalls/fanotify/fanotify23.c @@ -160,10 +160,16 @@ static void test_fanotify(void) } /* - * drop_caches should evict inode from cache and remove evictable mark + * drop_caches should evict inode from cache and remove evictable mark. + * We call drop_caches twice as once the dentries will just cycle + * through the LRU without being reclaimed and if there are no other + * objects to reclaim, the slab reclaim will just stop instead of + * retrying. Note that this relies on how reclaim of fs objects work + * for the filesystem but this test is restricted to ext2... */ fsync_file(TEST_FILE); SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); + SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); verify_mark_removed(TEST_FILE, "after drop_caches"); diff --git a/testcases/kernel/syscalls/fchmod/fchmod02.c b/testcases/kernel/syscalls/fchmod/fchmod02.c index e60cb33a6..d6abeffce 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod02.c +++ b/testcases/kernel/syscalls/fchmod/fchmod02.c @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] * - * Test Description: - * Verify that, fchmod() will succeed to change the mode of a file/directory - * set the sticky bit on it if invoked by root (uid = 0) process with - * the following constraints, - * - the process is not the owner of the file/directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file/directory. + * Verify that, fchmod(2) will succeed to change the mode of a file/directory + * set the sticky bit on it if invoked by root (uid = 0) process with + * the following constraints: * - * Expected Result: - * fchmod() should return value 0 on success and succeeds to set sticky bit - * on the specified file. + * - the process is not the owner of the file/directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file/directory */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchmod/fchmod03.c b/testcases/kernel/syscalls/fchmod/fchmod03.c index 12a6f5a93..bdd720c37 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod03.c +++ b/testcases/kernel/syscalls/fchmod/fchmod03.c @@ -8,10 +8,11 @@ * * Verify that, fchmod(2) will succeed to change the mode of a file * and set the sticky bit on it if invoked by non-root (uid != 0) - * process with the following constraints, - * - the process is the owner of the file. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file. + * process with the following constraints: + * + * - the process is the owner of the file + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchmod/fchmod04.c b/testcases/kernel/syscalls/fchmod/fchmod04.c index d60cb39b2..4fa69e227 100644 --- a/testcases/kernel/syscalls/fchmod/fchmod04.c +++ b/testcases/kernel/syscalls/fchmod/fchmod04.c @@ -8,10 +8,11 @@ * * Verify that, fchmod(2) will succeed to change the mode of a directory * and set the sticky bit on it if invoked by non-root (uid != 0) process - * with the following constraints, - * - the process is the owner of the directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the directory. + * with the following constraints: + * + * - the process is the owner of the directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the directory */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/fchown/fchown02.c b/testcases/kernel/syscalls/fchown/fchown02.c index d02f5bc92..bd1baf3bb 100644 --- a/testcases/kernel/syscalls/fchown/fchown02.c +++ b/testcases/kernel/syscalls/fchown/fchown02.c @@ -10,6 +10,7 @@ * [Description] * * Verify that fchown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/fcntl/.gitignore b/testcases/kernel/syscalls/fcntl/.gitignore index 48b36ec34..10cb0995f 100644 --- a/testcases/kernel/syscalls/fcntl/.gitignore +++ b/testcases/kernel/syscalls/fcntl/.gitignore @@ -8,8 +8,6 @@ /fcntl04_64 /fcntl05 /fcntl05_64 -/fcntl06 -/fcntl06_64 /fcntl07 /fcntl07_64 /fcntl08 diff --git a/testcases/kernel/syscalls/fcntl/fcntl06.c b/testcases/kernel/syscalls/fcntl/fcntl06.c deleted file mode 100644 index 8dcc04866..000000000 --- a/testcases/kernel/syscalls/fcntl/fcntl06.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * NAME - * fcntl06.c - * - * DESCRIPTION - * Error checking conditions for remote locking of regions of a file. - * - * CALLS - * open(2), write(2), fcntl(2) - * - * ALGORITHM - * Test unlocking sections around a write lock using remote Lock/Unlock - * call which should all fail. - * - * USAGE - * fcntl06 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Currently Linux kernel doesn't implement R_GETLK/R_SETLK facility, - * but this facility seems to be present in other standard flavours of - * Unix. Currently this program has all the testing done under - * "#ifdef LINUX_FILE_REGION_LOCK", when Linux implements the regions - * locking then, this testcase should be recompiled accordingly with the - * "ifdef" removed. - */ - -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "test.h" - -#define F_RGETLK 10 /* kludge code */ -#define F_RSETLK 11 /* kludge code */ - -char *TCID = "fcntl06"; -int TST_TOTAL = 1; - -void setup(); -void cleanup(); - -#define STRINGSIZE 27 -#define STRING "abcdefghijklmnopqrstuvwxyz\n" - -int fd; -void unlock_file(); -int do_lock(int, short, short, int, int); - -int main(int ac, char **av) -{ - int fail = 0; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - fail = 0; - -#ifdef LINUX_FILE_REGION_LOCK - if (fcntl(fd, F_RGETLK, &tl) == -1) { - if (errno == EINVAL) - tst_brkm(TCONF, cleanup, - "fcntl remote locking feature not implemented in " - "the kernel"); - else { - /* - * FIXME (garrcoop): having it always pass on - * non-EINVAL is a bad test. - */ - tst_resm(TPASS, "fcntl on file failed"); - } - } - - /* - * Add a write lock to the middle of the file and unlock a section - * just before the lock - */ - if (do_lock(F_RSETLK, F_WRLCK, 0, 10, 5) == -1) - tst_resm(TFAIL, "F_RSETLK WRLCK failed"); - - if (do_lock(F_RSETLK, F_UNLCK, 0, 5, 5) == -1) - tst_resm(TFAIL | TERRNO, "F_RSETLK UNLOCK failed"); - - unlock_file(); -#else - tst_resm(TCONF, "system doesn't have LINUX_LOCK_FILE_REGION support"); -#endif - - cleanup(); - tst_exit(); -} - -void setup(void) -{ - char *buf = STRING; - char template[PATH_MAX]; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - umask(0); - - TEST_PAUSE; - - tst_tmpdir(); - - snprintf(template, PATH_MAX, "fcntl06XXXXXX"); - - if ((fd = mkstemp(template)) == -1) - tst_resm(TBROK | TERRNO, "mkstemp failed"); - - if (write(fd, buf, STRINGSIZE) == -1) - tst_resm(TBROK | TERRNO, "write failed"); -} - -int do_lock(int cmd, short type, short whence, int start, int len) -{ - struct flock fl; - - fl.l_type = type; - fl.l_whence = whence; - fl.l_start = start; - fl.l_len = len; - return (fcntl(fd, cmd, &fl)); -} - -void unlock_file(void) -{ - if (do_lock(F_RSETLK, (short)F_UNLCK, (short)0, 0, 0) == -1) { - /* Same as FIXME comment above. */ - tst_resm(TPASS | TERRNO, "fcntl on file failed"); - } -} - -void cleanup(void) -{ - - if (close(fd) == -1) - tst_resm(TWARN | TERRNO, "close failed"); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/fcntl/fcntl11.c b/testcases/kernel/syscalls/fcntl/fcntl11.c index b66fa8421..d042c6b9b 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl11.c +++ b/testcases/kernel/syscalls/fcntl/fcntl11.c @@ -189,11 +189,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 0: + case F_RDLCK: return ("F_RDLCK"); - case 1: + case F_WRLCK: return ("F_WRLCK"); - case 2: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl19.c b/testcases/kernel/syscalls/fcntl/fcntl19.c index 88c91d6ea..f929aff99 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl19.c +++ b/testcases/kernel/syscalls/fcntl/fcntl19.c @@ -215,11 +215,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl20.c b/testcases/kernel/syscalls/fcntl/fcntl20.c index b671af8a9..4aa773451 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl20.c +++ b/testcases/kernel/syscalls/fcntl/fcntl20.c @@ -214,11 +214,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl21.c b/testcases/kernel/syscalls/fcntl/fcntl21.c index 8f1a67cf6..824b8c059 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl21.c +++ b/testcases/kernel/syscalls/fcntl/fcntl21.c @@ -222,11 +222,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl30.c b/testcases/kernel/syscalls/fcntl/fcntl30.c index c4c3f81f1..64bbb9e3a 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl30.c +++ b/testcases/kernel/syscalls/fcntl/fcntl30.c @@ -1,103 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Description: - * Verify that, - * Basic test for fcntl(2) using F_SETPIPE_SZ, F_GETPIPE_SZ argument. +/*\ + * [Description] + * + * Verify that, fetching and changing the capacity of a pipe works as + * expected with fcntl(2) syscall using F_GETPIPE_SZ, F_SETPIPE_SZ arguments. */ - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include <pwd.h> - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #include "lapi/fcntl.h" -char *TCID = "fcntl30"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); +static int fds[2]; +static int max_size_unpriv; -int main(int ac, char **av) +static void run(void) { - int lc; - int pipe_fds[2], test_fd; - int orig_pipe_size, new_pipe_size; + SAFE_PIPE(fds); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); - tst_parse_opts(ac, av, NULL, NULL); + TST_EXP_POSITIVE(fcntl(fds[1], F_SETPIPE_SZ, max_size_unpriv)); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); + TST_EXP_EXPR(TST_RET >= max_size_unpriv, + "new pipe size (%ld) >= requested size (%d)", + TST_RET, max_size_unpriv); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_PIPE(cleanup, pipe_fds); - test_fd = pipe_fds[1]; - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl get pipe size failed"); - } - - orig_pipe_size = TEST_RETURN; - new_pipe_size = orig_pipe_size * 2; - TEST(fcntl(test_fd, F_SETPIPE_SZ, new_pipe_size)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_SETPIPE_SZ failed"); - } - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_GETPIPE_SZ failed"); - } - tst_resm(TINFO, "orig_pipe_size: %d new_pipe_size: %d", - orig_pipe_size, new_pipe_size); - if (TEST_RETURN >= new_pipe_size) { - tst_resm(TPASS, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ passed"); - } else { - tst_resm(TFAIL, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ failed"); - } - SAFE_CLOSE(cleanup, pipe_fds[0]); - SAFE_CLOSE(cleanup, pipe_fds[1]); - } - - cleanup(); - tst_exit(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + SAFE_FILE_SCANF("/proc/sys/fs/pipe-max-size", "%d", &max_size_unpriv); } static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/fcntl/fcntl33.c b/testcases/kernel/syscalls/fcntl/fcntl33.c index 8d0d1a5a1..3c6a38b81 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl33.c +++ b/testcases/kernel/syscalls/fcntl/fcntl33.c @@ -209,7 +209,7 @@ static void cleanup(void) SAFE_CLOSE(fd); /* Restore the lease-break-time. */ - FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); + SAFE_FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/finit_module/finit_module01.c b/testcases/kernel/syscalls/finit_module/finit_module01.c index f960b2e40..1929c30fa 100644 --- a/testcases/kernel/syscalls/finit_module/finit_module01.c +++ b/testcases/kernel/syscalls/finit_module/finit_module01.c @@ -49,6 +49,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/finit_module/finit_module02.c b/testcases/kernel/syscalls/finit_module/finit_module02.c index a7434de7d..223d9b388 100644 --- a/testcases/kernel/syscalls/finit_module/finit_module02.c +++ b/testcases/kernel/syscalls/finit_module/finit_module02.c @@ -25,7 +25,7 @@ static char *mod_path; static int fd, fd_zero, fd_invalid = -1, fd_dir; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE); @@ -83,7 +83,9 @@ static void setup(void) tst_module_exists(MODULE_NAME, &mod_path); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; + SAFE_MKDIR(TEST_DIR, 0700); fd_dir = SAFE_OPEN(TEST_DIR, O_DIRECTORY); @@ -102,8 +104,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/flistxattr/flistxattr01.c b/testcases/kernel/syscalls/flistxattr/flistxattr01.c index 98a6fa254..68c3948b7 100644 --- a/testcases/kernel/syscalls/flistxattr/flistxattr01.c +++ b/testcases/kernel/syscalls/flistxattr/flistxattr01.c @@ -47,7 +47,7 @@ static int has_attribute(const char *list, int llen, const char *attr) static void verify_flistxattr(void) { - char buf[64]; + char buf[128]; TEST(flistxattr(fd, buf, sizeof(buf))); if (TST_RET == -1) { diff --git a/testcases/kernel/syscalls/fork/fork03.c b/testcases/kernel/syscalls/fork/fork03.c index 25b36c897..c6381dd67 100644 --- a/testcases/kernel/syscalls/fork/fork03.c +++ b/testcases/kernel/syscalls/fork/fork03.c @@ -1,119 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: 2001 Ported by Wayne Boyer */ -/* - * NAME - * fork03.c - * - * DESCRIPTION - * Check that child can use a large text space and do a large - * number of operations. - * - * ALGORITHM - * Fork one process, check for pid == 0 in child. - * Check for pid > 0 in parent after wait. +/*\ + *[Description] * - * USAGE - * fork03 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Check that child process can use a large text space and do a large number + * of operations. In this situation, check for pid == 0 in child and check + * for pid > 0 in parent after wait. */ -#include <sys/types.h> +#include <unistd.h> #include <sys/wait.h> -#include <stdio.h> -#include "test.h" - -char *TCID = "fork03"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void verify_fork(void) { float fl1, fl2; - int i; - int pid1, pid2, status; - - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - pid1 = fork(); - if (pid1 == -1) - tst_brkm(TBROK, cleanup, "fork() failed"); - - if (pid1 == 0) { - /* child uses some cpu cycles */ - for (i = 1; i < 32767; i++) { - fl1 = 0.000001; - fl1 = fl2 = 0.000001; - fl1 = fl1 * 10.0; - fl2 = fl1 / 1.232323; - fl1 = fl2 - fl2; - fl1 = fl2; - } - - /* Pid must always be zero in child */ - if (pid1 != 0) - exit(1); - else - exit(0); - } else { - tst_resm(TINFO, "process id in parent of child from " - "fork : %d", pid1); - pid2 = wait(&status); /* wait for child */ - - if (pid1 != pid2) { - tst_resm(TFAIL, "pids don't match : %d vs %d", - pid1, pid2); - continue; - } + int pid1, pid2, status, i; + + pid1 = SAFE_FORK(); + if (!pid1) { + /* child uses some cpu time slices */ + for (i = 1; i < 32767; i++) { + fl1 = 0.000001; + fl1 = fl2 = 0.000001; + fl1 = fl1 * 10.0; + fl2 = fl1 / 1.232323; + fl1 = fl2 - fl2; + fl1 = fl2; + } + exit(!!pid1); + } - if ((status >> 8) != 0) { - tst_resm(TFAIL, "child exited with failure"); - continue; - } + tst_res(TINFO, "process id in parent of child from fork: %d", pid1); + pid2 = SAFE_WAIT(&status); - tst_resm(TPASS, "test 1 PASSED"); - } + if (pid1 != pid2) { + tst_res(TFAIL, "pids don't match: %d vs %d", pid1, pid2); + return; } - cleanup(); - tst_exit(); -} + if ((status >> 8) != 0) { + tst_res(TFAIL, "child exited with failure"); + return; + } -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + tst_res(TPASS, "test PASSED"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_fork, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/fsconfig/.gitignore b/testcases/kernel/syscalls/fsconfig/.gitignore index 2bc54b827..cfedae5f7 100644 --- a/testcases/kernel/syscalls/fsconfig/.gitignore +++ b/testcases/kernel/syscalls/fsconfig/.gitignore @@ -1,2 +1,3 @@ /fsconfig01 /fsconfig02 +/fsconfig03 diff --git a/testcases/kernel/syscalls/fsconfig/fsconfig03.c b/testcases/kernel/syscalls/fsconfig/fsconfig03.c new file mode 100644 index 000000000..0ba5355d3 --- /dev/null +++ b/testcases/kernel/syscalls/fsconfig/fsconfig03.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Alejandro Guerrero <aguerrero@qualys.com> + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Test for CVE-2022-0185. + * + * References links: + * + * - https://www.openwall.com/lists/oss-security/2022/01/25/14 + * - https://github.com/Crusaders-of-Rust/CVE-2022-0185 + * + */ + +#include "tst_test.h" +#include "lapi/fsmount.h" + +#define MNTPOINT "mntpoint" + +static int fd = -1; + +static void setup(void) +{ + fsopen_supported_by_kernel(); +} + +static void run(void) +{ + char *val = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + long pagesize; + + TEST(fd = fsopen(tst_device->fs_type, 0)); + if (fd == -1) + tst_brk(TBROK | TTERRNO, "fsopen() failed"); + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize == -1) + tst_brk(TBROK, "sysconf(_SC_PAGESIZE) failed"); + + for (size_t i = 0; i < 5000; i++) { + /* use same logic in kernel legacy_parse_param function */ + const size_t len = i * (strlen(val) + 2) + (strlen(val) + 1) + 2; + + TEST(fsconfig(fd, FSCONFIG_SET_STRING, "\x00", val, 0)); + + /* Legacy fsconfig() just copies arguments to buffer */ + if (!TST_RET && len <= (size_t)pagesize) + continue; + + if (!TST_RET) { + tst_res(TFAIL, "fsconfig() passed unexpectedly"); + } else if (TST_RET != -1) { + tst_brk(TBROK | TTERRNO, + "Invalid fsconfig() return value %ld", TST_RET); + } else if (TST_ERR != EINVAL) { + tst_res(TFAIL | TTERRNO, + "fsconfig() failed with unexpected error"); + } + } + + if (fd != -1) + SAFE_CLOSE(fd); + + if (tst_taint_check()) + tst_res(TFAIL, "kernel has issues on %s", + tst_device->fs_type); + else + tst_res(TPASS, "kernel seems to be fine on %s", + tst_device->fs_type); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .skip_filesystems = (const char *const []){"fuse", NULL}, + .tags = (const struct tst_tag[]) { + {"linux-git", "722d94847de29"}, + {"CVE", "2022-0185"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/futex/Makefile b/testcases/kernel/syscalls/futex/Makefile index 7228496bc..1d05cf115 100644 --- a/testcases/kernel/syscalls/futex/Makefile +++ b/testcases/kernel/syscalls/futex/Makefile @@ -9,6 +9,9 @@ futex_wait02: LDLIBS+=-lrt futex_wake03: LDLIBS+=-lrt futex_wait05: LDLIBS+=-lrt futex_wait_bitset01: LDLIBS+=-lrt +futex_waitv01: LDLIBS+=-lrt +futex_waitv02: LDLIBS+=-lrt +futex_waitv03: LDLIBS+=-lrt futex_wait03: CFLAGS+=-pthread futex_wake02: CFLAGS+=-pthread diff --git a/testcases/kernel/syscalls/futex/futex_wake04.c b/testcases/kernel/syscalls/futex/futex_wake04.c index 176dd4aeb..03d90591b 100644 --- a/testcases/kernel/syscalls/futex/futex_wake04.c +++ b/testcases/kernel/syscalls/futex/futex_wake04.c @@ -21,7 +21,6 @@ */ #include <stdio.h> -#include <sys/mman.h> #include <fcntl.h> #include <sys/time.h> #include <string.h> diff --git a/testcases/kernel/syscalls/getcpu/getcpu01.c b/testcases/kernel/syscalls/getcpu/getcpu01.c index f6fcc4fc1..9842c8999 100644 --- a/testcases/kernel/syscalls/getcpu/getcpu01.c +++ b/testcases/kernel/syscalls/getcpu/getcpu01.c @@ -69,6 +69,7 @@ static unsigned int get_nodeid(unsigned int cpu_id) DIR *directory_parent, *directory_node; struct dirent *de, *dn; char directory_path[PATH_MAX]; + char *invalid_number; unsigned int cpu; int node_id = 0; @@ -91,7 +92,9 @@ static unsigned int get_nodeid(unsigned int cpu_id) while ((dn = readdir(directory_node)) != NULL) { if (strncmp(dn->d_name, "cpu", 3)) continue; - cpu = strtoul(dn->d_name + 3, NULL, 0); + cpu = strtoul(dn->d_name + 3, &invalid_number, 0); + if (strcmp(invalid_number, "\0")) + continue; if (cpu == cpu_id) { node_id = strtoul(de->d_name + 4, NULL, 0); diff --git a/testcases/kernel/syscalls/geteuid/geteuid01.c b/testcases/kernel/syscalls/geteuid/geteuid01.c index d02fb0a8d..66fb8936c 100644 --- a/testcases/kernel/syscalls/geteuid/geteuid01.c +++ b/testcases/kernel/syscalls/geteuid/geteuid01.c @@ -1,87 +1,26 @@ +//SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner +/*\ + *[Description] + * + * Check the basic functionality of the geteuid() system call. */ -#include <sys/types.h> -#include <errno.h> -#include <string.h> -#include <signal.h> - -#include "test.h" -#include "compat_16.h" - -static void setup(void); -static void cleanup(void); - -TCID_DEFINE(geteuid01); -int TST_TOTAL = 1; +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(GETEUID(cleanup)); - - if (TEST_RETURN < 0) { - tst_resm(TFAIL | TTERRNO, "geteuid failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "geteuid returned %ld", TEST_RETURN); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/geteuid/geteuid02.c b/testcases/kernel/syscalls/geteuid/geteuid02.c index e00f81296..eb2272bff 100644 --- a/testcases/kernel/syscalls/geteuid/geteuid02.c +++ b/testcases/kernel/syscalls/geteuid/geteuid02.c @@ -1,79 +1,36 @@ +//SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * Ported by Wayne Boyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) Linux Test Project, 2003-2023 + * Ported by Wayne Boyer */ -#include <pwd.h> -#include <errno.h> - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(geteuid02); -int TST_TOTAL = 1; +/*\ + *[Description] + * + * Check that geteuid() return value matches value from /proc/self/status. + */ -static void setup(void); -static void cleanup(void); +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - struct passwd *pwent; - int lc; - uid_t uid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + long uid[4]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); - TEST(GETEUID(cleanup)); + if (!TST_PASS) + return; - if (TEST_RETURN == -1) - tst_brkm(TBROK | TTERRNO, cleanup, "geteuid* failed"); + SAFE_FILE_LINES_SCANF("/proc/self/status", "Uid: %ld %ld %ld %ld", + &uid[0], &uid[1], &uid[2], &uid[3]); - uid = geteuid(); - pwent = getpwuid(uid); - - if (pwent == NULL) - tst_resm(TFAIL | TERRNO, "getpwuid failed"); - - UID16_CHECK(pwent->pw_uid, geteuid, cleanup); - if (pwent->pw_uid != TEST_RETURN) - tst_resm(TFAIL, "getpwuid value, %d, " - "does not match geteuid " - "value, %ld", pwent->pw_uid, - TEST_RETURN); - else - tst_resm(TPASS, "values from geteuid " - "and getpwuid match"); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_EXPR(TST_RET == uid[1], + "geteuid() ret %ld == /proc/self/status EUID: %ld", + TST_RET, uid[1]); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/getgroups/getgroups01.c b/testcases/kernel/syscalls/getgroups/getgroups01.c index dc3074b75..cfddeb408 100644 --- a/testcases/kernel/syscalls/getgroups/getgroups01.c +++ b/testcases/kernel/syscalls/getgroups/getgroups01.c @@ -95,7 +95,7 @@ int main(int ac, char **av) /* * Check that if ngrps is zero that the number of groups is - * return and the the gidset array is not modified. + * return and the gidset array is not modified. * This is a POSIX special case. */ memset(gidset, 052, NGROUPS * sizeof(GID_T)); diff --git a/testcases/kernel/syscalls/gethostname/gethostname01.c b/testcases/kernel/syscalls/gethostname/gethostname01.c index a7cb5417f..f2276a38c 100644 --- a/testcases/kernel/syscalls/gethostname/gethostname01.c +++ b/testcases/kernel/syscalls/gethostname/gethostname01.c @@ -1,161 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Copyright (c) 2023 SUSE LLC Ioannis Bonatakis <ybonatakis@suse.com> */ -/* $Id: gethostname01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : gethostname01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for gethostname(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) gethostname(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the gethostname(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * gethostname(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <errno.h> -#include <signal.h> -#include <string.h> - -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "gethostname01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - char hname[100]; /* host name */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(gethostname(hname, sizeof(hname))); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "gethostname failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "gethostname returned %ld", - TEST_RETURN); - } +/*\ + * [Description] + * + * Test is checking that gethostname() succeeds. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" +#include <stdlib.h> -void setup(void) +static void run(void) { + char hname[100]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS(gethostname(hname, sizeof(hname))); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid01.c b/testcases/kernel/syscalls/getpgid/getpgid01.c index 060486e7e..4c614e0b9 100644 --- a/testcases/kernel/syscalls/getpgid/getpgid01.c +++ b/testcases/kernel/syscalls/getpgid/getpgid01.c @@ -1,145 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * getpgid01.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * block1: Does getpgid(0), and checks for error. - * block2: Does getpgid(getpid()) and checks for error. - * block3: Does getpgid(getppid()) and checks for error. - * block4: Verifies that getpgid(getpgid(0)) == getpgid(0). - * block5: Does getpgid(1) and checks for error. +/*\ + * [Description] * - * USAGE - * getpgid01 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Expects that there are no EPERM limitations on getting the - * process group ID from proc 1 (init). + * Verify the basic functionality of getpgid(2) syscall. */ -#define _GNU_SOURCE 1 - -#include <errno.h> -#include <unistd.h> -#include <stdarg.h> -#include <sys/wait.h> -#include <sys/types.h> -#include "test.h" -void setup(void); -void cleanup(void); +#include "tst_test.h" -char *TCID = "getpgid01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) +static int get_init_pgid(void) { - int lc; - - register int pgid_0, pgid_1; - register int my_pid, my_ppid; - int ex_stat; - - tst_parse_opts(ac, av, NULL, NULL); + int pgid; - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - if ((pgid_0 = FORK_OR_VFORK()) == -1) - tst_brkm(TBROK, cleanup, "fork failed"); - if (pgid_0 > 0) { - while ((pgid_0 = wait(&ex_stat)) != -1) ; - - if (WEXITSTATUS(ex_stat) == 0) - tst_resm(TPASS, "%s PASSED", TCID); - else - tst_resm(TFAIL, "%s FAILED", TCID); - - exit(0); - } + SAFE_FILE_SCANF("/proc/1/stat", "%*d %*s %*c %*d %d", &pgid); + return pgid; +} - if ((pgid_0 = getpgid(0)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(0) failed"); - else - tst_resm(TPASS, "getpgid(0) PASSED"); +static void run(void) +{ + pid_t pid_1, child_pid, pgid; -//block2: - my_pid = getpid(); - if ((pgid_1 = getpgid(my_pid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_pid); + pgid = getpgid(0); + tst_res(TINFO, "getpgid(0) in parent = %d", pgid); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(my_pid=%d) != getpgid(0) " - "[%d != %d]", my_pid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getpid()) PASSED"); + pid_1 = SAFE_FORK(); + if (!pid_1) { + child_pid = getpid(); -//block3: - my_ppid = getppid(); - if ((pgid_1 = getpgid(my_ppid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_ppid); + tst_res(TINFO, "getpid() in child = %d", child_pid); + tst_res(TINFO, "Running getpgid() in child"); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - my_ppid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getppid()) PASSED"); + TST_EXP_PID(getpgid(0)); + TST_EXP_EQ_LI(TST_RET, pgid); -//block4: - if ((pgid_1 = getpgid(pgid_0)) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", pgid_0); + TST_EXP_PID(getpgid(child_pid), "getpgid(%d)", child_pid); + TST_EXP_EQ_LI(TST_RET, pgid); - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - pgid_0, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(%d) PASSED", pgid_0); + TST_EXP_PID(getpgid(pgid), "getpgid(%d)", pgid); + TST_EXP_EQ_LI(TST_RET, pgid); -//block5: - if (getpgid(1) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(1) failed"); - else - tst_resm(TPASS, "getpgid(1) PASSED"); + TST_EXP_PID(getpgid(1)); + TST_EXP_EQ_LI(TST_RET, get_init_pgid()); } - cleanup(); - tst_exit(); + tst_reap_children(); } -void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid02.c b/testcases/kernel/syscalls/getpgid/getpgid02.c index 92482e3ae..30d0129bc 100644 --- a/testcases/kernel/syscalls/getpgid/getpgid02.c +++ b/testcases/kernel/syscalls/getpgid/getpgid02.c @@ -1,137 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * getpgid02.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * test 1: Does getpgid(-99) and expects ESRCH. - * test 2: Searches an unused pid and expects ESRCH. - * - * USAGE: <for command-line> - * getpgid02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * none + * Verify that getpgid(2) fails with errno ESRCH when + * pid does not match any process. */ -#define _GNU_SOURCE 1 -#include <errno.h> -#include <unistd.h> -#include <stdarg.h> -#include <sys/wait.h> -#include <sys/types.h> -#include "test.h" +#include "tst_test.h" -void setup(void); -void cleanup(void); +static pid_t unused_pid; +static pid_t neg_pid = -99; -char *TCID = "getpgid02"; -int TST_TOTAL = 2; - -int pgid_0, pgid_1; -#define BADPID -99 - -struct test_case_t { - int *id; - int error; -} TC[] = { - /* The pid value is negative */ - { - &pgid_0, ESRCH}, - /* The pid value does not match any process */ - { - &pgid_1, ESRCH} -}; - -int main(int ac, char **av) +static void setup(void) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(getpgid(*TC[i].id)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - cleanup(); - - tst_exit(); + unused_pid = tst_get_unused_pid(); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - pgid_0 = BADPID; - - pgid_1 = tst_get_unused_pid(cleanup); + TST_EXP_FAIL2(getpgid(neg_pid), ESRCH, "getpgid(%d)", neg_pid); + TST_EXP_FAIL2(getpgid(unused_pid), ESRCH, "getpgid(%d)", unused_pid); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .setup = setup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgrp/getpgrp01.c b/testcases/kernel/syscalls/getpgrp/getpgrp01.c index 61feba8d1..a94736661 100644 --- a/testcases/kernel/syscalls/getpgrp/getpgrp01.c +++ b/testcases/kernel/syscalls/getpgrp/getpgrp01.c @@ -1,160 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* $Id: getpgrp01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : getpgrp01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for getpgrp(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) getpgrp(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the getpgrp(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * getpgrp(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> -#include <string.h> -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "getpgrp01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(getpgrp()); - - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "getpgrp failed"); - else - tst_resm(TPASS, "getpgrp returned %ld", TEST_RETURN); - - } +/*\ + * [Description] + * + * Verify that getpgrp(2) syscall executes successfully. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PID(getpgrp()); + TST_EXP_EQ_LI(TST_RET, SAFE_GETPGID(0)); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpid/getpid02.c b/testcases/kernel/syscalls/getpid/getpid02.c index d826724f4..86ad5a29f 100644 --- a/testcases/kernel/syscalls/getpid/getpid02.c +++ b/testcases/kernel/syscalls/getpid/getpid02.c @@ -7,6 +7,7 @@ * [Description] * * Check that: + * * - fork() in parent returns the same pid as getpid() in child * - getppid() in child returns the same pid as getpid() in parent */ diff --git a/testcases/kernel/syscalls/getrusage/getrusage04.c b/testcases/kernel/syscalls/getrusage/getrusage04.c index 06b576d79..b03bc549b 100644 --- a/testcases/kernel/syscalls/getrusage/getrusage04.c +++ b/testcases/kernel/syscalls/getrusage/getrusage04.c @@ -104,8 +104,9 @@ int main(int argc, char *argv[]) tst_count = 0; i = 0; SAFE_GETRUSAGE(cleanup, RUSAGE_THREAD, &usage); - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); ulast = usage.ru_utime.tv_usec; slast = usage.ru_stime.tv_usec; @@ -115,9 +116,9 @@ int main(int argc, char *argv[]) sdelta = usage.ru_stime.tv_usec - slast; if (udelta > 0 || sdelta > 0) { i++; - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, - usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); if ((long)udelta > 1000 + (BIAS_MAX * factor_nr)) { sprintf(msg_string, "utime increased > %ldus:", diff --git a/testcases/kernel/syscalls/init_module/init_module01.c b/testcases/kernel/syscalls/init_module/init_module01.c index 79e567cd6..26ff0b93b 100644 --- a/testcases/kernel/syscalls/init_module/init_module01.c +++ b/testcases/kernel/syscalls/init_module/init_module01.c @@ -53,6 +53,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/init_module/init_module02.c b/testcases/kernel/syscalls/init_module/init_module02.c index ad6569a06..e6730e21c 100644 --- a/testcases/kernel/syscalls/init_module/init_module02.c +++ b/testcases/kernel/syscalls/init_module/init_module02.c @@ -22,7 +22,7 @@ #define MODULE_NAME "init_module.ko" static unsigned long size, zero_size; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static void *buf, *faulty_buf, *null_buf; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); @@ -53,7 +53,8 @@ static void setup(void) tst_module_exists(MODULE_NAME, NULL); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); SAFE_FSTAT(fd, &sb); size = sb.st_size; @@ -67,8 +68,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/io_uring/io_uring01.c b/testcases/kernel/syscalls/io_uring/io_uring01.c index 70151bb85..ab1ec00d6 100644 --- a/testcases/kernel/syscalls/io_uring/io_uring01.c +++ b/testcases/kernel/syscalls/io_uring/io_uring01.c @@ -264,5 +264,10 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&iov, .iov_sizes = (int[]){BLOCK_SZ, -1}}, {} + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} } }; diff --git a/testcases/kernel/syscalls/io_uring/io_uring02.c b/testcases/kernel/syscalls/io_uring/io_uring02.c index c5c770074..c9d4bbcb1 100644 --- a/testcases/kernel/syscalls/io_uring/io_uring02.c +++ b/testcases/kernel/syscalls/io_uring/io_uring02.c @@ -255,6 +255,11 @@ static struct tst_test test = { TST_CAP(TST_CAP_REQ, CAP_SYS_CHROOT), {} }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, .tags = (const struct tst_tag[]) { {"linux-git", "9392a27d88b9"}, {"linux-git", "ff002b30181d"}, diff --git a/testcases/kernel/syscalls/ioctl/Makefile b/testcases/kernel/syscalls/ioctl/Makefile index c2ff6c8e7..1d40f5e0b 100644 --- a/testcases/kernel/syscalls/ioctl/Makefile +++ b/testcases/kernel/syscalls/ioctl/Makefile @@ -7,6 +7,8 @@ include $(top_srcdir)/include/mk/testcases.mk INSTALL_TARGETS += test_ioctl +ioctl01: LDLIBS+=-lutil + ifeq ($(ANDROID),1) FILTER_OUT_MAKE_TARGETS += ioctl02 endif diff --git a/testcases/kernel/syscalls/ioctl/ioctl01.c b/testcases/kernel/syscalls/ioctl/ioctl01.c index 2989c0e9b..c84a72b9a 100644 --- a/testcases/kernel/syscalls/ioctl/ioctl01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl01.c @@ -2,104 +2,90 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2020 Petr Vorel <petr.vorel@gmail.com> + * Copyright (c) Linux Test Project, 2002-2023 * 07/2001 Ported by Wayne Boyer * 04/2002 Fixes by wjhuie + */ + +/*\ + * [Description] * - * Testcase to check the errnos set by the ioctl(2) system call. + * Testcase to check the errnos set by the ioctl(2) system call. * - * ALGORITHM - * 1. EBADF: Pass an invalid fd to ioctl(fd, ..) and expect EBADF. - * 2. EFAULT: Pass an invalid address of arg in ioctl(fd, .., arg) - * 3. EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) - * 4. ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) - * 5. EFAULT: Pass a NULL address for termio + * - EBADF: Pass an invalid fd to ioctl(fd, ...) and expect EBADF + * - EFAULT: Pass an invalid address of arg in ioctl(fd, ..., arg) + * - EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) + * - ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) + * - EFAULT: Pass a NULL address for termio */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <termios.h> +#include <pty.h> #include "tst_test.h" #include "lapi/ioctl.h" #define INVAL_IOCTL 9999999 +static int amaster, aslave; static int fd, fd_file; static int bfd = -1; static struct termio termio; +static struct termios termios; static struct tcase { + const char *desc; int *fd; int request; - struct termio *s_tio; + void *s_tio; int error; } tcases[] = { - /* file descriptor is invalid */ - {&bfd, TCGETA, &termio, EBADF}, - /* termio address is invalid */ - {&fd, TCGETA, (struct termio *)-1, EFAULT}, - /* command is invalid */ + {"File descriptor is invalid (termio)", &bfd, TCGETA, &termio, EBADF}, + {"File descriptor is invalid (termios)", &bfd, TCGETS, &termios, EBADF}, + {"Termio address is invalid", &fd, TCGETA, (struct termio *)-1, EFAULT}, + {"Termios address is invalid", &fd, TCGETS, (struct termios *)-1, EFAULT}, /* This errno value was changed from EINVAL to ENOTTY * by kernel commit 07d106d0 and bbb63c51 */ - {&fd, INVAL_IOCTL, &termio, ENOTTY}, - /* file descriptor is for a regular file */ - {&fd_file, TCGETA, &termio, ENOTTY}, - /* termio is NULL */ - {&fd, TCGETA, NULL, EFAULT} + {"Command is invalid", &fd, INVAL_IOCTL, &termio, ENOTTY}, + {"File descriptor is for a regular file (termio)", &fd_file, TCGETA, &termio, ENOTTY}, + {"File descriptor is for a regular file (termios)", &fd_file, TCGETS, &termios, ENOTTY}, + {"Termio is NULL", &fd, TCGETA, NULL, EFAULT}, + {"Termios is NULL", &fd, TCGETS, NULL, EFAULT} }; -static char *device; - static void verify_ioctl(unsigned int i) { - TEST(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio)); - - if (TST_RET != -1) { - tst_res(TFAIL, "call succeeded unexpectedly"); - return; - } - - if (TST_ERR != tcases[i].error) { - tst_res(TFAIL | TTERRNO, - "failed unexpectedly; expected %s", - tst_strerrno(tcases[i].error)); - return; - } - - tst_res(TPASS | TTERRNO, "failed as expected"); + TST_EXP_FAIL(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio), + tcases[i].error, "%s", tcases[i].desc); } static void setup(void) { - unsigned int i; + if (openpty(&amaster, &aslave, NULL, NULL, NULL) < 0) + tst_brk(TBROK | TERRNO, "unable to open pty"); - if (!device) - tst_brk(TBROK, "You must specify a tty device with -D option"); - - fd = SAFE_OPEN(device, O_RDWR, 0777); + fd = amaster; fd_file = SAFE_OPEN("x", O_CREAT, 0777); } static void cleanup(void) { - if (fd > 0) - SAFE_CLOSE(fd); - + if (amaster > 0) + SAFE_CLOSE(amaster); + if (aslave > 0) + SAFE_CLOSE(aslave); if (fd_file > 0) SAFE_CLOSE(fd_file); } static struct tst_test test = { - .needs_root = 1, .needs_tmpdir = 1, .setup = setup, .cleanup = cleanup, .test = verify_ioctl, - .tcnt = ARRAY_SIZE(tcases), - .options = (struct tst_option[]) { - {"D:", &device, "Tty device. For example, /dev/tty[0-9]"}, - {} - } + .tcnt = ARRAY_SIZE(tcases) }; diff --git a/testcases/kernel/syscalls/ioctl/test_ioctl b/testcases/kernel/syscalls/ioctl/test_ioctl index 923275433..43836a229 100755 --- a/testcases/kernel/syscalls/ioctl/test_ioctl +++ b/testcases/kernel/syscalls/ioctl/test_ioctl @@ -41,29 +41,6 @@ case "$device_no" in [0-9]|[0-9][0-9]) has_tty $tttype if [ $? -eq 0 ]; then - tst_resm TINFO "Skipping ioctl01 with $tttype" - continue - fi - tst_resm TINFO "Testing ioctl01 with $tttype" - ioctl01 -D $tttype - RC=$? - if [ $RC -eq 0 ] - then - tst_resm TPASS "ioctl01 Passed with $tttype" - else - tst_resm TFAIL "ioctl01 Failed with $tttype" - fi -echo;; -esac -done - -for tttype in `ls /dev/tty*` -do -device_no=${tttype#/dev/tty} -case "$device_no" in -[0-9]|[0-9][0-9]) - has_tty $tttype - if [ $? -eq 0 ]; then tst_resm TINFO "Skipping ioctl02 with $tttype" continue fi diff --git a/testcases/kernel/syscalls/ioprio/ioprio.h b/testcases/kernel/syscalls/ioprio/ioprio.h index c74380475..dbe27c15f 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio.h +++ b/testcases/kernel/syscalls/ioprio/ioprio.h @@ -1,33 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project */ #ifndef LTP_IOPRIO_H #define LTP_IOPRIO_H -enum { - IOPRIO_CLASS_NONE = 0, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -/* The I/O scheduler classes have 8 priorities 0..7 except for the IDLE class */ -#define IOPRIO_PRIO_NUM 8 - -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(data) ((data) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_LEVEL(data) ((data) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) +#include "lapi/ioprio.h" +#include "lapi/syscalls.h" static const char * const to_class_str[] = { [IOPRIO_CLASS_NONE] = "NONE", @@ -46,10 +27,10 @@ static inline int sys_ioprio_set(int which, int who, int ioprio) return tst_syscall(__NR_ioprio_set, which, who, ioprio); } -/* Priority range from 0 (highest) to 7 (lowest) */ +/* Priority range from 0 (highest) to IOPRIO_PRIO_NUM (lowest) */ static inline int prio_in_range(int prio) { - if ((prio < 0) || (prio > 7)) + if ((prio < 0) || (prio >= IOPRIO_PRIO_NUM)) return 0; return 1; } @@ -91,4 +72,4 @@ static inline void ioprio_check_setting(int class, int prio, int report) newprio); } -#endif +#endif /* LTP_IOPRIO_H */ diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c index 6e822434e..f1325be31 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_get01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_get() test. Gets the current process I/O priority and * checks that the values are sane. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c index 19953ba36..0868cea7c 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2019-2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_set() test. Gets the current process I/O priority and * bumps it up one notch, then down two notches and checks that the * new priority is reported back correctly. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static int orig_class; diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c index 328a130cb..37db7bf42 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set02.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Extended ioprio_set() test. * Tests to set all 8 priority levels for best effort priority, then * switches to test all 8 priority levels for idle priority. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set03.c b/testcases/kernel/syscalls/ioprio/ioprio_set03.c index b2c962a6f..6efcacc1c 100644 --- a/testcases/kernel/syscalls/ioprio/ioprio_set03.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set03.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij <linus.walleij@linaro.org> + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Negative ioprio_set() test. Test some non-working priorities to make * sure they don't work. */ -#include <sys/types.h> -#include <sys/syscall.h> #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) @@ -27,7 +28,7 @@ static void run(void) sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(class, 4)); TEST(sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, - IOPRIO_PRIO_VALUE(class, 8))); + IOPRIO_PRIO_VALUE(class, IOPRIO_PRIO_NUM))); if (TST_RET == -1) { ioprio_check_setting(class, 4, 1); if (errno == EINVAL) diff --git a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c index 75adcb229..56d1505fd 100644 --- a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c +++ b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c @@ -6,7 +6,7 @@ */ /* - * Test that IPC_STAT command succeeds and the the buffer is filled with + * Test that IPC_STAT command succeeds and the buffer is filled with * correct data. */ #include <errno.h> diff --git a/testcases/kernel/syscalls/ipc/msgget/msgget02.c b/testcases/kernel/syscalls/ipc/msgget/msgget02.c index ce59a8fb5..1885599d1 100644 --- a/testcases/kernel/syscalls/ipc/msgget/msgget02.c +++ b/testcases/kernel/syscalls/ipc/msgget/msgget02.c @@ -8,11 +8,11 @@ * * Test for EEXIST, ENOENT, EACCES errors. * - * 1) msgget(2) fails if a message queue exists for key and msgflg + * - msgget(2) fails if a message queue exists for key and msgflg * specified both IPC_CREAT and IPC_EXCL. - * 2) msgget(2) fails if no message queue exists for key and msgflg + * - msgget(2) fails if no message queue exists for key and msgflg * did not specify IPC_CREAT. - * 3) msgget(2) fails if a message queue exists for key, but the + * - msgget(2) fails if a message queue exists for key, but the * calling process does not have permission to access the queue, * and does not have the CAP_IPC_OWNER capability. * diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c index 3cb70ab18..aa37d9058 100644 --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c @@ -110,11 +110,12 @@ int main(int argc, char **argv) } free_pids = tst_get_free_pids(cleanup); - if (nprocs >= free_pids) { + /* Each forked child forks once, take it into account here. */ + if (nprocs * 2 >= free_pids) { tst_resm(TINFO, "Requested number of processes higher than limit (%d > %d), " - "setting to %d", nprocs, free_pids, free_pids); - nprocs = free_pids; + "setting to %d", nprocs * 2, free_pids, free_pids); + nprocs = free_pids / 2; } srand(getpid()); diff --git a/testcases/kernel/syscalls/ipc/semget/.gitignore b/testcases/kernel/syscalls/ipc/semget/.gitignore index ce26c93b0..4519b30d2 100644 --- a/testcases/kernel/syscalls/ipc/semget/.gitignore +++ b/testcases/kernel/syscalls/ipc/semget/.gitignore @@ -1,5 +1,3 @@ /semget01 /semget02 -/semget03 /semget05 -/semget06 diff --git a/testcases/kernel/syscalls/ipc/semget/Makefile b/testcases/kernel/syscalls/ipc/semget/Makefile index 26b9f264d..b1201281d 100644 --- a/testcases/kernel/syscalls/ipc/semget/Makefile +++ b/testcases/kernel/syscalls/ipc/semget/Makefile @@ -3,10 +3,10 @@ top_srcdir ?= ../../../../.. -LTPLIBS = ltpipc +LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpipc +LTPLDLIBS = -lltpnewipc include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semget/semget01.c b/testcases/kernel/syscalls/ipc/semget/semget01.c index 217163b3a..872acabd3 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget01.c +++ b/testcases/kernel/syscalls/ipc/semget/semget01.c @@ -1,172 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget01.c - * - * DESCRIPTION - * semget01 - test that semget() correclty creates a semaphore set +/*\ + * [Description] * - * ALGORITHM - * loop if that option was specified - * call semget() to create the semaphore set - * check the return code - * if failure, issue a FAIL message. - * otherwise, - * if doing functionality testing - * stat the semaphore set - * if the number of primitive semaphores is correct and - * the semaphore uid == the process uid - * then, - * issue a PASS message - * otherwise - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * This case checks that semget() correclty creates a semaphore set. */ -#include "ipcsem.h" +#include <unistd.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" -char *TCID = "semget01"; -int TST_TOTAL = 1; +static int sem_id = -1, sem_key = -1; -int sem_id_1 = -1; - -int main(int ac, char **av) +static void check_functionality(void) { - int lc; - void check_functionality(void); - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * Use TEST macro to make the call - */ - - TEST(semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "%s call failed - errno = %d : %s", - TCID, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - /* get the semaphore ID */ - sem_id_1 = TEST_RETURN; - - check_functionality(); - } - - /* - * remove the semaphore that was created and mark the ID - * as invalid. - */ - if (sem_id_1 != -1) { - rm_sema(sem_id_1); - sem_id_1 = -1; - } - } + struct semid_ds semary; + union semun un_arg; - cleanup(); + un_arg.buf = &semary; + SAFE_SEMCTL(sem_id, 0, IPC_STAT, un_arg); + TST_EXP_EQ_LI(un_arg.buf->sem_nsems, PSEMS); + TST_EXP_EQ_LI(un_arg.buf->sem_perm.cuid, geteuid()); - tst_exit(); + tst_res(TPASS, "basic semaphore values are okay"); } -/* - * check_functionality() - check the functionality of the tested system call. - */ -void check_functionality(void) +static void verify_semget(void) { - struct semid_ds semary; - union semun un_arg; /* union defined in ipcsem.h */ - - /* STAT the semaphore */ - un_arg.buf = &semary; - if (semctl(sem_id_1, 0, IPC_STAT, un_arg) == -1) { - tst_brkm(TBROK, cleanup, "Could not stat the semaphore"); + TEST(semget(sem_key, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "semget() failed"); return; } - if (un_arg.buf->sem_nsems != PSEMS) { - tst_resm(TFAIL, "# of semaphores in set != # given to create"); - return; - } + sem_id = TST_RET; + check_functionality(); - if (un_arg.buf->sem_perm.cuid != geteuid()) { - tst_resm(TFAIL, "semaphore uid != process uid"); - return; - } - - tst_resm(TPASS, "basic semaphore values are okay"); + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); + sem_key = GETIPCKEY(); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resouce */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget02.c b/testcases/kernel/syscalls/ipc/semget/semget02.c index 4124514c2..4273c84c7 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget02.c +++ b/testcases/kernel/syscalls/ipc/semget/semget02.c @@ -1,165 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget02.c +/*\ + * [Description] * - * DESCRIPTION - * semget02 - test for EACCES and EEXIST errors + * This basic error handing of the semget syscall. * - * ALGORITHM - * create a semaphore set without read or alter permissions - * loop if that option was specified - * call semget() using two different invalid cases - * check the errno value - * issue a PASS message if we get EACCES or EEXIST - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * - EACCES - a semaphore set exists for key, but the calling process does not + * have permission to access the set + * - EEXIST - a semaphore set already exists for key and IPC_CREAT | IPC_EXCL + * is given + * - ENOENT - No semaphore set exists for key and semflg did not specify + * IPC_CREAT + * - EINVAL - nsems is less than 0 or greater than the limit on the number of + * semaphores per semaphore set(SEMMSL) + * - EINVAL - a semaphore set corresponding to key already exists, but nsems is + * larger than the number of semaphores in that set */ -#include <pwd.h> - -#include "ipcsem.h" -char *TCID = "semget02"; -int TST_TOTAL = 2; - -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; - -int sem_id_1 = -1; - -struct test_case_t { +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/types.h> +#include <pwd.h> +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" +#include "libnewipc.h" +#include "lapi/sem.h" + +static int sem_id = -1; +static key_t semkey, semkey1; +static struct passwd *pw; +static struct tcase { + int *key; + int nsems; int flags; - int error; -} TC[] = { - /* EACCES - the semaphore has no read or alter permissions */ - { - SEM_RA, EACCES}, - /* EEXIST - the semaphore id exists and semget() was called with */ - /* IPC_CREAT and IPC_EXCL */ - { - IPC_CREAT | IPC_EXCL, EEXIST} + int exp_err; + /*1: nobody expected, 0: root expected */ + int exp_user; +} tcases[] = { + {&semkey, PSEMS, SEM_RA, EACCES, 1}, + {&semkey, PSEMS, IPC_CREAT | IPC_EXCL, EEXIST, 0}, + {&semkey1, PSEMS, SEM_RA, ENOENT, 0}, + {&semkey1, -1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey1, SEMMSL + 1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey, PSEMS + 1, SEM_RA, EINVAL, 0}, }; -int main(int ac, char **av) +static void verify_semget(struct tcase *tc) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* use the TEST macro to make the call */ - - TEST(semget(semkey, PSEMS, TC[i].flags)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded"); - continue; - } + TST_EXP_FAIL2(semget(*tc->key, tc->nsems, tc->flags), tc->exp_err, + "semget(%i, %i, %i)", *tc->key, tc->nsems, tc->flags); +} - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } +static void do_test(unsigned int n) +{ + pid_t pid; + struct tcase *tc = &tcases[n]; + + if (tc->exp_user == 0) { + verify_semget(tc); + } else { + pid = SAFE_FORK(); + if (pid) { + tst_reap_children(); + } else { + SAFE_SETUID(pw->pw_uid); + verify_semget(tc); + exit(0); } } - - cleanup(); - - tst_exit(); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - tst_require_root(); - - /* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + semkey1 = GETIPCKEY(); - TEST_PAUSE; + sem_id = SAFE_SEMGET(semkey, PSEMS, IPC_CREAT | IPC_EXCL); - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); - - /* create a semaphore set without read or alter permissions */ - if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) { - tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup"); - } + pw = SAFE_GETPWNAM("nobody"); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .needs_root = 1, + .forks_child = 1, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget03.c b/testcases/kernel/syscalls/ipc/semget/semget03.c deleted file mode 100644 index 995b4bd3a..000000000 --- a/testcases/kernel/syscalls/ipc/semget/semget03.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * NAME - * semget03.c - * - * DESCRIPTION - * semget03 - test for ENOENT error - * - * ALGORITHM - * loop if that option was specified - * call semget() with a valid key but with no associated semaphore set - * and IPC_CREAT is not asserted - * check the errno value - * issue a PASS message if we get ENOENT - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget03"; -int TST_TOTAL = 1; - -int sem_id_1 = -1; - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* use the TEST macro to make the call */ - - TEST(semget(semkey, PSEMS, SEM_RA)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded when error expected"); - continue; - } - - switch (TEST_ERRNO) { - case ENOENT: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); -} - -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/ipc/semget/semget05.c b/testcases/kernel/syscalls/ipc/semget/semget05.c index f801cb8ed..dd9a6285d 100644 --- a/testcases/kernel/syscalls/ipc/semget/semget05.c +++ b/testcases/kernel/syscalls/ipc/semget/semget05.c @@ -1,152 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget05.c - * - * DESCRIPTION - * semget05 - test for ENOSPC error +/*\ + * [Description] * - * ALGORITHM - * create semaphore sets in a loop until the system limit is reached - * loop if that option was specified - * attempt to create yet another semaphore set - * check the errno value - * issue a PASS message if we get ENOSPC - * otherwise, the tests fails - * issue a FAIL message - * call cleanup + * Test for ENOSPC error. * - * USAGE: <for command-line> - * HISTORY - * 03/2001 - Written by Wayne Boyer - * 07/2006 - Changes By Michael Reed - * - Changed the value of MAXIDS for the specific machine by reading - * the system limit for SEMMNI - The maximum number of sempahore sets - * 03/2008 - Matthieu Fertré (mfertre@irisa.fr) - * - Fix concurrency issue. Create private semaphores to - * avoid conflict with concurrent processes. - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget05"; -int TST_TOTAL = 1; - -/* - * The MAXIDS value is somewhat arbitrary and may need to be increased - * depending on the system being tested. + * ENOSPC - a semaphore set exceed the maximum number of semaphore sets(SEMMNI) */ -int MAXIDS = 2048; - -int *sem_id_arr = NULL; -int num_sems = 0; /* count the semaphores created */ - -int main(int ac, char **av) +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" + +static int *sem_id_arr; +static int maxsems, array_cnt, used_cnt; +static key_t semkey; + +static void verify_semget(void) { - int lc; - FILE *fp; - - tst_parse_opts(ac, av, NULL, NULL); - - /* Set the MAXIDS for the specific machine by reading the system limit - * for SEMMNI - The maximum number of sempahore sets - */ - fp = fopen("/proc/sys/kernel/sem", "r"); - if (fp != NULL) { - int getmaxid; - if (fscanf(fp, "%*d %*d %*d %d", &getmaxid) == 1) - MAXIDS = getmaxid + 1; - fclose(fp); - } - - sem_id_arr = malloc(sizeof(int) * MAXIDS); - if (sem_id_arr == NULL) - tst_brkm(TBROK, cleanup, "malloc failed"); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - - TEST(semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded when error expected"); - continue; - } - - switch (TEST_ERRNO) { - case ENOSPC: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - - cleanup(); - - tst_exit(); + TST_EXP_FAIL2(semget(semkey + maxsems, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA), + ENOSPC, "semget(%i, %i, %i)", semkey + maxsems, PSEMS, + IPC_CREAT | IPC_EXCL | SEM_RA); } -void setup(void) +static void setup(void) { - int sem_q; + int res, num; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + used_cnt = GET_USED_ARRAYS(); + tst_res(TINFO, "Current environment %d semaphore arrays are already in use", + used_cnt); + SAFE_FILE_SCANF("/proc/sys/kernel/sem", "%*d %*d %*d %d", &maxsems); - TEST_PAUSE; + /* Prevent timeout due to high semaphore array limit */ + tst_set_max_runtime(maxsems / 200); - tst_tmpdir(); - - while ((sem_q = semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL)) != -1) { - sem_id_arr[num_sems++] = sem_q; - if (num_sems == MAXIDS) { - tst_brkm(TBROK, cleanup, "The maximum number of " - "semaphore ID's has been\n\t reached. Please " - "increase the MAXIDS value in the test."); - } - } + sem_id_arr = SAFE_MALLOC((maxsems - used_cnt) * sizeof(int)); + for (num = 0; num < maxsems - used_cnt; num++) { + res = semget(semkey + num, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA); + if (res == -1) + tst_brk(TBROK | TERRNO, "semget failed unexpectedly"); - if (errno != ENOSPC) { - tst_brkm(TBROK, cleanup, "Didn't get ENOSPC in test setup" - " - errno = %d : %s", errno, strerror(errno)); + sem_id_arr[array_cnt++] = res; } + tst_res(TINFO, "The maximum number of semaphore arrays (%d) has been reached", + maxsems); } -void cleanup(void) +static void cleanup(void) { - int i; + int num; - for (i = 0; i < num_sems; i++) { - rm_sema(sem_id_arr[i]); - } + if (!sem_id_arr) + return; + + for (num = 0; num < array_cnt; num++) + SAFE_SEMCTL(sem_id_arr[num], PSEMS, IPC_RMID); free(sem_id_arr); - tst_rmdir(); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, + .save_restore = (const struct tst_path_val[]){ + {"/proc/sys/kernel/sem", NULL, + TST_SR_TCONF_MISSING | TST_SR_SKIP_RO}, + {} + } +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget06.c b/testcases/kernel/syscalls/ipc/semget/semget06.c deleted file mode 100644 index 52297c010..000000000 --- a/testcases/kernel/syscalls/ipc/semget/semget06.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * NAME - * semget06.c - * - * DESCRIPTION - * semget06 - test for EINVAL error - * - * ALGORITHM - * loop if that option was specified - * call semget() using two different invalid cases - too many and too - * few primitive semaphores - * check the errno value - * issue a PASS message if we get EINVAL - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: <for command-line> - * semget06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget06"; -int TST_TOTAL = 2; - -#define LARGENUM 1024 * 32 -#define SMALLNUM -1 - -int sem_id_1 = -1; - -int num_sems[] = { LARGENUM, SMALLNUM }; - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - - for (i = 0; i < TST_TOTAL; i++) { - TEST(semget(semkey, num_sems[i], - IPC_CREAT | IPC_EXCL | SEM_RA)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded"); - continue; - } - - switch (TEST_ERRNO) { - case EINVAL: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); -} - -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/ipc/semop/.gitignore b/testcases/kernel/syscalls/ipc/semop/.gitignore index bb57f08af..cc67b1862 100644 --- a/testcases/kernel/syscalls/ipc/semop/.gitignore +++ b/testcases/kernel/syscalls/ipc/semop/.gitignore @@ -1,3 +1,5 @@ /semop01 /semop02 /semop03 +/semop04 +/semop05 diff --git a/testcases/kernel/syscalls/ipc/semop/Makefile b/testcases/kernel/syscalls/ipc/semop/Makefile index 6b2b26d05..43afffb3f 100644 --- a/testcases/kernel/syscalls/ipc/semop/Makefile +++ b/testcases/kernel/syscalls/ipc/semop/Makefile @@ -7,6 +7,9 @@ LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpnewipc +semop01: LTPLDLIBS = -lltpnewipc +semop02: LTPLDLIBS = -lltpnewipc +semop03: LTPLDLIBS = -lltpnewipc +semop05: LDLIBS += -lpthread include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semop/semop04.c b/testcases/kernel/syscalls/ipc/semop/semop04.c new file mode 100644 index 000000000..1f49e7740 --- /dev/null +++ b/testcases/kernel/syscalls/ipc/semop/semop04.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (C) 2003-2023 Linux Test Project, Inc. + * Author: 2001 Paul Larson <plars@us.ibm.com> + * Modified: 2001 Manoj Iyer <manjo@ausin.ibm.com> + */ + +/*\ + * [Description] + * + * Creates a semaphore and two processes. The processes + * each go through a loop where they semdown, delay for a + * random amount of time, and semup, so they will almost + * always be fighting for control of the semaphore. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include "lapi/sem.h" +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" + +#define LOOPS 1000 +#define SEED 123 + +static void semup(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = 1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void semdown(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = -1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void mainloop(int semid) +{ + int i; + + for (i = 0; i < LOOPS; i++) { + semdown(semid); + usleep(1 + ((100.0 * rand()) / RAND_MAX)); + semup(semid); + } +} + +static void run(void) +{ + int semid; + union semun semunion; + pid_t pid; + + /* set up the semaphore */ + semid = SAFE_SEMGET((key_t) 9142, 1, 0666 | IPC_CREAT); + + semunion.val = 1; + + SAFE_SEMCTL(semid, 0, SETVAL, semunion); + + tst_res(TINFO, "srand seed is %d", SEED); + srand(SEED); + + pid = SAFE_FORK(); + + if (pid) { + mainloop(semid); + tst_reap_children(); + TST_EXP_POSITIVE(semctl(semid, 0, IPC_RMID, semunion)); + } else { + mainloop(semid); + } +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/ipc/semaphore/sem02.c b/testcases/kernel/syscalls/ipc/semop/semop05.c index 34b714bf0..34b714bf0 100644 --- a/testcases/kernel/ipc/semaphore/sem02.c +++ b/testcases/kernel/syscalls/ipc/semop/semop05.c diff --git a/testcases/kernel/syscalls/ipc/shmget/shmget02.c b/testcases/kernel/syscalls/ipc/shmget/shmget02.c index 3788e711f..8168803a5 100644 --- a/testcases/kernel/syscalls/ipc/shmget/shmget02.c +++ b/testcases/kernel/syscalls/ipc/shmget/shmget02.c @@ -11,17 +11,17 @@ * * Test for ENOENT, EEXIST, EINVAL, EACCES, EPERM errors. * - * ENOENT - No segment exists for the given key and IPC_CREAT was not specified. - * EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. - * EINVAL - A new segment was to be created and size is less than SHMMIN or - * greater than SHMMAX. Or a segment for the given key exists, but size is - * gran eater than the size of that segment. - * EACCES - The user does not have permission to access the shared memory segment. - * EPERM - The SHM_HUGETLB flag was specified, but the caller was not privileged - * (did not have the CAP_IPC_LOCK capability) and is not a member of the - * sysctl_hugetlb_shm_group group. - * ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but not - * have enough hugepage memory space. + * - ENOENT - No segment exists for the given key and IPC_CREAT was not specified. + * - EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. + * - EINVAL - A new segment was to be created and size is less than SHMMIN or + * greater than SHMMAX. Or a segment for the given key exists, but size is + * gran eater than the size of that segment. + * - EACCES - The user does not have permission to access the shared memory segment. + * - EPERM - The SHM_HUGETLB flag was specified, but the caller was not + * privileged (did not have the CAP_IPC_LOCK capability) and is not a member + * of the sysctl_hugetlb_shm_group group. + * - ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but + * not have enough hugepage memory space. */ #include <errno.h> @@ -56,7 +56,7 @@ static struct tcase { {&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT}, {&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST}, {&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, - {&shmkey1, SHMMAX + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, + {&shmkey1, 8192 + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES}, {&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM}, @@ -149,4 +149,8 @@ static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(tcases), .hugepages = {TST_NO_HUGEPAGES}, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/shmmax", "8192", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, + {} + }, }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl02.c b/testcases/kernel/syscalls/keyctl/keyctl02.c index 572f34b16..35cc2838d 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl02.c +++ b/testcases/kernel/syscalls/keyctl/keyctl02.c @@ -144,6 +144,7 @@ static struct tst_test test = { .test_all = do_test, .tags = (const struct tst_tag[]) { {"linux-git", "b4a1b4f5047e"}, + {"CVE", "2015-7550"}, {} } }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl07.c b/testcases/kernel/syscalls/keyctl/keyctl07.c index 875ef0bb8..d9e20db5f 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl07.c +++ b/testcases/kernel/syscalls/keyctl/keyctl07.c @@ -104,7 +104,7 @@ static struct tst_test test = { .test_all = do_test, .forks_child = 1, .tags = (const struct tst_tag[]) { - {"CVE", "2017-12912"}, + {"CVE", "2017-12192"}, {"linux-git", "37863c43b2c6"}, {} } diff --git a/testcases/kernel/syscalls/madvise/.gitignore b/testcases/kernel/syscalls/madvise/.gitignore index f4bfdfefe..722ac3c34 100644 --- a/testcases/kernel/syscalls/madvise/.gitignore +++ b/testcases/kernel/syscalls/madvise/.gitignore @@ -7,3 +7,4 @@ /madvise08 /madvise09 /madvise10 +/madvise11 diff --git a/testcases/kernel/syscalls/madvise/Makefile b/testcases/kernel/syscalls/madvise/Makefile index 044619fb8..78613df11 100644 --- a/testcases/kernel/syscalls/madvise/Makefile +++ b/testcases/kernel/syscalls/madvise/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +madvise11: CFLAGS += -pthread diff --git a/testcases/kernel/syscalls/madvise/madvise01.c b/testcases/kernel/syscalls/madvise/madvise01.c index 2262bf12d..884c59b0b 100644 --- a/testcases/kernel/syscalls/madvise/madvise01.c +++ b/testcases/kernel/syscalls/madvise/madvise01.c @@ -11,7 +11,6 @@ */ #include <sys/types.h> -#include <sys/mman.h> #include <sys/stat.h> #include <sys/mount.h> #include <errno.h> diff --git a/testcases/kernel/syscalls/madvise/madvise02.c b/testcases/kernel/syscalls/madvise/madvise02.c index 858d67ae2..90c0431c5 100644 --- a/testcases/kernel/syscalls/madvise/madvise02.c +++ b/testcases/kernel/syscalls/madvise/madvise02.c @@ -30,7 +30,6 @@ */ #include <sys/types.h> -#include <sys/mman.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/time.h> diff --git a/testcases/kernel/syscalls/madvise/madvise06.c b/testcases/kernel/syscalls/madvise/madvise06.c index c7967ae6f..be22318ea 100644 --- a/testcases/kernel/syscalls/madvise/madvise06.c +++ b/testcases/kernel/syscalls/madvise/madvise06.c @@ -198,7 +198,7 @@ static void test_advice_willneed(void) meminfo_diag("After madvise"); res = swapcached > swapcached_start + PASS_THRESHOLD_KB; - tst_res(res ? TPASS : TFAIL, + tst_res(res ? TPASS : TINFO, "%s than %ld Kb were moved to the swap cache", res ? "more" : "less", PASS_THRESHOLD_KB); @@ -226,10 +226,15 @@ static void test_advice_willneed(void) meminfo_diag("After page access"); res = page_fault_num_2 - page_fault_num_1; - tst_res(res == 0 ? TPASS : TFAIL, + tst_res(res == 0 ? TPASS : TINFO, "%d pages were faulted out of 3 max", res); SAFE_MUNMAP(target, CHUNK_SZ); + + if (tst_taint_check()) + tst_res(TFAIL, "Kernel tainted"); + else + tst_res(TPASS, "No kernel taints"); } static struct tst_test test = { @@ -237,6 +242,7 @@ static struct tst_test test = { .setup = setup, .needs_tmpdir = 1, .needs_root = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/swappiness", NULL, TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, diff --git a/testcases/kernel/syscalls/madvise/madvise11.c b/testcases/kernel/syscalls/madvise/madvise11.c new file mode 100644 index 000000000..7a12abf20 --- /dev/null +++ b/testcases/kernel/syscalls/madvise/madvise11.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + */ + +/*\ + * [Description] + * + * Stress a possible race condition between memory pages allocation + * and soft-offline of unrelated pages as explained in the commit: + * d4ae9916ea29 (mm: soft-offline: close the race against page allocation) + * + * Control that soft-offlined pages get correctly replaced: with the + * same content and without SIGBUS generation when accessed. + */ + +#include <errno.h> +#include <mntent.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/klog.h> + +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "tst_safe_stdio.h" +#include "lapi/mmap.h" + +#define NUM_LOOPS 5 +#define NUM_PAGES 32 +#define NUM_PAGES_OFFSET 5 + +/* Needed module to online back memory pages */ +#define HW_MODULE "hwpoison_inject" + +static pthread_t *thread_ids; +static int number_threads; +static int run_iterations; +static int maximum_pfns; + +static volatile int sigbus_received; +static pthread_cond_t sigbus_received_cv; +static pthread_mutex_t sigbus_received_mtx = PTHREAD_MUTEX_INITIALIZER; + +static long pagesize; +static char beginning_tag[BUFSIZ]; +static int hwpoison_probe; + +static void my_yield(void) +{ + static const struct timespec t0 = { 0, 0 }; + + nanosleep(&t0, NULL); +} + +/* a SIGBUS received is a confirmation of test failure */ +static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + sigbus_received++; + pthread_cond_signal(&sigbus_received_cv); + pthread_mutex_unlock(&sigbus_received_mtx); + pause(); +} + +static void *sigbus_monitor(void *arg LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + while (!sigbus_received) + pthread_cond_wait(&sigbus_received_cv, &sigbus_received_mtx); + pthread_mutex_unlock(&sigbus_received_mtx); + tst_res(TFAIL, "SIGBUS Received"); + exit(1); +} + +/* + * Allocate a page and write a sentinel value into it. + */ +static void *allocate_write(int sentinel) +{ + void *p; + int *s; + + p = SAFE_MMAP(NULL, pagesize, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + s = (int *)p; + *s = sentinel; + return p; +} + +/* + * Verify and unmap the given page. + */ +static int verif_unmap(void *page, int sentinel) +{ + int *s = (int *)page; + + if (*s != sentinel) { + tst_res(TFAIL, "pid[%d]: fail: bad sentinel value seen: %d expected: %d\n", getpid(), *s, sentinel); + return 1; + } + + return SAFE_MUNMAP(page, pagesize); +} + +/* + * allocate_offline() - Allocate and offline test called per-thread + * + * This function does the allocation and offline by mmapping an + * anonymous page and offlining it. + */ +static int allocate_offline(int tnum) +{ + int loop; + + for (loop = 0; loop < NUM_LOOPS; loop++) { + long *ptrs[NUM_PAGES]; + int num_alloc; + int i; + + for (num_alloc = 0; num_alloc < NUM_PAGES; num_alloc++) { + + ptrs[num_alloc] = allocate_write((tnum << NUM_PAGES_OFFSET) | num_alloc); + if (ptrs[num_alloc] == NULL) + return -1; + + if (madvise(ptrs[num_alloc], pagesize, MADV_SOFT_OFFLINE) == -1) { + if (errno != EINVAL) + tst_res(TFAIL | TERRNO, "madvise failed"); + if (errno == EINVAL) + tst_res(TCONF, "madvise() didn't support MADV_SOFT_OFFLINE"); + return errno; + } + } + + for (i = 0; i < num_alloc; i++) { + if (verif_unmap(ptrs[i], (tnum << NUM_PAGES_OFFSET) | i) != 0) + return 1; + } + + my_yield(); + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Thread [%d]: Test runtime is over, exiting", tnum); + break; + } + } + + return 0; +} + +static void *alloc_mem(void *threadnum) +{ + int err; + int tnum = (int)(uintptr_t)threadnum; + + /* waiting for other threads starting */ + TST_CHECKPOINT_WAIT(0); + + err = allocate_offline(tnum); + tst_res(TINFO, + "Thread [%d] returned %d, %s.", tnum, err, (err ? "failed" : "succeeded")); + return (void *)(uintptr_t) (err ? -1 : 0); +} + +static void stress_alloc_offl(void) +{ + int thread_index; + int thread_failure = 0; + pthread_t sigbus_monitor_t; + + run_iterations++; + + SAFE_PTHREAD_CREATE(&sigbus_monitor_t, NULL, sigbus_monitor, NULL); + pthread_detach(sigbus_monitor_t); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + SAFE_PTHREAD_CREATE(&thread_ids[thread_index], NULL, alloc_mem, + (void *)(uintptr_t)thread_index); + } + + TST_CHECKPOINT_WAKE2(0, number_threads); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + void *status; + + SAFE_PTHREAD_JOIN(thread_ids[thread_index], &status); + if ((intptr_t)status != 0) { + tst_res(TFAIL, "thread [%d] - exited with errors", + thread_index); + thread_failure++; + } + } + + if (thread_failure == 0) + tst_res(TPASS, "soft-offline / mmap race still clean"); +} + +/* + * ------------ + * Cleanup code: + * The idea is to retrieve all the pfn numbers that have been soft-offined + * (generating a "Soft offlining pfn 0x..." message in the kernel ring buffer) + * by the current test (since a "beginning_tag" message we write when starting). + * And to put these pages back online by writing the pfn number to the + * <debugfs>/hwpoison/unpoison-pfn special file. + * ------------ + */ +#define OFFLINE_PATTERN "Soft offlining pfn 0x" +#define OFFLINE_PATTERN_LEN sizeof(OFFLINE_PATTERN) + +/* return the pfn if the kmsg msg is a soft-offline indication*/ +static unsigned long parse_kmsg_soft_offlined_pfn(char *line, ssize_t len) +{ + char *pos; + unsigned long addr = 0UL; + + pos = strstr(line, OFFLINE_PATTERN); + if (pos == NULL) + return 0UL; + + pos += OFFLINE_PATTERN_LEN-1; + if (pos > (line + len)) + return 0UL; + + addr = strtoul(pos, NULL, 16); + if ((addr == ULONG_MAX) && (errno == ERANGE)) + return 0UL; + + return addr; +} + +/* return the pfns seen in kernel message log */ +static int populate_from_klog(char *begin_tag, unsigned long *pfns, int max) +{ + int found = 0, fd, beginning_tag_found = 0; + ssize_t sz; + unsigned long pfn; + char buf[BUFSIZ]; + + fd = SAFE_OPEN("/dev/kmsg", O_RDONLY|O_NONBLOCK); + + while (found < max) { + sz = read(fd, buf, sizeof(buf)); + /* kmsg returns EPIPE if record was modified while reading */ + if (sz < 0 && errno == EPIPE) + continue; + if (sz <= 0) + break; + if (!beginning_tag_found) { + if (strstr(buf, begin_tag)) + beginning_tag_found = 1; + continue; + } + pfn = parse_kmsg_soft_offlined_pfn(buf, sz); + if (pfn) + pfns[found++] = pfn; + } + SAFE_CLOSE(fd); + return found; +} + +/* + * Read the given file to search for the key. + * Return 1 if the key is found. + */ +static int find_in_file(char *path, char *key) +{ + char line[4096]; + int found = 0; + FILE *file = SAFE_FOPEN(path, "r"); + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, key)) { + found = 1; + break; + } + } + SAFE_FCLOSE(file); + return found; +} + +static void unpoison_this_pfn(unsigned long pfn, int fd) +{ + char pfn_str[19]; + + snprintf(pfn_str, sizeof(pfn_str), "0x%lx", pfn); + SAFE_WRITE(0, fd, pfn_str, strlen(pfn_str)); +} + +/* Find and open the <debugfs>/hwpoison/unpoison-pfn special file */ +static int open_unpoison_pfn(void) +{ + char *added_file_path = "/hwpoison/unpoison-pfn"; + const char *const cmd_modprobe[] = {"modprobe", HW_MODULE, NULL}; + char debugfs_fp[4096]; + struct mntent *mnt; + FILE *mntf; + + if (!find_in_file("/proc/modules", HW_MODULE) && tst_check_builtin_driver(HW_MODULE)) + hwpoison_probe = 1; + + /* probe hwpoison only if it isn't already there */ + if (hwpoison_probe) + SAFE_CMD(cmd_modprobe, NULL, NULL); + + /* debugfs mount point */ + mntf = setmntent("/proc/mounts", "r"); + if (!mntf) { + tst_brk(TBROK | TERRNO, "Can't open /proc/mounts"); + return -1; + } + while ((mnt = getmntent(mntf)) != NULL) { + if (strcmp(mnt->mnt_type, "debugfs") == 0) { + strcpy(debugfs_fp, mnt->mnt_dir); + strcat(debugfs_fp, added_file_path); + break; + } + } + endmntent(mntf); + if (!mnt) + return -1; + + TEST(open(debugfs_fp, O_WRONLY)); + + if (TST_RET == -1 && TST_ERR == EPERM && tst_lockdown_enabled() > 0) { + tst_res(TINFO, + "Cannot restore soft-offlined memory due to lockdown"); + return TST_RET; + } + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, "open(%s) failed", debugfs_fp); + } else if (TST_RET < 0) { + tst_brk(TBROK | TTERRNO, "Invalid open() return value %ld", + TST_RET); + } + + return TST_RET; +} + +/* + * Get all the Offlined PFNs indicated in the dmesg output + * starting after the given beginning tag, and request a debugfs + * hwpoison/unpoison-pfn for each of them. + */ +static void unpoison_pfn(char *begin_tag) +{ + unsigned long *pfns; + const char *const cmd_rmmod[] = {"rmmod", HW_MODULE, NULL}; + int found_pfns, fd; + + pfns = SAFE_MALLOC(sizeof(pfns) * maximum_pfns * run_iterations); + + fd = open_unpoison_pfn(); + if (fd >= 0) { + found_pfns = populate_from_klog(begin_tag, pfns, maximum_pfns * run_iterations); + + tst_res(TINFO, "Restore %d Soft-offlined pages", found_pfns); + /* unpoison in reverse order */ + while (found_pfns-- > 0) + unpoison_this_pfn(pfns[found_pfns], fd); + + SAFE_CLOSE(fd); + } + /* remove hwpoison only if we probed it */ + if (hwpoison_probe) + SAFE_CMD(cmd_rmmod, NULL, NULL); +} + +/* + * Create and write a beginning tag to the kernel buffer to be used on cleanup + * when trying to restore the soft-offlined pages of our test run. + */ +static void write_beginning_tag_to_kmsg(void) +{ + int fd; + + fd = SAFE_OPEN("/dev/kmsg", O_WRONLY); + snprintf(beginning_tag, sizeof(beginning_tag), + "Soft-offlining pages test starting (pid: %ld)", + (long)getpid()); + SAFE_WRITE(1, fd, beginning_tag, strlen(beginning_tag)); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + struct sigaction my_sigaction; + + number_threads = (int)sysconf(_SC_NPROCESSORS_ONLN) * 2; + if (number_threads <= 1) + number_threads = 2; + else if (number_threads > 5) + number_threads = 5; + + maximum_pfns = number_threads * NUM_LOOPS * NUM_PAGES; + thread_ids = SAFE_MALLOC(sizeof(pthread_t) * number_threads); + pagesize = sysconf(_SC_PAGESIZE); + + /* SIGBUS is the main failure criteria */ + my_sigaction.sa_handler = sigbus_handler; + if (sigaction(SIGBUS, &my_sigaction, NULL) == -1) + tst_res(TFAIL | TERRNO, "Signal handler attach failed"); + + write_beginning_tag_to_kmsg(); + tst_res(TINFO, "Spawning %d threads, with a total of %d memory pages", + number_threads, maximum_pfns); +} + +static void cleanup(void) +{ + unpoison_pfn(beginning_tag); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_drivers = (const char *const []) { + HW_MODULE, + NULL + }, + .needs_cmds = (const char *[]) { + "modprobe", + "rmmod", + NULL + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_MEMORY_FAILURE=y", + NULL + }, + .max_runtime = 30, + .needs_checkpoints = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = stress_alloc_offl, + .tags = (const struct tst_tag[]) { + {"linux-git", "d4ae9916ea29"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create02.c b/testcases/kernel/syscalls/memfd_create/memfd_create02.c index f547e1424..b9ddc0825 100644 --- a/testcases/kernel/syscalls/memfd_create/memfd_create02.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create02.c @@ -13,10 +13,8 @@ #define _GNU_SOURCE #include <errno.h> - -#include <tst_test.h> - #include "memfd_create_common.h" +#include "tst_test.h" static char buf[2048]; static char term_buf[2048]; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create04.c b/testcases/kernel/syscalls/memfd_create/memfd_create04.c index 7b699b218..585f17e16 100644 --- a/testcases/kernel/syscalls/memfd_create/memfd_create04.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create04.c @@ -1,20 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 - * Email: code@zilogic.com + * Copyright (c) Zilogic Systems Pvt. Ltd. <code@zilogic.com>, 2018 + * Copyright (c) Linux Test Project, 2019-2023 */ -/* - * Test: Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. +/*\ + * [Description] + * + * Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. * - * Test cases: Attempt to create files in the hugetlbfs filesystem using - * different huge page sizes. + * Attempt to create files in the hugetlbfs filesystem using different huge page + * sizes. * - * Test logic: memfd_create() should return non-negative value (fd) - * if the system supports that particular huge page size. - * On success, fd is returned. - * On failure, -1 is returned with ENODEV error. + * [Algorithm] + * + * memfd_create() should return non-negative value (fd) if the system supports + * that particular huge page size. + * On success, fd is returned. On failure, -1 is returned with ENODEV error. */ #define _GNU_SOURCE @@ -25,8 +28,6 @@ #include <errno.h> #include <stdio.h> -#define PATH_HUGEPAGES "/sys/kernel/mm/hugepages" - static struct test_flag { int flag; char *h_size; @@ -48,7 +49,7 @@ static void check_hugepage_support(struct test_flag *test_flags) char pattern[64]; sprintf(pattern, PATH_HUGEPAGES); - strcat(pattern, "/hugepages-"); + strcat(pattern, "hugepages-"); strcat(pattern, test_flags->h_size); if (access(pattern, F_OK)) diff --git a/testcases/kernel/syscalls/mknod/mknod01.c b/testcases/kernel/syscalls/mknod/mknod01.c index f79e5fa42..7a4d5b43f 100644 --- a/testcases/kernel/syscalls/mknod/mknod01.c +++ b/testcases/kernel/syscalls/mknod/mknod01.c @@ -1,123 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + */ + +/*\ + * [Description] * + * Verify that mknod(2) successfully creates a filesystem node with + * various modes. */ -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/sysmacros.h> - -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "mknod01"; +#include "tst_test.h" #define PATH "test_node" -int tcases[] = { /* modes to give nodes created (1 per text case) */ - S_IFREG | 0777, /* ordinary file with mode 0777 */ - S_IFIFO | 0777, /* fifo special with mode 0777 */ - S_IFCHR | 0777, /* character special with mode 0777 */ - S_IFBLK | 0777, /* block special with mode 0777 */ +static int tcases[] = { + S_IFREG | 0777, + S_IFIFO | 0777, + S_IFCHR | 0777, + S_IFBLK | 0777, - S_IFREG | 04700, /* ordinary file with mode 04700 (suid) */ - S_IFREG | 02700, /* ordinary file with mode 02700 (sgid) */ - S_IFREG | 06700, /* ordinary file with mode 06700 (sgid & suid) */ + S_IFREG | 04700, + S_IFREG | 02700, + S_IFREG | 06700, }; -int TST_TOTAL = ARRAY_SIZE(tcases); -int main(int ac, char **av) +static void run(unsigned int i) { - int lc, i; - dev_t dev; - - tst_parse_opts(ac, av, NULL, NULL); + dev_t dev = 0; - setup(); + if (S_ISCHR(tcases[i]) || S_ISBLK(tcases[i])) + dev = makedev(1, 3); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* - * overlayfs doesn't support mknod char device with - * major 0 and minor 0, which is known as whiteout_dev - */ - if (S_ISCHR(tcases[i])) - dev = makedev(1, 3); - else - dev = 0; - TEST(mknod(PATH, tcases[i], dev)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, %lu) failed, errno=%d : %s", - PATH, tcases[i], dev, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "mknod(%s, %#o, %lu) returned %ld", - PATH, tcases[i], dev, TEST_RETURN); - } - - SAFE_UNLINK(cleanup, PATH); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(mknod(PATH, tcases[i], dev), + "mknod(PATH, %o, %ld)", + tcases[i], dev); + SAFE_UNLINK(PATH); } -void setup(void) -{ - tst_require_root(); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); -} - -void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mknod/mknod02.c b/testcases/kernel/syscalls/mknod/mknod02.c index 594473e24..b1885fed1 100644 --- a/testcases/kernel/syscalls/mknod/mknod02.c +++ b/testcases/kernel/syscalls/mknod/mknod02.c @@ -1,301 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Name: mknod02 - * - * Test Description: - * Verify that mknod(2) succeeds when used to create a filesystem - * node with set group-ID bit set on a directory without set group-ID bit set. - * The node created should have set group-ID bit set and its gid should be - * equal to that of its parent directory. - * - * Expected Result: - * mknod() should return value 0 on success and node created should have - * set group-ID bit set, its gid should be equal to that of its parent - * directory. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: <for command-line> - * mknod02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Verify that if mknod(2) creates a filesystem node in a directory which + * does not have the set-group-ID bit set, new node will not inherit the + * group ownership from its parent directory and its group ID will be the + * effective group ID of the process. */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> #include <pwd.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -#define LTPUSER "nobody" -#define MODE_RWX S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO -#define MODE_SGID S_IFIFO | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO -#define DIR_TEMP "testdir_2" -#define TNODE "tnode_%d" +#define MODE_DIR 0777 +#define MODE1 0010777 +#define MODE_SGID 02000 -struct stat buf; /* struct. to hold stat(2) o/p contents */ -struct passwd *user1; /* struct. to hold getpwnam(3) o/p contents */ +#define TEMP_DIR "testdir" +#define TEMP_NODE "testnode" -char *TCID = "mknod02"; -int TST_TOTAL = 1; -char node_name[PATH_MAX]; /* buffer to hold node name created */ +static struct stat buf; +static struct passwd *user_nobody; +static gid_t gid_nobody; -gid_t group1_gid, group2_gid, mygid; /* user and process group id's */ -uid_t save_myuid, user1_uid; /* user and process user id's */ -pid_t mypid; /* process id */ - -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) +static void setup(void) { - int lc; - int fflag; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Attempt to create a filesystem node with group-id bit set - * on a directory without group id bit set such that, - * the node created by mknod(2) should have group-id (sgid) - * bit set and node's gid should be equal to that of its - * parent directory. - */ - TEST(mknod(node_name, MODE_SGID, 0)); - - /* Check return code from mknod(2) */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, 0) failed, errno=%d : %s", - node_name, MODE_SGID, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } - /* Set the functionality flag */ - fflag = 1; - - /* Check for node's creation */ - if (stat(node_name, &buf) < 0) { - tst_resm(TFAIL, "stat() of %s failed, errno:%d", - node_name, TEST_ERRNO); - - /* unset functionality flag */ - fflag = 0; - } - - /* Verify mode permissions of node */ - if (!(buf.st_mode & S_ISGID)) { - tst_resm(TFAIL, "%s: Incorrect modes, setgid " - "bit not set", node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - - /* Verify group ID of node */ - if (buf.st_gid != mygid) { - tst_resm(TFAIL, "%s: Incorrect group", - node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - if (fflag) { - tst_resm(TPASS, "Functionality of mknod(%s, " - "%#o, 0) successful", - node_name, MODE_SGID); - } - - /* Remove the node for the next go `round */ - if (unlink(node_name) == -1) { - tst_resm(TWARN, "unlink(%s) failed, errno:%d %s", - node_name, errno, strerror(errno)); - } - } + user_nobody = SAFE_GETPWNAM("nobody"); + gid_nobody = user_nobody->pw_gid; - /* Change the directory back to temporary directory */ - SAFE_CHDIR(cleanup, ".."); - - /* - * Invoke cleanup() to delete the test directories created - * in the setup() and exit main(). - */ - cleanup(); - - tst_exit(); + SAFE_MKDIR(TEMP_DIR, MODE_DIR); + SAFE_CHOWN(TEMP_DIR, -1, gid_nobody); } -/* - * setup(void) - performs all ONE TIME setup for this test. - * Exit the test program on receipt of unexpected signals. - * Create a temporary directory used to hold test directories created - * and change the directory to it. - * Verify that pid of process executing the test is root. - * Create a test directory on temporary directory and set the ownership - * of test directory to ltp user and process. - * Set the effective uid/gid of the process to that of ltp user. - */ -void setup(void) +static void run(void) { - tst_require_root(); - - /* Capture unexpected signals */ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Make a temp dir and cd to it */ - tst_tmpdir(); - - /* fix permissions on the tmpdir */ - if (chmod(".", 0711) != 0) { - tst_brkm(TBROK, cleanup, "chmod() failed"); - } - - /* Save the real user id of the current test process */ - save_myuid = getuid(); - - /* Save the process id of the current test process */ - mypid = getpid(); - - /* Get the node name to be created in the test */ - sprintf(node_name, TNODE, mypid); - - /* Get the uid/gid of ltpuser */ - if ((user1 = getpwnam(LTPUSER)) == NULL) { - tst_brkm(TBROK | TERRNO, cleanup, - "Couldn't determine if %s was in /etc/passwd", - LTPUSER); - } - user1_uid = user1->pw_uid; - group1_gid = user1->pw_gid; - - /* Get the effective group id of the test process */ - group2_gid = getegid(); + SAFE_CHDIR(TEMP_DIR); + TST_EXP_PASS(mknod(TEMP_NODE, MODE1, 0), "mknod(%s, %o, 0)", TEMP_NODE, MODE1); - /* - * Create a test directory under temporary directory with the - * specified mode permissions, with uid/gid set to that of guest - * user and the test process. - */ - SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); - SAFE_CHOWN(cleanup, DIR_TEMP, user1_uid, group2_gid); + SAFE_STAT(TEMP_NODE, &buf); + TST_EXP_EQ_LI(buf.st_gid, 0); - /* - * Verify that test directory created with expected permission modes - * and ownerships. - */ - SAFE_STAT(cleanup, DIR_TEMP, &buf); - - /* Verify modes of test directory */ - if (buf.st_mode & S_ISGID) { - tst_brkm(TBROK, cleanup, - "%s: Incorrect modes, setgid bit set", DIR_TEMP); - } - - /* Verify group ID of test directory */ - if (buf.st_gid != group2_gid) { - tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); - } - - /* - * Set the effective group id and user id of the test process - * to that of guest user. - */ - SAFE_SETGID(cleanup, group1_gid); - if (setreuid(-1, user1_uid) < 0) { - tst_brkm(TBROK, cleanup, - "Unable to set process uid to that of ltp user"); - } - - /* Save the real group ID of the current process */ - mygid = getgid(); - - /* Change directory to DIR_TEMP */ - SAFE_CHDIR(cleanup, DIR_TEMP); + SAFE_UNLINK(TEMP_NODE); + SAFE_CHDIR(".."); } -/* - * cleanup() - Performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Print test timing stats and errno log if test executed with options. - * Restore the real/effective user id of the process changed during - * setup(). - * Remove temporary directory and sub-directories/files under it - * created during setup(). - * Exit the test program with normal exit code. - */ -void cleanup(void) -{ - - /* - * Restore the effective uid of the process changed in the - * setup(). - */ - if (setreuid(-1, save_myuid) < 0) { - tst_brkm(TBROK, NULL, - "resetting process real/effective uid failed"); - } - - tst_rmdir(); - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mlock/mlock01.c b/testcases/kernel/syscalls/mlock/mlock01.c index 2338d4d56..0b079f8be 100644 --- a/testcases/kernel/syscalls/mlock/mlock01.c +++ b/testcases/kernel/syscalls/mlock/mlock01.c @@ -1,145 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * NAME - * mlock01.c - * - * DESCRIPTION - * Test to see that mlock works - *$ - * ALGORITHM - * test 1: - * Call mlock with various valid addresses and lengths. No - * error should be returned - * - * USAGE: <for command-line> - * -c n Run n copies concurrently - * -e Turn on errno logging - * -f Turn off functional testing - * -h Show this help screen - * -i n Execute test n times - * -I x Execute test for x seconds - * -p Pause for SIGUSR1 before starting - * -P x Pause for x seconds between iterations - * -t Turn on syscall timing + * Copyright (c) International Business Machines Corp., 2002 * * HISTORY * 06/2002 Written by Paul Larson - * - * RESTRICTIONS - * None */ -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test mlock with various valid addresses and lengths. + */ -char *TCID = "mlock01"; -int TST_TOTAL = 4; +#include <stdlib.h> +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - /* mlock should return ENOMEM when some or all of the address - * range pointed to by addr and len are not valid mapped pages - * in the address space of the process - */ - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"mlock 1 byte", 1}, + {"mlock 1024 bytes", 1024}, + {"mlock 1024 * 1024 bytes", 1024 * 1024}, + {"mlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -#if !defined(UCLINUX) - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* - * FIXME (garrcoop): this should really test out whether or not the - * process's mappable address space is indeed accessible by the - * current user, instead of needing to be run by root all the time. - */ - tst_require_root(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(TC[i].len); - - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* I'm confused -- given the description above this - * should fail as designed, but this application - * */ - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "mlock failed"); - else - tst_resm(TPASS, "mlock passed"); - } - } - - cleanup(); - - tst_exit(); -} - -#else - -int main(void) +static void do_mlock(unsigned int i) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); -} - -#endif /* if !defined(UCLINUX) */ + struct tcase *tc = &tcases[i]; -void setup(void) -{ - TEST_PAUSE; + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + TST_EXP_PASS(mlock(addr, tc->len), "mlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -void setup1(int len) +static void cleanup(void) { - addr1 = malloc(len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); + if (addr) + free(addr); } -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = do_mlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock02.c b/testcases/kernel/syscalls/mlock/mlock02.c index 50ee31d1c..921ddeeae 100644 --- a/testcases/kernel/syscalls/mlock/mlock02.c +++ b/testcases/kernel/syscalls/mlock/mlock02.c @@ -1,109 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2002 - * 06/2002 Written by Paul Larson + * Copyright (c) International Business Machines Corp., 2002 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 06/2002 Written by Paul Larson */ -/* - * Test Description: - * Verify that, - * 1. mlock() fails with -1 return value and sets errno to ENOMEM, - * if some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * 2. mlock() fails with -1 return value and sets errno to ENOMEM, - * if (Linux 2.6.9 and later) the caller had a non-zero RLIMIT_MEMLOCK - * soft resource limit, but tried to lock more memory than the limit - * permitted. This limit is not enforced if the process is privileged - * (CAP_IPC_LOCK). - * 3. mlock() fails with -1 return value and sets errno to EPERM, - * if (Linux 2.6.9 and later) the caller was not privileged (CAP_IPC_LOCK) - * and its RLIMIT_MEMLOCK soft resource limit was 0. +/*\ + * [Description] + * + * Test for ENOMEM, EPERM errors. + * + * 1) mlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of + * the process. + * + * 2) mlock(2) fails with ENOMEM if the caller had a non-zero RLIMIT_MEMLOCK + * soft resource limit, but tried to lock more memory than the limit + * permitted. This limit is not enforced if the process is + * privileged (CAP_IPC_LOCK). + * + * 3) mlock(2) fails with EPERM if the caller was not privileged (CAP_IPC_LOCK) + * and its RLIMIT_MEMLOCK soft resource limit was 0. */ -#include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/types.h> #include <pwd.h> - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "mlock02"; - -#if !defined(UCLINUX) - -static void setup(void); -static void cleanup(void); -static void test_enomem1(void); -static void test_enomem2(void); -static void test_eperm(void); -static void mlock_verify(const void *, const size_t, const int); +#include "tst_test.h" static size_t len; static struct rlimit original; static struct passwd *ltpuser; -static void (*test_func[])(void) = { test_enomem1, test_enomem2, test_eperm }; - -int TST_TOTAL = ARRAY_SIZE(test_func); - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - (*test_func[i])(); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); - - len = getpagesize(); - - SAFE_GETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); -} - static void test_enomem1(void) { void *addr; - struct rlimit rl; - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - mlock_verify(addr, len, ENOMEM); + SAFE_MUNMAP(addr, len); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); } static void test_enomem2(void) @@ -113,20 +50,14 @@ static void test_enomem2(void) rl.rlim_max = len - 1; rl.rlim_cur = len - 1; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, ENOMEM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } static void test_eperm(void) @@ -136,51 +67,32 @@ static void test_eperm(void) rl.rlim_max = 0; rl.rlim_cur = 0; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, EPERM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), EPERM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } -static void mlock_verify(const void *addr, const size_t len, const int error) +static void run(void) { - TEST(mlock(addr, len)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mlock succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO != error) { - tst_resm(TFAIL | TTERRNO, - "mlock didn't fail as expected; expected - %d : %s", - error, strerror(error)); - } else { - tst_resm(TPASS | TTERRNO, "mlock failed as expected"); - } + test_enomem1(); + test_enomem2(); + test_eperm(); } -static void cleanup(void) -{ -} - -#else - -int TST_TOTAL = 1; - -int main(void) +static void setup(void) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); + ltpuser = SAFE_GETPWNAM("nobody"); + len = getpagesize(); + SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &original); } -#endif /* if !defined(UCLINUX) */ +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock03.c b/testcases/kernel/syscalls/mlock/mlock03.c index 8bc65701c..3700b64b0 100644 --- a/testcases/kernel/syscalls/mlock/mlock03.c +++ b/testcases/kernel/syscalls/mlock/mlock03.c @@ -1,5 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This case is a regression test on old RHEL5. + * * Stack size mapping is decreased through mlock/munlock call. + * See the following url: + * https://bugzilla.redhat.com/show_bug.cgi?id=643426 * * This is to test kernel if it has a problem with shortening [stack] * mapping through several loops of mlock/munlock of /proc/self/maps. @@ -11,109 +22,61 @@ * munlock 44KiB bfefa000-bff05000 rw-p 00000000 00:00 0 [stack] * * with more iterations - could drop to 0KiB. - * - * Copyright (C) 2010 Red Hat, Inc. - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ + #include <sys/mman.h> #include <stdio.h> #include <string.h> -#include "test.h" +#include <pwd.h> +#include "tst_test.h" +#include "tst_safe_stdio.h" #define KB 1024 -char *TCID = "mlock03"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void verify_mlock(void) { - int lc; long from, to; long first = -1, last = -1; char b[KB]; FILE *fp; - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + fp = SAFE_FOPEN("/proc/self/maps", "r"); + while (!feof(fp)) { + if (!fgets(b, KB - 1, fp)) + break; + b[strlen(b) - 1] = '\0'; + if (sscanf(b, "%lx-%lx", &from, &to) != 2) { + tst_brk(TBROK, "parse %s start and end address failed", + b); + continue; + } - for (lc = 0; TEST_LOOPING(lc); lc++) { - fp = fopen("/proc/self/maps", "r"); - if (fp == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "fopen"); - while (!feof(fp)) { - if (!fgets(b, KB - 1, fp)) - break; - b[strlen(b) - 1] = '\0'; - sscanf(b, "%lx-%lx", &from, &to); + /* Record the initial stack size. */ + if (strstr(b, "[stack]") != NULL) + first = (to - from) / KB; - /* Record the initial stack size. */ - if (lc == 0 && strstr(b, "[stack]") != NULL) - first = (to - from) / KB; + tst_res(TINFO, "mlock [%lx,%lx]", from, to); + if (mlock((const void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "mlock failed"); - switch (lc & 1) { - case 0: - if (mlock((const void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "mlock failed"); - break; - case 1: - if (munlock((void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "munlock failed"); - break; - default: - break; - } - tst_resm(TINFO, "%s from %lx to %0lx", - (lc & 1) ? "munlock" : "mlock", from, to); + tst_res(TINFO, "munlock [%lx,%lx]", from, to); + if (munlock((void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "munlock failed"); - /* Record the final stack size. */ - if (strstr(b, "[stack]") != NULL) - last = (to - from) / KB; - } - fclose(fp); + /* Record the final stack size. */ + if (strstr(b, "[stack]") != NULL) + last = (to - from) / KB; } - tst_resm(TINFO, "starting stack size is %ld", first); - tst_resm(TINFO, "final stack size is %ld", last); + SAFE_FCLOSE(fp); + + tst_res(TINFO, "starting stack size is %ld", first); + tst_res(TINFO, "final stack size is %ld", last); if (last < first) - tst_resm(TFAIL, "stack size is decreased."); + tst_res(TFAIL, "stack size is decreased."); else - tst_resm(TPASS, "stack size is not decreased."); - - cleanup(); - tst_exit(); + tst_res(TPASS, "stack size is not decreased."); } -void setup(void) -{ - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_mlock, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock04.c b/testcases/kernel/syscalls/mlock/mlock04.c index 8ac884583..f25460ba1 100644 --- a/testcases/kernel/syscalls/mlock/mlock04.c +++ b/testcases/kernel/syscalls/mlock/mlock04.c @@ -1,102 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * This is a reproducer copied from one of LKML patch submission, + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This is a reproducer copied from one of LKML patch submission * which subject is * * [PATCH] mlock: revert the optimization for dirtying pages and triggering writeback. + * url see https://www.spinics.net/lists/kernel/msg1141090.html * * "In 5ecfda0, we do some optimization in mlock, but it causes * a very basic test case(attached below) of mlock to fail. So * this patch revert it with some tiny modification so that it * apply successfully with the lastest 38-rc2 kernel." * - * Copyright (C) 2010 Red Hat, Inc. - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. + * This bug was fixed by kernel + * commit fdf4c587a7 ("mlock: operate on any regions with protection != PROT_NONE") * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * As this case does, mmaps a file with PROT_WRITE permissions but without + * PROT_READ, so attempt to not unnecessarity break COW during mlock ended up + * causing mlock to fail with a permission problem on unfixed kernel. */ -#include "test.h" -#include "safe_macros.h" -#include "config.h" - -char *TCID = "mlock04"; -int TST_TOTAL = 1; #include <sys/mman.h> #include <stdio.h> #include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> - -int fd, file_len = 40960; -char *testfile = "test_mlock"; +#include "tst_test.h" +#include "tst_safe_macros.h" -static void setup(void); -static void cleanup(void); +static int fd = -1, file_len = 40960; +static char *testfile = "test_mlock"; -int main(void) +static void verify_mlock(void) { char *buf; - int lc; - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - buf = mmap(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); - - if (buf == MAP_FAILED) - tst_brkm(TBROK | TERRNO, cleanup, "mmap"); - if (mlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mlock"); - - tst_resm(TINFO, "locked %d bytes from %p", file_len, buf); - - if (munlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "munlock"); - - SAFE_MUNMAP(cleanup, buf, file_len); - } - - tst_resm(TPASS, "test succeeded."); - - cleanup(); - - tst_exit(); + buf = SAFE_MMAP(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); + TST_EXP_PASS(mlock(buf, file_len), "mlock(%p, %d)", buf, file_len); + SAFE_MUNLOCK(buf, file_len); + SAFE_MUNMAP(buf, file_len); } static void setup(void) { - tst_tmpdir(); - - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - - SAFE_FTRUNCATE(cleanup, fd, file_len); - - TEST_PAUSE; + fd = SAFE_OPEN(testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + SAFE_FTRUNCATE(fd, file_len); } static void cleanup(void) { - close(fd); - - tst_rmdir(); + if (fd > -1) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_mlock, + .tags = (const struct tst_tag[]) { + {"linux-git", "fdf4c587a793"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/mmap/.gitignore b/testcases/kernel/syscalls/mmap/.gitignore index 8811226be..4591fdbb9 100644 --- a/testcases/kernel/syscalls/mmap/.gitignore +++ b/testcases/kernel/syscalls/mmap/.gitignore @@ -5,7 +5,6 @@ /mmap04 /mmap05 /mmap06 -/mmap07 /mmap08 /mmap09 /mmap10 @@ -18,3 +17,4 @@ /mmap17 /mmap18 /mmap19 +/mmap20 diff --git a/testcases/kernel/syscalls/mmap/mmap02.c b/testcases/kernel/syscalls/mmap/mmap02.c index 566cc323a..7ffe61fa3 100644 --- a/testcases/kernel/syscalls/mmap/mmap02.c +++ b/testcases/kernel/syscalls/mmap/mmap02.c @@ -1,186 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() with prot parameter set to PROT_READ and with the file - * descriptor being open for read, to map a file creating mapped memory - * with read access. The minimum file permissions should be 0444. - * - * The call should succeed to create the mapped region with required - * attributes. +/*\ + * [Description] * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * the mapped region should contain the contents of the mapped file. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with PROT_READ and a file descriptor which is + * open for read only, succeeds to map a file creating mapped memory with + * read access. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap02"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define TEMPFILE "mmapfile" +static ssize_t page_sz; +static int fd; static char *addr; -static char *dummy; -static size_t page_sz; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); - continue; - } - - /* - * Read the file contents into the dummy - * string. - */ - if (read(fildes, dummy, page_sz) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, - "reading %s failed", TEMPFILE); - } - - /* - * Check whether mapped memory region has - * the file contents. - */ - if (memcmp(dummy, addr, page_sz)) { - tst_resm(TFAIL, "mapped memory area contains " - "invalid data"); - } else { - tst_resm(TPASS, - "Functionality of mmap() successful"); - } - - /* Clean up things in case we are looping */ - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmapping failed"); - } - } - - cleanup(); - tst_exit(); -} +static char *buf; static void setup(void) { - char *tst_buff; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, - "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Change Mode permissions on Temporary file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod(%s, 0444) failed", - TEMPFILE); - } - - /* Close the temporary file */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_FCHMOD(fd, 0444); + SAFE_CLOSE(fd); + fd = SAFE_OPEN(TEMPFILE, O_RDONLY); +} - /* Open the temporary file again, - Readonly mode */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL, cleanup, "reopening %s readonly failed", - TEMPFILE); - } +static void run(void) +{ + addr = SAFE_MMAP(NULL, page_sz, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); - /* Allocate and initialize dummy string of system page size bytes */ - if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); - } + if (memcmp(buf, addr, page_sz) == 0) + tst_res(TPASS, "mmap() functionality successful"); + else + tst_res(TFAIL, "mapped memory area contains invalid data"); + SAFE_MUNMAP(addr, page_sz); } static void cleanup(void) { - close(fildes); - free(dummy); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); + + free(buf); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap05.c b/testcases/kernel/syscalls/mmap/mmap05.c index 82f122543..7abddaa9e 100644 --- a/testcases/kernel/syscalls/mmap/mmap05.c +++ b/testcases/kernel/syscalls/mmap/mmap05.c @@ -1,205 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() to map a file creating mapped memory with no access under - * the following conditions - - * - The prot parameter is set to PROT_NONE - * - The file descriptor is open for read(any mode other than write) - * - The minimum file permissions should be 0444. - * - * The call should succeed to map the file creating mapped memory with the - * required attributes. - * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * and an attempt to access the contents of the mapped region should give - * rise to the signal SIGSEGV. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with 'PROT_NONE' and a file descriptor which is + * open for read and write, succeeds to map the file creating mapped memory, + * but any attempt to access the contents of the mapped region causes the + * SIGSEGV signal. */ -#include <stdio.h> + #include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> #include <setjmp.h> +#include "tst_test.h" -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap05"; -int TST_TOTAL = 1; - +#define TEMPFILE "mmapfile" static size_t page_sz; static volatile char *addr; -static int fildes; -static volatile int pass = 0; +static int fd; +static volatile int sig_flag; static sigjmp_buf env; -static void setup(void); -static void cleanup(void); -static void sig_handler(int sig); - -int main(int ac, char **av) +static void sig_handler(int sig) { - int lc; - char file_content; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with no access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_NONE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap() failed on %s", - TEMPFILE); - continue; - } - - /* - * Try to access the mapped region. This should - * generate a SIGSEGV which will be caught below. - * - * This is wrapped by the sigsetjmp() call that will - * take care of restoring the program's context in an - * elegant way in conjunction with the call to - * siglongjmp() in the signal handler. - */ - if (sigsetjmp(env, 1) == 0) { - file_content = addr[0]; - } - - if (pass) { - tst_resm(TPASS, "Got SIGSEGV as expected"); - } else { - tst_resm(TFAIL, "Mapped memory region with NO " - "access is accessible"); - } - - /* Unmap mapped memory and reset pass in case we are looping */ - if (munmap((void *)addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmap failed"); - } - pass = 0; - + if (sig == SIGSEGV) { + sig_flag = 1; + siglongjmp(env, 1); } - - cleanup(); - tst_exit(); } static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, sig_handler, cleanup); + char *buf; - TEST_PAUSE; + SAFE_SIGNAL(SIGSEGV, sig_handler); page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); +static void run(void) +{ + addr = mmap(NULL, page_sz, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + tst_res(TFAIL | TERRNO, "mmap() of %s failed", TEMPFILE); + return; } - /* Free the memory allocated for test buffer */ - free(tst_buff); + if (sigsetjmp(env, 1) == 0) + tst_res(TINFO, "Trying to access mapped region: %c", addr[0]); - /* Make sure proper permissions set on file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod of %s failed", - TEMPFILE); - } + if (sig_flag) + tst_res(TPASS, "Received SIGSEGV signal as expected"); + else + tst_res(TFAIL, "SIGSEGV signal not received"); - /* Close the temporary file opened for write */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_MUNMAP((char *)addr, page_sz); - /* Open the temporary file again for reading */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s readonly failed", - TEMPFILE); - } -} - -/* - * sig_handler() - Signal Catching function. - * This function gets executed when the test process receives - * the signal SIGSEGV while trying to access the contents of memory which - * is not accessible. - */ -static void sig_handler(int sig) -{ - if (sig == SIGSEGV) { - /* set the global variable and jump back */ - pass = 1; - siglongjmp(env, 1); - } else { - tst_brkm(TBROK, cleanup, "received an unexpected signal: %d", - sig); - } + sig_flag = 0; } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap06.c b/testcases/kernel/syscalls/mmap/mmap06.c index fb7c49257..615743fa7 100644 --- a/testcases/kernel/syscalls/mmap/mmap06.c +++ b/testcases/kernel/syscalls/mmap/mmap06.c @@ -1,143 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() to map a file creating a mapped region with read access - * under the following conditions - - * - The prot parameter is set to PROT_READ - * - The file descriptor is open for writing. +/*\ + * [Description] * - * The call should fail to map the file. + * Verify that, mmap() call fails with errno: * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EACCES. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * - EACCES, when a file mapping is requested but the file descriptor is not open for reading. + * - EINVAL, when length argument is 0. + * - EINVAL, when flags contains none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" - -#define TEMPFILE "mmapfile" -char *TCID = "mmap06"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define MMAPSIZE 1024 +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL | TERRNO, - "mmap() returned invalid value, expected: %p", - MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_resm(TBROK, "munmap() failed"); - cleanup(); - } - continue; - } - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "mmap failed with EACCES"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with unexpected errno"); - } - } - cleanup(); - tst_exit(); - -} +static int fd; + +static struct tcase { + size_t length; + int prot; + int flags; + int exp_errno; +} tcases[] = { + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {0, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EINVAL}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE, EINVAL} +}; static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + char *buf; page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc() failed (tst_buff)"); - } + fd = SAFE_OPEN(TEMPFILE, O_WRONLY | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); +static void run(unsigned int i) +{ + struct tcase *tc = &tcases[i]; - tst_tmpdir(); + TESTPTR(mmap(NULL, tc->length, tc->prot, tc->flags, fd, 0)); - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() was successful unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, MMAPSIZE); + } else if (TST_ERR == tc->exp_errno) { + tst_res(TPASS | TERRNO, "mmap() failed with"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed unexpectedly"); } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (ssize_t)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - free(tst_buff); } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap07.c b/testcases/kernel/syscalls/mmap/mmap07.c deleted file mode 100644 index 682e527aa..000000000 --- a/testcases/kernel/syscalls/mmap/mmap07.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * Test Description: - * Call mmap() to map a file creating a mapped region with read access - * under the following conditions - - * - The prot parameter is set to PROT_WRITE - * - The file descriptor is open for writing. - * - The flags parameter has MAP_PRIVATE set. - * - * The call should fail to map the file. - * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EACCES. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap07"; -int TST_TOTAL = 1; - -static size_t page_sz; -static char *addr; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with write access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_WRITE, - MAP_FILE | MAP_PRIVATE, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL | TERRNO, - "mmap() returned invalid value, expected: %p", - MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_resm(TBROK, "munmap() failed"); - cleanup(); - } - continue; - } - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "mmap failed with EACCES"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with unexpected errno"); - } - - } - cleanup(); - tst_exit(); - -} - -static void setup(void) -{ - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, - "calloc() failed to allocate space for tst_buff"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "open() on %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - free(tst_buff); -} - -static void cleanup(void) -{ - close(fildes); - tst_rmdir(); -} diff --git a/testcases/kernel/syscalls/mmap/mmap08.c b/testcases/kernel/syscalls/mmap/mmap08.c index f2daf45a3..5c9fd782c 100644 --- a/testcases/kernel/syscalls/mmap/mmap08.c +++ b/testcases/kernel/syscalls/mmap/mmap08.c @@ -1,142 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Verify that mmap() fails to map a file creating a mapped region - * when the file specified by file descriptor is not valid. - * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EBADF. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * verify that, mmap() calls fails with errno EBADF when a file mapping + * is requested but the fd is not a valid file descriptor. */ -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap08"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; +static int fd; -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * which is already closed. so, fildes is not valid. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_WRITE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL, "mmap() didn't fail (%p != %p)", - addr, MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TBROK, cleanup, "munmap() failed"); - } - continue; - } - if (TEST_ERRNO == EBADF) { - tst_resm(TPASS, "mmap failed with EBADF"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with an invalid errno"); - } - } - - cleanup(); - tst_exit(); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_CLOSE(fd); } -static void setup(void) +static void run(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, - "calloc() failed to allocate space for tst_buff"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Close the temporary file opened for writing */ - if (close(fildes) < 0) { - tst_brkm(TFAIL, cleanup, "closing %s failed", TEMPFILE); + TESTPTR(mmap(NULL, page_sz, PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0)); + + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() passed unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, page_sz); + } else if (TST_ERR == EBADF) { + tst_res(TPASS, "mmap() failed with EBADF"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed with an invalid errno"); } } static void cleanup(void) { - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap17.c b/testcases/kernel/syscalls/mmap/mmap17.c index a8136a0b2..39703fbd3 100644 --- a/testcases/kernel/syscalls/mmap/mmap17.c +++ b/testcases/kernel/syscalls/mmap/mmap17.c @@ -17,7 +17,6 @@ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> -#include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> diff --git a/testcases/kernel/syscalls/mmap/mmap20.c b/testcases/kernel/syscalls/mmap/mmap20.c new file mode 100644 index 000000000..02d150e45 --- /dev/null +++ b/testcases/kernel/syscalls/mmap/mmap20.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Paulson Raja L <paulson@zilogic.com> + */ + +/*\ + * [Description] + * + * Test mmap(2) with MAP_SHARED_VALIDATE flag. + * + * Test expected EOPNOTSUPP errno when testing mmap(2) with MAP_SHARED_VALIDATE + * flag and invalid flag. + */ + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include "tst_test.h" +#include "lapi/mmap.h" + +#define TEST_FILE "file_to_mmap" +#define TEST_FILE_SIZE 1024 +#define INVALID_FLAG (1 << 10) + +static int fd = -1; +static void *addr; + +static void setup(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_RDWR, 0600); + + if (tst_fill_file(TEST_FILE, 'a', TEST_FILE_SIZE, 1)) + tst_brk(TBROK, "Could not fill the testfile"); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); + + if (addr && addr != MAP_FAILED) + SAFE_MUNMAP(addr, TEST_FILE_SIZE); +} + +static void test_mmap(void) +{ + addr = mmap(NULL, TEST_FILE_SIZE, PROT_READ | PROT_WRITE, + INVALID_FLAG | MAP_SHARED_VALIDATE, fd, 0); + + if (addr != MAP_FAILED) + tst_res(TFAIL | TERRNO, "mmap() is successful, but it should have failed"); + else if (errno == EOPNOTSUPP) + tst_res(TPASS, "mmap() failed with errno set to EOPNOTSUPP"); + else + tst_res(TFAIL | TERRNO, "mmap() failed with unexpected error"); +} + +static struct tst_test test = { + .min_kver = "4.15", + .setup = setup, + .cleanup = cleanup, + .test_all = test_mmap, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/mount/.gitignore b/testcases/kernel/syscalls/mount/.gitignore index f92600d36..80885dbf0 100644 --- a/testcases/kernel/syscalls/mount/.gitignore +++ b/testcases/kernel/syscalls/mount/.gitignore @@ -5,3 +5,4 @@ /mount04 /mount05 /mount06 +/mount07 diff --git a/testcases/kernel/syscalls/mount/mount03.c b/testcases/kernel/syscalls/mount/mount03.c index 60f9963da..98d5933b7 100644 --- a/testcases/kernel/syscalls/mount/mount03.c +++ b/testcases/kernel/syscalls/mount/mount03.c @@ -122,7 +122,7 @@ static void test_file_dir_noatime(int update_fatime, int update_datime) SAFE_CLOSEDIR(test_dir); dir_atime = dir_st.st_atime; - sleep(1); + usleep(1001000); SAFE_READ(0, otfd, readbuf, sizeof(readbuf)); SAFE_FSTAT(otfd, &st); diff --git a/testcases/kernel/syscalls/mount/mount07.c b/testcases/kernel/syscalls/mount/mount07.c new file mode 100644 index 000000000..eb3fb55a0 --- /dev/null +++ b/testcases/kernel/syscalls/mount/mount07.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for MS_NOSYMFOLLOW mount option and is copied + * from kernel selftests nosymfollow-test.c. + * + * It tests to make sure that symlink traversal fails with ELOOP when + * 'nosymfollow' is set, but symbolic links can still be created, and + * readlink(2) and realpath(3) still work properly. It also verifies + * that statfs(2) correctly returns ST_NOSYMFOLLOW. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mount.h> +#include <stdbool.h> +#include "tst_test.h" +#include "lapi/mount.h" + +#ifndef ST_NOSYMFOLLOW +# define ST_NOSYMFOLLOW 0x2000 +#endif + +#define MNTPOINT "mntpoint" + +static char test_file[PATH_MAX]; +static char link_file[PATH_MAX]; +static char temp_link_file[PATH_MAX]; +static int flag; + +static void setup_symlink(void) +{ + int fd; + + fd = SAFE_CREAT(test_file, O_RDWR); + SAFE_SYMLINK(test_file, link_file); + SAFE_CLOSE(fd); + flag = 1; +} + +static void test_link_traversal(bool nosymfollow) +{ + if (nosymfollow) { + TST_EXP_FAIL2(open(link_file, 0, O_RDWR), ELOOP, + "open(%s, 0, O_RDWR)", link_file); + } else { + TST_EXP_FD(open(link_file, 0, O_RDWR)); + } + + if (TST_RET > 0) + SAFE_CLOSE(TST_RET); +} + +static void test_readlink(void) +{ + char buf[4096]; + + memset(buf, 0, 4096); + TST_EXP_POSITIVE(readlink(link_file, buf, sizeof(buf)), + "readlink(%s, buf, %ld)", link_file, sizeof(buf)); + if (strcmp(buf, test_file) != 0) { + tst_res(TFAIL, "readlink strcmp failed, %s, %s", + buf, test_file); + } else { + tst_res(TPASS, "readlink strcmp succeeded"); + } +} + +static void test_realpath(void) +{ + TESTPTR(realpath(link_file, NULL)); + + if (!TST_RET_PTR) { + tst_res(TFAIL | TERRNO, "realpath failed"); + return; + } + + if (strcmp(TST_RET_PTR, test_file) != 0) { + tst_res(TFAIL, "realpath strcmp failed, %s, %s", + (char *)TST_RET_PTR, test_file); + } else { + tst_res(TPASS, "realpath strcmp succeeded"); + } +} + +static void test_cycle_link(void) +{ + TST_EXP_PASS(symlink(test_file, temp_link_file), "symlink(%s, %s)", + test_file, temp_link_file); + TST_EXP_PASS(unlink(temp_link_file)); +} + +static void test_statfs(bool nosymfollow) +{ + struct statfs buf; + + SAFE_STATFS(MNTPOINT, &buf); + if (buf.f_flags & ST_NOSYMFOLLOW) { + tst_res(nosymfollow ? TPASS : TFAIL, "ST_NOSYMFOLLOW set on %s", + MNTPOINT); + } else { + tst_res(nosymfollow ? TFAIL : TPASS, "ST_NOSYMFOLLOW not set on %s", + MNTPOINT); + } +} + +static void setup(void) +{ + char *tmpdir = tst_get_tmpdir(); + + snprintf(test_file, PATH_MAX, "%s/%s/test_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(link_file, PATH_MAX, "%s/%s/link_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(temp_link_file, PATH_MAX, "%s/%s/temp_link_file", + tst_get_tmpdir(), MNTPOINT); + free(tmpdir); +} + +static void cleanup(void) +{ + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); +} + +static void run_tests(bool nosymfollow) +{ + test_link_traversal(nosymfollow); + test_readlink(); + test_realpath(); + test_cycle_link(); + test_statfs(nosymfollow); +} + +static void run(void) +{ + tst_res(TINFO, "Testing behaviour when not setting MS_NOSYMFOLLOW"); + + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + 0, NULL)); + if (!flag || !strcmp(tst_device->fs_type, "tmpfs")) + setup_symlink(); + run_tests(false); + + tst_res(TINFO, "Testing behaviour when setting MS_NOSYMFOLLOW"); + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + MS_REMOUNT | MS_NOSYMFOLLOW, NULL)); + run_tests(true); + + SAFE_UMOUNT(MNTPOINT); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .min_kver = "5.10", + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c index 83746b878..e500df28e 100644 --- a/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c +++ b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c @@ -32,7 +32,6 @@ #include <sys/statvfs.h> #include "tst_test.h" #include "lapi/fsmount.h" -#include "lapi/stat.h" #define MNTPOINT "mntpoint" #define OT_MNTPOINT "ot_mntpoint" diff --git a/testcases/kernel/syscalls/mprotect/.gitignore b/testcases/kernel/syscalls/mprotect/.gitignore index 9571ffd43..929c3b3a2 100644 --- a/testcases/kernel/syscalls/mprotect/.gitignore +++ b/testcases/kernel/syscalls/mprotect/.gitignore @@ -2,3 +2,4 @@ /mprotect02 /mprotect03 /mprotect04 +/mprotect05 diff --git a/testcases/kernel/syscalls/mprotect/mprotect05.c b/testcases/kernel/syscalls/mprotect/mprotect05.c new file mode 100644 index 000000000..2b15f5beb --- /dev/null +++ b/testcases/kernel/syscalls/mprotect/mprotect05.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All Rights Reserved. + * Author: Liam R. Howlett <liam.howlett@oracle.com> + */ + +/*\ + * [Description] + * + * Testcase to check the mprotect(2) system call split and merge. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=217061 + * + */ + +#include "tst_test.h" + +#define TEST_FILE "mprotect05-testfile" + +static int fd; +static char *addr = MAP_FAILED; +static unsigned long pagesize; +static unsigned long fullsize; + +static void setup(void) +{ + pagesize = getpagesize(); + fullsize = 5 * pagesize; +} + +static void run(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0777); + addr = SAFE_MMAP(0, fullsize, PROT_READ, MAP_SHARED, fd, 0); + + if (mprotect(addr + pagesize, pagesize, PROT_EXEC)) + tst_res(TFAIL | TERRNO, "mprotect failed to exec"); + + if (mprotect(addr + 3 * pagesize, pagesize, PROT_WRITE)) + tst_res(TFAIL | TERRNO, "mprotect failed to write"); + + if (mprotect(addr + pagesize, pagesize * 4, PROT_READ)) + tst_res(TFAIL | TERRNO, "mprotect failed to read"); + + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + addr = MAP_FAILED; + SAFE_UNLINK(TEST_FILE); + tst_res(TPASS, "test passed"); +} + +static void cleanup(void) +{ + if (addr != MAP_FAILED) { + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + } +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .tags = (const struct tst_tag[]) { + {"linux-git", "2fcd07b7ccd5"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/mq_notify/.gitignore b/testcases/kernel/syscalls/mq_notify/.gitignore index cca05a7fa..3f9403c05 100644 --- a/testcases/kernel/syscalls/mq_notify/.gitignore +++ b/testcases/kernel/syscalls/mq_notify/.gitignore @@ -1,2 +1,3 @@ /mq_notify01 /mq_notify02 +/mq_notify03 diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify02.c b/testcases/kernel/syscalls/mq_notify/mq_notify02.c index 3109fe345..d979a4e9d 100644 --- a/testcases/kernel/syscalls/mq_notify/mq_notify02.c +++ b/testcases/kernel/syscalls/mq_notify/mq_notify02.c @@ -1,91 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. - * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program. + * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * ALGORITHM - * test 1: - * sevp->sigev_notify = -1, EINVAL should be returned. - * test 2: - * sevp->sigev_notify = SIGEV_SIGNAL and sevp->sigev_signo > _NSG, - * EINVAL should be returned. + +/*\ + * [Description] + * + * This test verifies that mq_notify() fails with EINVAL when invalid input + * arguments are given. */ -#include <errno.h> #include <mqueue.h> -#include "test.h" - -char *TCID = "mq_notify02"; -static void setup(void); -static void cleanup(void); +#include "tst_test.h" static struct test_case_t { struct sigevent sevp; int exp_errno; -} test_cases[] = { +} tcase[] = { {{.sigev_notify = -1}, EINVAL}, - {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG+1}, EINVAL}, + {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG + 1}, EINVAL}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void mq_notify_verify(struct test_case_t *); - -int main(int argc, char **argv) -{ - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - mq_notify_verify(&test_cases[i]); - } - cleanup(); - tst_exit(); -} - -static void setup(void) +static void run(unsigned int i) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + struct test_case_t *test = &tcase[i]; - TEST_PAUSE; + TST_EXP_FAIL(mq_notify(0, &(test->sevp)), test->exp_errno); } -static void mq_notify_verify(struct test_case_t *test) -{ - TEST(mq_notify(0, &(test->sevp))); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mq_notify() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "mq_notify failed as expected"); - } else if (TEST_ERRNO == ENOSYS) { - tst_resm(TCONF | TTERRNO, "mq_notify not available"); - } else { - tst_resm(TFAIL | TTERRNO, - "mq_notify failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcase), + .test = run, +}; diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify03.c b/testcases/kernel/syscalls/mq_notify/mq_notify03.c new file mode 100644 index 000000000..bf6898cd8 --- /dev/null +++ b/testcases/kernel/syscalls/mq_notify/mq_notify03.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) The GNU Toolchain Authors. + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + * + */ + +/*\ + * [Description] + * + * Test for NULL pointer dereference in mq_notify(CVE-2021-38604) + * + * References links: + * - https://sourceware.org/bugzilla/show_bug.cgi?id=28213 + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <mqueue.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" + +static mqd_t m = -1; +static const char msg[] = "hello"; + +static void try_null_dereference_cb(union sigval sv) +{ + char buf[sizeof(msg)]; + + (void)sv; + + TST_EXP_VAL((size_t) mq_receive(m, buf, sizeof(buf), NULL), + sizeof(buf)); + TST_EXP_PASS(memcmp(buf, msg, sizeof(buf))); + + exit(0); +} + +static void try_null_dereference(void) +{ + struct sigevent sev; + + memset(&sev, '\0', sizeof(sev)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = try_null_dereference_cb; + + /* Step 1: Register & unregister notifier. + * Helper thread should receive NOTIFY_REMOVED notification. + * In a vulnerable version of glibc, NULL pointer dereference follows. + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_notify(m, NULL)); + + /* Step 2: Once again, register notification. + * Try to send one message. + * Test is considered successful, if the callback does exit (0). + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_send(m, msg, sizeof(msg), 1)); + + /* Wait... */ + pause(); +} + +static void do_test(void) +{ + static const char m_name[] = "/ltp_mq_notify03"; + struct mq_attr m_attr; + + memset(&m_attr, '\0', sizeof(m_attr)); + m_attr.mq_maxmsg = 1; + m_attr.mq_msgsize = sizeof(msg); + + m = SAFE_MQ_OPEN(m_name, + O_RDWR | O_CREAT | O_EXCL, + 0600, + &m_attr); + + TST_EXP_PASS(mq_unlink(m_name)); + + try_null_dereference(); +} + + +static struct tst_test test = { + .test_all = do_test, + .tags = (const struct tst_tag[]) { + {"glibc-git", "b805aebd42"}, + {"CVE", "2021-38604"}, + {} + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/mremap/.gitignore b/testcases/kernel/syscalls/mremap/.gitignore index 833e1b883..ec15a19cd 100644 --- a/testcases/kernel/syscalls/mremap/.gitignore +++ b/testcases/kernel/syscalls/mremap/.gitignore @@ -3,3 +3,4 @@ /mremap03 /mremap04 /mremap05 +/mremap06 diff --git a/testcases/kernel/syscalls/mremap/mremap06.c b/testcases/kernel/syscalls/mremap/mremap06.c new file mode 100644 index 000000000..a19262750 --- /dev/null +++ b/testcases/kernel/syscalls/mremap/mremap06.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC + * Author: Vlastimil Babka <vbabka@suse.cz> + * https://bugzilla.suse.com/attachment.cgi?id=867254 + * LTP port: Petr Vorel <pvorel@suse.cz> + */ + +/*\ + * [Description] + * + * Bug reproducer for 7e7757876f25 ("mm/mremap: fix vm_pgoff in vma_merge() case 3") + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "tst_test.h" +#include "tst_safe_macros.h" + +#define NUM_PAGES 3 + +static int fd; +static char *buf, *buf2; +static int page_size, mmap_size, mremap_size; + +static struct tcase { + size_t incompatible; + const char *desc; +} tcases[] = { + { + .desc = "all pages with compatible mapping", + }, + { + .incompatible = 3, + .desc = "third page's mapping incompatible", + }, + { + .incompatible = 1, + .desc = "first page's mapping incompatible", + }, +}; + +static int check_pages(void) +{ + int fail = 0, i; + char val; + + for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { + val = buf[i * page_size]; + if (val != 0x30 + i) { + tst_res(TFAIL, "page %d wrong value %d (0x%x)", i, val - 0x30, val); + fail = 1; + } + } + + return fail; +} + +static void do_test(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int ret; + + tst_res(TINFO, "%s", tc->desc); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + buf2 = mremap(buf + page_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + mremap_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (tc->incompatible) { + ret = mprotect(buf + (tc->incompatible-1)*page_size, page_size, PROT_READ); + if (ret == -1) + tst_brk(TBROK, "mprotect() failed"); + } + + buf2 = mremap(buf + mremap_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + page_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (!check_pages()) + tst_res(TPASS, "mmap/mremap work properly"); + + SAFE_MUNMAP(buf, mremap_size); +} + +static void setup(void) +{ + int ret, i; + + page_size = getpagesize(); + mmap_size = (NUM_PAGES+1) * page_size; + mremap_size = NUM_PAGES * page_size; + + fd = SAFE_OPEN("testfile", O_CREAT | O_RDWR | O_TRUNC, 0600); + + ret = fallocate(fd, 0, 0, mmap_size); + if (ret == -1) + tst_brk(TBROK, "fallocate() failed"); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + for (i = 0; i < (int)ARRAY_SIZE(tcases)+1; i++) + buf[i*page_size] = 0x30 + i; + + /* clear the page tables */ + SAFE_MUNMAP(buf, mmap_size); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = do_test, + .needs_tmpdir = 1, + .tcnt = ARRAY_SIZE(tcases), + .tags = (struct tst_tag[]) { + {"linux-git", "7e7757876f25"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/msync/msync01.c b/testcases/kernel/syscalls/msync/msync01.c index 3a5a48ee5..3c57ebb99 100644 --- a/testcases/kernel/syscalls/msync/msync01.c +++ b/testcases/kernel/syscalls/msync/msync01.c @@ -25,7 +25,7 @@ * of, or all of a mapped region. * * Expected Result: - * msync() should succeed with a return value of 0, and succesfully + * msync() should succeed with a return value of 0, and successfully * synchronize the memory region. Data read from mapped region should be * the same as the initialized data. * diff --git a/testcases/kernel/syscalls/munlock/munlock01.c b/testcases/kernel/syscalls/munlock/munlock01.c index 8a52f032d..31d749e66 100644 --- a/testcases/kernel/syscalls/munlock/munlock01.c +++ b/testcases/kernel/syscalls/munlock/munlock01.c @@ -1,162 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * AUTHOR: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock01 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic test for munlock(2) - * - * TEST CASE TOTAL : 4 - * - * AUTHOR : Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * This is a Phase I test for the munlock(2) system call. - * It is intended to provide a limited exposure of the system call. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * USAGE: <for command-line> - * munlock01 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * RESTRICTIONS - * Must be root/superuser to run it. - *****************************************************************************/ - -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test munlock with various valid addresses and lengths. + */ -char *TCID = "munlock01"; -int TST_TOTAL = 4; +#include <stdlib.h> +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"munlock 1 byte", 1}, + {"munlock 1024 bytes", 1024}, + {"munlock 1024 * 1024 bytes", 1024 * 1024}, + {"munlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(i); - - TEST(munlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "mlock(%p, %d) Failed with " - "return=%ld", TC[i].addr, TC[i].len, - TEST_RETURN); - } else { - tst_resm(TPASS, "test %d passed length = %d", - i, TC[i].len); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); -} - -void setup1(int i) +static void verify_munlock(unsigned int i) { - addr1 = malloc(TC[i].len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", TC[i].addr, - TC[i].len, TEST_RETURN); - } + struct tcase *tc = &tcases[i]; + + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + SAFE_MLOCK(addr, tc->len); + TST_EXP_PASS(munlock(addr, tc->len), "munlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -/* setup() - performs all ONE TIME setup for this test. */ -void setup(void) +static void cleanup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (addr) + free(addr); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = verify_munlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/munlock/munlock02.c b/testcases/kernel/syscalls/munlock/munlock02.c index 75906a1df..f51c3d21f 100644 --- a/testcases/kernel/syscalls/munlock/munlock02.c +++ b/testcases/kernel/syscalls/munlock/munlock02.c @@ -1,198 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * AUTHOR: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock02 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Test for checking basic error conditions for - * munlock(2) - * - * TEST CASE TOTAL : 2 - * - * AUTHOR : Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * Check for basic errors returned by munlock(2) system call. - * - * Verify that munlock(2) returns -1 and sets errno to - * - * 1) ENOMEM - Some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Do necessary setup for each test. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given + +/*\ + * [Description] * - * USAGE: <for command-line> - * munlock02 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Test for ENOMEM error. * - * RESTRICTIONS - * Test must run as root. - *****************************************************************************/ -#include <errno.h> -#include <unistd.h> -#include <sys/mman.h> -#include <pwd.h> -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "munlock02"; -int TST_TOTAL = 1; - -#define LEN 1024 - -void *addr1; + * munlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of the + * process. + */ -struct test_case_t { - void *addr; - int len; - int error; - char *edesc; -} TC[] = { - { -NULL, 0, ENOMEM, "address range out of address space"},}; +#include <sys/mman.h> +#include "tst_test.h" -#if !defined(UCLINUX) +static size_t len, pg_size; +static void *addr; -int main(int ac, char **av) +static void run(void) { - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) { -#ifdef __ia64__ - TC[0].len = 8 * getpagesize(); -#endif - TEST(munlock(TC[i].addr, TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - if (TEST_ERRNO != TC[i].error) - tst_brkm(TFAIL, cleanup, - "munlock() Failed with wrong " - "errno, expected errno=%s, " - "got errno=%d : %s", - TC[i].edesc, TEST_ERRNO, - strerror(TEST_ERRNO)); - else - tst_resm(TPASS, - "expected failure - errno " - "= %d : %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_brkm(TFAIL, cleanup, - "munlock() Failed, expected " - "return value=-1, got %ld", - TEST_RETURN); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); + TST_EXP_FAIL(munlock(addr, len), ENOMEM, "munlock(%p, %lu)", + addr, len); } -/* setup() - performs all ONE TIME setup for this test. */ - -void setup(void) +static void setup(void) { - - char *address; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TC[0].len = 8 * getpagesize(); - address = mmap(0, TC[0].len, PROT_READ | PROT_WRITE, - MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); - if (address == MAP_FAILED) - tst_brkm(TFAIL, cleanup, "mmap_failed"); - memset(address, 0x20, TC[0].len); - TEST(mlock(address, TC[0].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", address, - TC[0].len, TEST_RETURN); - } - TC[0].addr = address; + pg_size = getpagesize(); + len = 8 * pg_size; + addr = SAFE_MMAP(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + memset(addr, 0x20, len); + SAFE_MLOCK(addr, len); /* * unmap part of the area, to create the condition for ENOMEM */ - address += 2 * getpagesize(); - munmap(address, 4 * getpagesize()); - - TEST_PAUSE; - - return; -} - -#else - -int main(void) -{ - tst_resm(TINFO, "test is not available on uClinux"); - tst_exit(); + addr += 2 * pg_size; + SAFE_MUNMAP(addr, 4 * pg_size); } -#endif /* if !defined(UCLINUX) */ - -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - return; -} +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/munmap/munmap01.c b/testcases/kernel/syscalls/munmap/munmap01.c index 2a5cfc90d..7d10c0eac 100644 --- a/testcases/kernel/syscalls/munmap/munmap01.c +++ b/testcases/kernel/syscalls/munmap/munmap01.c @@ -193,7 +193,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* MAP_SHARED is not implemented on uClinux */ diff --git a/testcases/kernel/syscalls/munmap/munmap02.c b/testcases/kernel/syscalls/munmap/munmap02.c index b43250512..cd85d9436 100644 --- a/testcases/kernel/syscalls/munmap/munmap02.c +++ b/testcases/kernel/syscalls/munmap/munmap02.c @@ -197,7 +197,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* mmap() doesn't support MAP_SHARED on uClinux */ diff --git a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c index 9677b0671..6535fdf5c 100644 --- a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c +++ b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c @@ -72,7 +72,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); } diff --git a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c index 76be720ca..6171229f0 100644 --- a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c +++ b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c @@ -55,7 +55,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); f_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); d_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); diff --git a/testcases/kernel/syscalls/personality/personality01.c b/testcases/kernel/syscalls/personality/personality01.c index b646e2a9b..47fb66256 100644 --- a/testcases/kernel/syscalls/personality/personality01.c +++ b/testcases/kernel/syscalls/personality/personality01.c @@ -1,24 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) International Business Machines Corp., 2001 * 03/2001 - Written by Wayne Boyer * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* +/*\ + * [Description] + * * Tries to set different personalities. * * We set the personality in a child process since it's not guaranteed that we @@ -26,19 +17,17 @@ * bit archs. */ -#include "test.h" -#include <sys/personality.h> - -char *TCID = "personality01"; +#include "tst_test.h" +#include "lapi/personality.h" #define PAIR(id) {id, #id} struct personalities { - unsigned long int pers; + unsigned long pers; const char *name; }; -struct personalities pers[] = { +static struct personalities pers[] = { PAIR(PER_LINUX), PAIR(PER_LINUX_32BIT), PAIR(PER_SVR4), @@ -62,60 +51,24 @@ struct personalities pers[] = { PAIR(PER_HPUX), }; -int TST_TOTAL = ARRAY_SIZE(pers); - -static void do_child(unsigned int i) +static void run(unsigned int i) { - int ret; + pid_t pid; - ret = personality(pers[i].pers); - if (ret < 0) { - tst_resm(TFAIL | TERRNO, "personality(%s) failed", pers[i].name); - return; - } + pid = SAFE_FORK(); + if (!pid) { + SAFE_PERSONALITY(pers[i].pers); - ret = personality(0xffffffff); + TST_EXP_EXPR((unsigned long)SAFE_PERSONALITY(0xffffffff) == pers[i].pers, + "%s personality is set", + pers[i].name); - if ((unsigned long)ret != pers[i].pers) { - tst_resm(TFAIL, - "%s: wrong personality read back %d expected %lu", - pers[i].name, ret, pers[i].pers); return; } - - tst_resm(TPASS, "personality(%s)", pers[i].name); -} - -static void verify_personality(unsigned int i) -{ - pid_t pid; - - pid = tst_fork(); - switch (pid) { - case 0: - do_child(i); - tst_exit(); - break; - case -1: - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); - break; - default: - tst_record_childstatus(NULL, pid); - break; - } } -int main(int ac, char **av) -{ - int i, lc; - - tst_parse_opts(ac, av, NULL, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) { - verify_personality(i); - } - } - - tst_exit(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(pers), + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/personality/personality02.c b/testcases/kernel/syscalls/personality/personality02.c index eb18c9951..e080284f4 100644 --- a/testcases/kernel/syscalls/personality/personality02.c +++ b/testcases/kernel/syscalls/personality/personality02.c @@ -1,62 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * If personality with STICKY_TIMEOUTS is used select() timeout is not updated. +/*\ + * [Description] + * + * This test checks if select() timeout is not updated when personality with + * STICKY_TIMEOUTS is used. */ -#include "test.h" -#include <sys/personality.h> +#include "tst_test.h" +#include "lapi/personality.h" #include <sys/select.h> -char *TCID = "personality02"; -int TST_TOTAL = 1; - #define USEC 10 -static void verify_personality(void) +static void run(void) { - struct timeval tv = {.tv_sec = 0, .tv_usec = USEC}; - int ret; + struct timeval tv = { .tv_sec = 0, .tv_usec = USEC }; fd_set rfds; FD_ZERO(&rfds); FD_SET(1, &rfds); - personality(PER_LINUX | STICKY_TIMEOUTS); - ret = select(2, &rfds, NULL, NULL, &tv); - personality(PER_LINUX); - if (ret < 0) - tst_resm(TBROK | TERRNO, "select()"); + SAFE_PERSONALITY(PER_LINUX | STICKY_TIMEOUTS); - if (tv.tv_usec != USEC) - tst_resm(TFAIL, "Timeout was modified"); - else - tst_resm(TPASS, "Timeout wasn't modified"); -} - -int main(int ac, char **av) -{ - int lc; + TEST(select(2, &rfds, NULL, NULL, &tv)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select() error"); - tst_parse_opts(ac, av, NULL, NULL); + SAFE_PERSONALITY(PER_LINUX); - for (lc = 0; TEST_LOOPING(lc); lc++) - verify_personality(); - - tst_exit(); + TST_EXP_EQ_LI(tv.tv_usec, USEC); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/pipe/.gitignore b/testcases/kernel/syscalls/pipe/.gitignore index 23e7186a6..774d73205 100644 --- a/testcases/kernel/syscalls/pipe/.gitignore +++ b/testcases/kernel/syscalls/pipe/.gitignore @@ -11,3 +11,4 @@ /pipe11 /pipe12 /pipe13 +/pipe14 diff --git a/testcases/kernel/syscalls/pipe/pipe03.c b/testcases/kernel/syscalls/pipe/pipe03.c index 89c0911c1..d20867b2b 100644 --- a/testcases/kernel/syscalls/pipe/pipe03.c +++ b/testcases/kernel/syscalls/pipe/pipe03.c @@ -1,51 +1,42 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) 2003-2023 Linux Test Project */ -/* - * Make sure that writing to the read end of a pipe and reading from - * the write end of a pipe both fail. +/*\ + * [Description] + * + * Verify that, an attempt to write to the read end of a pipe fails with EBADF + * and an attempt to read from the write end of a pipe also fails with EBADF. */ -#include <unistd.h> -#include <errno.h> #include "tst_test.h" static int fd[2]; static void verify_pipe(void) { - char buf[2]; - - TEST(pipe(fd)); - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "pipe() failed unexpectedly"); - return; - } - - TEST(write(fd[0], "A", 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure writing " - "to read end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure writing " - "to read end of pipe"); - } - - TEST(read(fd[1], buf, 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure reading " - "from write end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure reading " - "from write end of pipe"); - } + char buf[] = "abcdef"; + + SAFE_PIPE(fd); + + TST_EXP_FAIL2(write(fd[0], "A", 1), EBADF); + TST_EXP_FAIL2(read(fd[1], buf, 1), EBADF); SAFE_CLOSE(fd[0]); SAFE_CLOSE(fd[1]); } +static void cleanup(void) +{ + if (fd[0] > 0) + SAFE_CLOSE(fd[0]); + if (fd[1] > 0) + SAFE_CLOSE(fd[1]); +} + static struct tst_test test = { .test_all = verify_pipe, + .cleanup = cleanup }; diff --git a/testcases/kernel/syscalls/pipe/pipe06.c b/testcases/kernel/syscalls/pipe/pipe06.c index d83765632..0c6bc03bd 100644 --- a/testcases/kernel/syscalls/pipe/pipe06.c +++ b/testcases/kernel/syscalls/pipe/pipe06.c @@ -1,119 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) Linux Test Project, 2002-2015 + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe06.c - * - * DESCRIPTION - * Check what happens when the system runs out of pipes. - * - * ALGORITHM - * Issue enough pipe calls to run the system out of pipes. - * Check that we get EMFILE. +/*\ + * [Description] * - * USAGE: <for command-line> - * pipe06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, pipe(2) syscall fails with errno EMFILE when + * limit on the number of open file descriptors has been reached. */ -#include <fcntl.h> -#include <errno.h> -#include "test.h" -char *TCID = "pipe06"; -int TST_TOTAL = 1; +#include "tst_test.h" +#include <stdlib.h> -int pipe_ret, pipes[2]; -void setup(void); -void cleanup(void); +static int fds[2]; +static int *opened_fds, num_opened_fds; -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; + int max_fds; - TEST(pipe(pipes)); + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + opened_fds = SAFE_MALLOC(max_fds * sizeof(int)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - } - - if (TEST_ERRNO != EMFILE) { - tst_resm(TFAIL | TTERRNO, "pipe failed unexpectedly"); - } else { - tst_resm(TPASS, "failed with EMFILE"); - } - - } - cleanup(); - tst_exit(); + do { + SAFE_PIPE(fds); + opened_fds[num_opened_fds++] = fds[0]; + opened_fds[num_opened_fds++] = fds[1]; + } while (fds[1] < max_fds - 2); + tst_res(TINFO, "Number of fds opened by pipe calls: %d", num_opened_fds); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - int i, numb_fds; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - numb_fds = getdtablesize(); - - for (i = 0; i < numb_fds; i++) { - pipe_ret = pipe(pipes); - if (pipe_ret < 0) { - if (errno != EMFILE) { - tst_brkm(TBROK | TTERRNO, cleanup, - "didn't get EMFILE"); - } - break; - } - } + TST_EXP_FAIL(pipe(fds), EMFILE); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) +static void cleanup(void) { + for (int i = 0; i < num_opened_fds; i++) + SAFE_CLOSE(opened_fds[i]); + + if (opened_fds) + free(opened_fds); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe07.c b/testcases/kernel/syscalls/pipe/pipe07.c index 55bb9f419..8098007c2 100644 --- a/testcases/kernel/syscalls/pipe/pipe07.c +++ b/testcases/kernel/syscalls/pipe/pipe07.c @@ -1,176 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 - * Ported by Paul Larson + * Ported by Paul Larson * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test the ability of pipe to open the maximum even number of file - * descriptors permitted (or (maxfds - 3)/2 pipes) +/*\ + * [Description] * - * ALGORITHM - * 1. record file descriptors open prior to test run - * 2. open pipes until EMFILE is returned - * 3. check to see that the number of pipes opened is (maxfds - 3) / 2 - * 4. close all fds in range 0, maximal fd that were not open prior to - * the test execution + * Verify that, pipe(2) syscall can open the maximum number of + * file descriptors permitted. */ -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <dirent.h> -#include "test.h" -#include "safe_macros.h" - -char *TCID = "pipe07"; -int TST_TOTAL = 1; - -/* used to record file descriptors open at the test start */ -static int rec_fds[128]; -static int rec_fds_max; -static void record_open_fds(void); -static void close_test_fds(int max_fd); +#include "tst_test.h" +#include <stdlib.h> -static void setup(void); -static void cleanup(void); +static int *opened_fds, *pipe_fds; +static int num_pipe_fds, exp_num_pipes; -int main(int ac, char **av) +static int record_open_fds(void) { - int lc; - int min, ret; - int npipes; - int pipes[2], max_fd = 0; - - tst_parse_opts(ac, av, NULL, NULL); + DIR *dir; + struct dirent *ent; + int fd; + int num_opened_fds = 0; + int arr_size = 0; - setup(); + dir = SAFE_OPENDIR("/proc/self/fd"); - min = getdtablesize() - rec_fds_max; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + while ((ent = SAFE_READDIR(dir))) { + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) + continue; + fd = atoi(ent->d_name); - for (npipes = 0;; npipes++) { - ret = pipe(pipes); - if (ret < 0) { - if (errno != EMFILE) { - tst_brkm(TFAIL, cleanup, - "got unexpected error - %d", - errno); - } - break; - } + if (fd == dirfd(dir)) + continue; - max_fd = MAX(pipes[0], max_fd); - max_fd = MAX(pipes[1], max_fd); + if (num_opened_fds >= arr_size) { + arr_size = MAX(1, arr_size * 2); + opened_fds = SAFE_REALLOC(opened_fds, arr_size * sizeof(int)); } - - if (npipes == (min / 2)) - tst_resm(TPASS, "Opened %d pipes", npipes); - else - tst_resm(TFAIL, "Unable to open maxfds/2 pipes"); - - close_test_fds(max_fd); - max_fd = 0; + opened_fds[num_opened_fds++] = fd; } - cleanup(); - tst_exit(); + SAFE_CLOSEDIR(dir); + + return num_opened_fds; } static void setup(void) { - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + int max_fds; + + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + pipe_fds = SAFE_MALLOC(max_fds * sizeof(int)); - record_open_fds(); + exp_num_pipes = (max_fds - record_open_fds()) / 2 * 2; + tst_res(TINFO, "expected max fds to be opened by pipe(): %d", exp_num_pipes); } -static void record_open_fds(void) +static void run(void) { - DIR *dir = opendir("/proc/self/fd"); - int dir_fd, fd; - struct dirent *file; - - if (dir == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "opendir()"); - - dir_fd = dirfd(dir); + int fds[2]; - if (dir_fd == -1) - tst_brkm(TBROK | TERRNO, cleanup, "dirfd()"); - - errno = 0; - - while ((file = readdir(dir))) { - if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) - continue; - - fd = atoi(file->d_name); - - if (fd == dir_fd) - continue; - - if (rec_fds_max >= (int)ARRAY_SIZE(rec_fds)) { - tst_brkm(TBROK, cleanup, - "Too much file descriptors open"); + do { + TEST(pipe(fds)); + if (!TST_RET) { + pipe_fds[num_pipe_fds++] = fds[0]; + pipe_fds[num_pipe_fds++] = fds[1]; } + } while (!TST_RET); - rec_fds[rec_fds_max++] = fd; - } - - if (errno) - tst_brkm(TBROK | TERRNO, cleanup, "readdir()"); + TST_EXP_EQ_LI(errno, EMFILE); + TST_EXP_EQ_LI(exp_num_pipes, num_pipe_fds); - closedir(dir); + for (int i = 0; i < num_pipe_fds; i++) + SAFE_CLOSE(pipe_fds[i]); - tst_resm(TINFO, "Found %u files open", rec_fds_max); + num_pipe_fds = 0; } -static int not_recorded(int fd) +static void cleanup(void) { - int i; + for (int i = 0; i < num_pipe_fds; i++) + if (pipe_fds[i] > 0) + SAFE_CLOSE(pipe_fds[i]); - for (i = 0; i < rec_fds_max; i++) - if (fd == rec_fds[i]) - return 0; + if (pipe_fds) + free(pipe_fds); - return 1; + if (opened_fds) + free(opened_fds); } -static void close_test_fds(int max_fd) -{ - int i; - - for (i = 0; i <= max_fd; i++) { - if (not_recorded(i)) { - if (close(i)) { - if (errno == EBADF) - continue; - tst_resm(TWARN | TERRNO, "close(%i)", i); - } - } - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe08.c b/testcases/kernel/syscalls/pipe/pipe08.c index 173ec788a..28088cf61 100644 --- a/testcases/kernel/syscalls/pipe/pipe08.c +++ b/testcases/kernel/syscalls/pipe/pipe08.c @@ -1,137 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe08.c - * - * DESCRIPTION - * Check that a SIGPIPE signal is generated when a write is - * attempted on an empty pipe. - * - * ALGORITHM - * 1. Write to a pipe after closing the read side. - * 2. Check for the signal SIGPIPE to be received. +/*\ + * [Description] * - * USAGE: <for command-line> - * pipe08 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * USAGE - * pipe08 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, on any attempt to write to a pipe which is closed for + * reading will generate a SIGPIPE signal and write will fail with + * EPIPE errno. */ -#include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include "test.h" -char *TCID = "pipe08"; -int TST_TOTAL = 1; +#include "tst_test.h" -void setup(void); -void cleanup(void); -void sighandler(int); +static int pipefd[2]; +static volatile int sigpipe_cnt; -int main(int ac, char **av) +static void sighandler(int sig) { - int lc; - - int pipefd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ]; - int written, length; - int close_stat; /* exit status of close(read fd) */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; - - TEST(pipe(pipefd)); + if (sig == SIGPIPE) + sigpipe_cnt++; +} - if (TEST_RETURN != 0) { - tst_resm(TFAIL, "call failed unexpectedly"); - continue; - } +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; - if ((close_stat = close(pipefd[0])) == -1) { - tst_brkm(TBROK, cleanup, "close of read side failed"); - } + sigpipe_cnt = 0; - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz\0"); - length = strlen(wrbuf); + SAFE_PIPE(pipefd); + SAFE_CLOSE(pipefd[0]); - /* - * the SIGPIPE signal will be caught here or else - * the program will dump core when the signal is - * sent - */ - written = write(pipefd[1], wrbuf, length); - if (written > 0) - tst_brkm(TBROK, cleanup, "write succeeded unexpectedly"); - } - cleanup(); - tst_exit(); + TST_EXP_FAIL2_SILENT(write(pipefd[1], wrbuf, sizeof(wrbuf)), EPIPE); + TST_EXP_EQ_LI(sigpipe_cnt, 1); + SAFE_CLOSE(pipefd[1]); } -/* - * sighandler - catch signals and look for SIGPIPE - */ -void sighandler(int sig) +static void setup(void) { - if (sig != SIGPIPE) - tst_resm(TFAIL, "expected SIGPIPE, got %d", sig); - else - tst_resm(TPASS, "got expected SIGPIPE signal"); + SAFE_SIGNAL(SIGPIPE, sighandler); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { - - tst_sig(NOFORK, sighandler, cleanup); - - TEST_PAUSE; + if (pipefd[0] > 0) + SAFE_CLOSE(pipefd[0]); + if (pipefd[1] > 0) + SAFE_CLOSE(pipefd[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe10.c b/testcases/kernel/syscalls/pipe/pipe10.c index 48f722e3e..018e653da 100644 --- a/testcases/kernel/syscalls/pipe/pipe10.c +++ b/testcases/kernel/syscalls/pipe/pipe10.c @@ -1,164 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * NAME - * pipe10.c - * - * DESCRIPTION - * Check that parent can open a pipe and have a child read from it - * - * ALGORITHM - * Parent opens pipe, child reads. Passes if child can read all the - * characters written by the parent. - * - * USAGE: <for command-line> - * pipe10 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None + * Verify that, when a parent process opens a pipe, a child process can + * read from it. */ -#include <errno.h> -#include <unistd.h> -#include <sys/wait.h> -#include <string.h> -#include "test.h" -char *TCID = "pipe10"; -int TST_TOTAL = 1; +#include <stdio.h> +#include "tst_test.h" -void setup(void); -void cleanup(void); +static int fds[2]; -ssize_t do_read(int fd, void *buf, size_t count) +static void run(void) { - ssize_t n; - - do { - n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - -int main(int ac, char **av) -{ - int lc; - - int fd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ], rebuf[BUFSIZ]; - int red, written; /* no of chars read and */ - /* written to pipe */ - int length, greater, forkstat; - int retval = 0, status, e_code; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { + int wr_cnt, rd_cnt; + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[BUFSIZ]; - /* reset tst_count in case we are looping */ - tst_count = 0; + SAFE_PIPE(fds); + wr_cnt = SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); - TEST(pipe(fd)); - - if (TEST_RETURN == -1) { - retval = 1; - tst_resm(TFAIL, "pipe creation failed"); - continue; - } - - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz"); - length = strlen(wrbuf) + 1; - - written = write(fd[1], wrbuf, length); - - /* did write write at least some chars */ - if ((written < 0) || (written > length)) { - tst_brkm(TBROK, cleanup, "write to pipe failed"); - } - - forkstat = FORK_OR_VFORK(); - - if (forkstat == -1) { - tst_brkm(TBROK, cleanup, "fork() failed"); - } - - if (forkstat == 0) { /* child */ - red = do_read(fd[0], rebuf, written); - - /* did read , get at least some chars */ - if ((red < 0) || (red > written)) { - tst_brkm(TBROK, cleanup, "read pipe failed"); - } - - greater = strcmp(rebuf, wrbuf); - - /* are the strings written and read equal */ - if (greater == 0) { - tst_resm(TPASS, "functionality is correct"); - } else { - retval = 1; - tst_resm(TFAIL, "read & write strings do " - "not match"); - } - exit(retval); - } else { /* parent */ - /* wait for the child to finish */ - wait(&status); - /* make sure the child returned a good exit status */ - e_code = status >> 8; - if (e_code != 0) { - tst_resm(TFAIL, "Failures reported above"); - } - } + if (!SAFE_FORK()) { + rd_cnt = SAFE_READ(1, fds[0], rdbuf, wr_cnt); + TST_EXP_EQ_LU(wr_cnt, rd_cnt); } - cleanup(); - tst_exit(); + tst_reap_children(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe14.c b/testcases/kernel/syscalls/pipe/pipe14.c new file mode 100644 index 000000000..2d2969d82 --- /dev/null +++ b/testcases/kernel/syscalls/pipe/pipe14.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + */ + +/*\ + * [Description] + * + * Verify that, if the write end of a pipe is closed, then a process reading + * from the pipe will see end-of-file (i.e., read() returns 0) once it has + * read all remaining data in the pipe. + */ + +#include "tst_test.h" + +static int fds[2]; + +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[30]; + + memset(rdbuf, 0, sizeof(rdbuf)); + SAFE_PIPE(fds); + + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); + SAFE_CLOSE(fds[1]); + + SAFE_READ(0, fds[0], rdbuf, sizeof(wrbuf)); + + TST_EXP_VAL(SAFE_READ(0, fds[0], rdbuf, 1), 0); + SAFE_CLOSE(fds[0]); +} + +static void cleanup(void) +{ + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/prctl/prctl04.c b/testcases/kernel/syscalls/prctl/prctl04.c index f6e1f0fea..8b135d611 100644 --- a/testcases/kernel/syscalls/prctl/prctl04.c +++ b/testcases/kernel/syscalls/prctl/prctl04.c @@ -45,6 +45,7 @@ static const struct sock_filter strict_filter[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_waitid, 7, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_rt_sigprocmask, 6, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), diff --git a/testcases/kernel/syscalls/preadv2/preadv203.c b/testcases/kernel/syscalls/preadv2/preadv203.c index 25c6e1c2e..c87deb674 100644 --- a/testcases/kernel/syscalls/preadv2/preadv203.c +++ b/testcases/kernel/syscalls/preadv2/preadv203.c @@ -159,7 +159,7 @@ static void *writer_thread(void *unused) while (!stop) { int fd = fds[random() % FILES]; - for (j = 0; j < CHUNKS; j++) { + for (j = 0; j < CHUNKS && !stop; j++) { memset(buf, '0' + j, sizeof(buf)); off_t off = CHUNK_SZ * j; diff --git a/testcases/kernel/syscalls/process_madvise/.gitignore b/testcases/kernel/syscalls/process_madvise/.gitignore new file mode 100644 index 000000000..93d2640f7 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/.gitignore @@ -0,0 +1 @@ +/process_madvise01 diff --git a/testcases/kernel/syscalls/paging/Makefile b/testcases/kernel/syscalls/process_madvise/Makefile index 044619fb8..ad5b66061 100644 --- a/testcases/kernel/syscalls/paging/Makefile +++ b/testcases/kernel/syscalls/process_madvise/Makefile @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) International Business Machines Corp., 2001 +# Copyright (C) 2023 Linux Test Project, Inc. top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise.h b/testcases/kernel/syscalls/process_madvise/process_madvise.h new file mode 100644 index 000000000..5b227ada0 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +#ifndef PROCESS_MADVISE_H__ +#define PROCESS_MADVISE_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst_safe_stdio.h" + +struct addr_mapping { + int size; + int rss; + int pss; + int shared_clean; + int shared_dirty; + int private_clean; + int private_dirty; + int referenced; + int anonymous; + int anon_huge_pages; + int shmem_huge_pages; + int shmem_pmd_mapped; + int swap; + int kernel_page_size; + int mmu_page_size; + int locked; + int protection_key; +}; + +static inline void read_address_mapping(unsigned long address, struct addr_mapping *mapping) +{ + FILE *f; + int found = 0; + char label[BUFSIZ]; + char line[BUFSIZ]; + char smaps[BUFSIZ]; + char ptr_str[BUFSIZ]; + int value; + + snprintf(smaps, BUFSIZ, "/proc/%i/smaps", getpid()); + snprintf(ptr_str, BUFSIZ, "%lx", address); + + f = SAFE_FOPEN(smaps, "r"); + + while (fgets(line, BUFSIZ, f) != NULL) { + if (strncmp(ptr_str, line, strlen(ptr_str)) == 0) + found = 1; + + if (!found) + continue; + + if (found && strncmp(line, "VmFlags", 7) == 0) + break; + + if (sscanf(line, "%31[^:]: %d", label, &value) > 0) { + if (strcmp(label, "Size") == 0) + mapping->size = value; + else if (strcmp(label, "Rss") == 0) + mapping->rss = value; + else if (strcmp(label, "Pss") == 0) + mapping->pss = value; + else if (strcmp(label, "Shared_Clean") == 0) + mapping->shared_clean = value; + else if (strcmp(label, "Shared_Dirty") == 0) + mapping->shared_dirty = value; + else if (strcmp(label, "Private_Clean") == 0) + mapping->private_clean = value; + else if (strcmp(label, "Private_Dirty") == 0) + mapping->private_dirty = value; + else if (strcmp(label, "Referenced") == 0) + mapping->referenced = value; + else if (strcmp(label, "Anonymous") == 0) + mapping->anonymous = value; + else if (strcmp(label, "AnonHugePages") == 0) + mapping->anon_huge_pages = value; + else if (strcmp(label, "ShmemHugePages") == 0) + mapping->shmem_huge_pages = value; + else if (strcmp(label, "ShmemPmdMapped") == 0) + mapping->shmem_pmd_mapped = value; + else if (strcmp(label, "Swap") == 0) + mapping->swap = value; + else if (strcmp(label, "KernelPageSize") == 0) + mapping->kernel_page_size = value; + else if (strcmp(label, "MMUPageSize") == 0) + mapping->mmu_page_size = value; + else if (strcmp(label, "Locked") == 0) + mapping->locked = value; + else if (strcmp(label, "ProtectionKey") == 0) + mapping->protection_key = value; + } + } + + SAFE_FCLOSE(f); +} + +#endif diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise01.c b/testcases/kernel/syscalls/process_madvise/process_madvise01.c new file mode 100644 index 000000000..0fd3c1ef4 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise01.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Allocate anonymous memory pages inside child and reclaim it with + * MADV_PAGEOUT. Then check if memory pages have been swapped out by looking + * at smaps information. + * + * The advice might be ignored for some pages in the range when it is + * not applicable, so test passes if swap memory increases after + * reclaiming memory with MADV_PAGEOUT. + */ + +#define _GNU_SOURCE + +#include <sys/mman.h> +#include "tst_test.h" +#include "lapi/mmap.h" +#include "lapi/syscalls.h" +#include "process_madvise.h" + +#define MEM_CHILD (1 * TST_MB) + +static void **data_ptr; + +static void child_alloc(void) +{ + char data[MEM_CHILD]; + struct addr_mapping map_before; + struct addr_mapping map_after; + + memset(data, 'a', MEM_CHILD); + + tst_res(TINFO, "Allocate memory: %d bytes", MEM_CHILD); + + *data_ptr = SAFE_MMAP(NULL, MEM_CHILD, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(*data_ptr, 'a', MEM_CHILD); + + memset(&map_before, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_before); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + memset(&map_after, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_after); + + if (memcmp(*data_ptr, data, MEM_CHILD) != 0) { + tst_res(TFAIL, "Dirty memory after reclaiming it"); + return; + } + + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + *data_ptr = NULL; + + TST_EXP_EXPR(map_before.swap < map_after.swap, + "Most of the memory has been swapped out: %dkB out of %dkB", + map_after.swap - map_before.swap, + MEM_CHILD / TST_KB); +} + +static void setup(void) +{ + data_ptr = SAFE_MMAP(NULL, sizeof(void *), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (*data_ptr) + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(void *)); +} + +static void run(void) +{ + int ret; + int pidfd; + pid_t pid_alloc; + struct iovec vec; + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Reclaim memory using MADV_PAGEOUT"); + + pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0); + + vec.iov_base = *data_ptr; + vec.iov_len = MEM_CHILD; + + ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL, + MADV_PAGEOUT, 0UL); + + if (ret == -1) + tst_brk(TBROK | TERRNO, "process_madvise failed"); + + if (ret != MEM_CHILD) + tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .min_kver = "5.10", + .needs_checkpoints = 1, + .needs_root = 1, + .min_swap_avail = MEM_CHILD / TST_MB, + .needs_kconfigs = (const char *[]) { + "CONFIG_SWAP=y", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/quotactl/quotactl08.c b/testcases/kernel/syscalls/quotactl/quotactl08.c index da1d62a32..0fabb51a5 100644 --- a/testcases/kernel/syscalls/quotactl/quotactl08.c +++ b/testcases/kernel/syscalls/quotactl/quotactl08.c @@ -28,6 +28,7 @@ * - turn off quota with Q_QUOTAOFF flag for group * * It is similar to quotactl01.c, only two difference + * * - use new quotactl_fd syscalls if supports * - quota file hidden in filesystem * diff --git a/testcases/kernel/syscalls/readahead/readahead02.c b/testcases/kernel/syscalls/readahead/readahead02.c index 7acf4bb18..dc03c5931 100644 --- a/testcases/kernel/syscalls/readahead/readahead02.c +++ b/testcases/kernel/syscalls/readahead/readahead02.c @@ -318,6 +318,19 @@ static void test_readahead(unsigned int n) tst_res(TCONF, "Page cache on your system is too small " "to hold whole testfile."); } + + /* + * The time consuming of readahead quite depending on the platform IO + * speed, sometime test timeout when the default max_runtime is used up. + * + * readahead02.c:221: TINFO: Test #2: POSIX_FADV_WILLNEED on file + * readahead02.c:285: TINFO: read_testfile(0) took: 26317623 usec + * readahead02.c:286: TINFO: read_testfile(1) took: 26101484 usec + * + * Here raise the maximum runtime dynamically. + */ + if ((tc+1)->readahead) + tst_set_max_runtime(test.max_runtime + (usec + usec_ra) / 1000000); } @@ -352,7 +365,7 @@ static void setup_readahead_length(void) /* raise bdi limit as much as kernel allows */ ra_new_limit = testfile_size / 1024; while (ra_new_limit > pagesize / 1024) { - FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); + SAFE_FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); SAFE_FILE_SCANF(sys_bdi_ra_path, "%d", &ra_limit); if (ra_limit == ra_new_limit) { diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat01.c b/testcases/kernel/syscalls/readlinkat/readlinkat01.c index 985890ebe..b1214c3ae 100644 --- a/testcases/kernel/syscalls/readlinkat/readlinkat01.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat01.c @@ -1,143 +1,103 @@ -/****************************************************************************** - * +// SPDX-License-Identifier: GPL-2.0-or-later +/* * Copyright (c) International Business Machines Corp., 2006 - * Author: Yi Yang <yyangcdl@cn.ibm.com> * Copyright (c) Cyril Hrubis 2014 <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * This test case will verify basic function of readlinkat - * added by kernel 2.6.16 or up. + * Check the basic functionality of the readlinkat() system call. * - *****************************************************************************/ + * - readlinkat() passes if dirfd is directory file descriptor + * and the pathname is relative. + * - readlinkat() passes if the pathname is abspath, then dirfd + * is ignored. + * - readlinkat() passes if dirfd is the special value AT_FDCWD + * and the pathname is relative. + * - readlinkat() passes if pathname is an empty string, in which + * case the call operates on the symbolic link referred to by dirfd. + */ -#define _GNU_SOURCE - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <fcntl.h> #include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" - -static void setup(void); -static void cleanup(void); +#include <stdio.h> +#include "tst_test.h" +#include "lapi/fcntl.h" -char *TCID = "readlinkat01"; +#define TEST_FILE "readlink_file" +#define TEST_SYMLINK "readlink_symlink" -static int dir_fd, fd; -static int fd_invalid = 100; +static int file_fd, dir_fd, dir_fd2; static int fd_atcwd = AT_FDCWD; - -#define TEST_SYMLINK "readlink_symlink" -#define TEST_FILE "readlink_file" - -static char abspath[1024]; - -static struct test_case { - int *dir_fd; - const char *path; - const char *exp_buf; - int exp_ret; - int exp_errno; -} test_cases[] = { - {&dir_fd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&dir_fd, abspath, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&fd, TEST_SYMLINK, NULL, -1, ENOTDIR}, - {&fd_invalid, TEST_SYMLINK, NULL, -1, EBADF}, - {&fd_atcwd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, +static const char *abspath; +static const char *testsymlink; +static const char *emptypath; + +static struct tcase { + int *fd; + const char **path; +} tcases[] = { + {&dir_fd, &testsymlink}, + {&dir_fd, &abspath}, + {&file_fd, &abspath}, + {&fd_atcwd, &abspath}, + {&fd_atcwd, &testsymlink}, + {&dir_fd2, &emptypath}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -static void verify_readlinkat(struct test_case *test) +static void verify_readlinkat(unsigned int i) { char buf[1024]; + struct tcase *tc = &tcases[i]; memset(buf, 0, sizeof(buf)); - TEST(readlinkat(*test->dir_fd, test->path, buf, sizeof(buf))); - - if (TEST_RETURN != test->exp_ret) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (TEST_ERRNO != test->exp_errno) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (test->exp_ret > 0 && strcmp(test->exp_buf, buf)) { - tst_resm(TFAIL, "Unexpected buffer have '%s', expected '%s'", - buf, test->exp_buf); - return; - } - - tst_resm(TPASS | TTERRNO, "readlinkat() returned %ld", TEST_RETURN); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + TST_EXP_POSITIVE(readlinkat(*tc->fd, *tc->path, buf, sizeof(buf)), + "readlinkat(%d, %s, %s, %ld)", + *tc->fd, *tc->path, buf, sizeof(buf)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) - verify_readlinkat(&test_cases[i]); - } - - cleanup(); - tst_exit(); + if (strcmp(buf, TEST_FILE) == 0) + tst_res(TPASS, "The filename in buffer is correct"); + else + tst_res(TFAIL, "Wrong filename in buffer '%s'", buf); } static void setup(void) { - tst_tmpdir(); char *tmpdir = tst_get_tmpdir(); - snprintf(abspath, sizeof(abspath), "%s/" TEST_SYMLINK, tmpdir); + abspath = tst_aprintf("%s/" TEST_SYMLINK, tmpdir); free(tmpdir); - fd = SAFE_OPEN(cleanup, TEST_FILE, O_CREAT, 0600); - SAFE_SYMLINK(cleanup, TEST_FILE, TEST_SYMLINK); - dir_fd = SAFE_OPEN(cleanup, ".", O_DIRECTORY); - - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_CREAT, 0600); + SAFE_SYMLINK(TEST_FILE, TEST_SYMLINK); + dir_fd = SAFE_OPEN(".", O_DIRECTORY); + dir_fd2 = SAFE_OPEN(TEST_SYMLINK, O_PATH | O_NOFOLLOW); } static void cleanup(void) { - if (fd > 0 && close(fd)) - tst_resm(TWARN | TERRNO, "Failed to close fd"); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - if (dir_fd > 0 && close(dir_fd)) - tst_resm(TWARN | TERRNO, "Failed to close dir_fd"); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (dir_fd2 > -1) + SAFE_CLOSE(dir_fd2); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testsymlink, .str = TEST_SYMLINK}, + {&emptypath, .str = ""}, + {}, + }, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat02.c b/testcases/kernel/syscalls/readlinkat/readlinkat02.c index d30c1917a..64afb898f 100644 --- a/testcases/kernel/syscalls/readlinkat/readlinkat02.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat02.c @@ -1,122 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * - readlinkat() fails with EINVAL if the bufsiz is 0. * - * This program 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 Library General Public License for more details. + * - readlinkat() fails with EINVAL if the named file is not a symbolic link. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * - readlinkat() fails with ENOTDIR if the component of the path prefix is + * not a directory. * - */ -/* - * Test Description: - * Verify that, - * 1. bufsiz is 0, EINVAL should be returned. - * 2. The named file is not a symbolic link, EINVAL should be returned. - * 3. The component of the path prefix is not a directory, ENOTDIR should be - * returned. - * 4. pathname is relative and dirfd is a file descriptor referring to a file - * other than a directory, ENOTDIR should be returned. + * - readlinkat() fails with ENOTDIR if the pathname is relative and + * dirfd is a file descriptor referring to a file other than a directory. + * + * - readlinkat() fails with EBADF if the file descriptor is invalid. + * + * - readlinkat() fails with ENOENT when the pathname does not exists. */ -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" -#include "lapi/syscalls.h" +#include "tst_test.h" #define TEST_FILE "test_file" #define SYMLINK_FILE "symlink_file" #define BUFF_SIZE 256 static int file_fd, dir_fd; +static int fd_invalid = -1; -static struct test_case_t { - int *dirfd; +static struct tcase { + int *fd; const char *pathname; size_t bufsiz; int exp_errno; -} test_cases[] = { +} tcases[] = { {&dir_fd, SYMLINK_FILE, 0, EINVAL}, {&dir_fd, TEST_FILE, BUFF_SIZE, EINVAL}, {&file_fd, SYMLINK_FILE, BUFF_SIZE, ENOTDIR}, {&dir_fd, "test_file/test_file", BUFF_SIZE, ENOTDIR}, + {&fd_invalid, SYMLINK_FILE, BUFF_SIZE, EBADF}, + {&dir_fd, "does_not_exists", BUFF_SIZE, ENOENT}, }; -char *TCID = "readlinkat02"; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void cleanup(void); -static void readlinkat_verify(const struct test_case_t *); - -int main(int argc, char **argv) +static void verify_readlinkat(unsigned int i) { - int i, lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + char buf[BUFF_SIZE]; + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - readlinkat_verify(&test_cases[i]); - } + memset(buf, 0, sizeof(buf)); - cleanup(); - tst_exit(); + TST_EXP_FAIL(readlinkat(*tc->fd, tc->pathname, buf, tc->bufsiz), + tc->exp_errno, "readlinkat(%d, %s, NULL, %ld)", + *tc->fd, tc->pathname, tc->bufsiz); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + dir_fd = SAFE_OPEN(".", O_RDONLY); - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0644); - tst_tmpdir(); - - dir_fd = SAFE_OPEN(cleanup, "./", O_RDONLY); - - file_fd = SAFE_OPEN(cleanup, TEST_FILE, O_RDWR | O_CREAT, 0644); - - SAFE_SYMLINK(cleanup, TEST_FILE, SYMLINK_FILE); -} - -static void readlinkat_verify(const struct test_case_t *test) -{ - char buf[BUFF_SIZE]; - TEST(readlinkat(*test->dirfd, test->pathname, buf, test->bufsiz)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "readlinkat succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "readlinkat failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "readlinkat failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } + SAFE_SYMLINK(TEST_FILE, SYMLINK_FILE); } static void cleanup(void) { - close(dir_fd); - close(file_fd); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - tst_rmdir(); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/recvmsg/recvmsg01.c b/testcases/kernel/syscalls/recvmsg/recvmsg01.c index 3ce7ab027..80c1b3aa9 100644 --- a/testcases/kernel/syscalls/recvmsg/recvmsg01.c +++ b/testcases/kernel/syscalls/recvmsg/recvmsg01.c @@ -1,364 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2001 Wayne Boyer International Business Machines + * Copyright (c) Linux Test Project, 2002-2022 + * Copyright (c) 2023 Wei Gao <wegao@suse.com> */ -/* - * Test Name: recvmsg01 - * - * Test Description: - * Verify that recvmsg() returns the proper errno for various failure cases - * - * Usage: <for command-line> - * recvmsg01 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * None. +/*\ + * [Description] * + * Verify that recvmsg() returns the proper errno for various failure cases. */ #include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> - +#include <stdlib.h> #include <sys/wait.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/signal.h> -#include <sys/uio.h> -#include <sys/un.h> -#include <sys/file.h> - -#include <netinet/in.h> - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "recvmsg01"; -int testno; - -char buf[1024], cbuf[1024]; -int s; /* socket descriptor */ -int passed_fd = -1; /* rights-passing test descriptor */ -struct sockaddr_in sin1, from; -struct sockaddr_un sun1; -struct msghdr msgdat; -struct cmsghdr *control = 0; -int controllen = 0; -struct iovec iov[1]; +#include "tst_test.h" + +#define MSG "from recvmsg01 server" +#define BUF_SIZE 1024 +#define CONTROL_LEN (128 * 1024) + +static char recv_buf[BUF_SIZE], cbuf[BUF_SIZE]; +static int sock; +static struct sockaddr_in sin1, from; +static struct sockaddr_un sun1; +static struct msghdr msgdat; +static struct cmsghdr *control; +static int controllen; +static struct iovec iov[1]; static int sfd; /* shared between do_child and start_server */ static int ufd; /* shared between do_child and start_server */ - -void setup(void); -void setup0(void); -void setup1(void); -void setup2(void); -void setup3(void); -void setup4(void); -void cleanup(void); -void cleanup0(void); -void cleanup1(void); -void cleanup2(void); -void do_child(void); - -void sender(int); -pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); - -struct test_case_t { /* test case structure */ - int domain; /* PF_INET, PF_UNIX, ... */ - int type; /* SOCK_STREAM, SOCK_DGRAM ... */ - int proto; /* protocol number (usually 0 = default) */ +static pid_t pid; +static char tmpsunpath[BUF_SIZE]; + +static void setup_all(void); +static void setup_invalid_sock(int); +static void setup_valid_sock(int); +static void setup_valid_msg_control(int); +static void setup_large_msg_control(int); +static void cleanup_all(void); +static void cleanup_invalid_sock(int); +static void cleanup_close_sock(int); +static void cleanup_reset_all(int); +static void do_child(void); +static pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); + +static struct tcase { + int domain; + int type; + int protocol; struct iovec *iov; int iovcnt; - void *buf; /* recv data buffer */ - int buflen; /* recv buffer length */ + void *recv_buf; + int buflen; struct msghdr *msg; - unsigned flags; - struct sockaddr *from; /* from address */ - int fromlen; /* from address value/result buffer length */ - int retval; /* syscall return value */ - int experrno; /* expected errno */ - void (*setup) (void); - void (*cleanup) (void); + unsigned int flags; + struct sockaddr *from; + int fromlen; + int exp_errno; + void (*setup)(int n); + void (*cleanup)(int n); char *desc; -} tdat[] = { -/* 1 */ - { - PF_INET, SOCK_STREAM, 0, iov, 1, buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, EBADF, setup0, cleanup0, "bad file descriptor"} - , -/* 2 */ +} tcases[] = { { - 0, 0, 0, iov, 1, (void *)buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, ENOTSOCK, setup0, cleanup0, "invalid socket"} - , -/* 3 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EBADF, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "bad file descriptor", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)-1, sizeof(from), 0, - ENOTSOCK, setup1, cleanup1, "invalid socket buffer"} - , -/* 4 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = ENOTSOCK, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "invalid socket", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, -1, (struct sockaddr *)&from, -1, -1, - EINVAL, setup1, cleanup1, "invalid socket length"}, -/* 5 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = -1, + .from = (struct sockaddr *)&from, + .fromlen = -1, + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid socket length", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)-1, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid recv buffer"} - , -/* 6 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)-1, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid recv buffer", + }, { - PF_INET, SOCK_STREAM, 0, 0, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid iovec buffer"} - , -/* 7 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec buffer", + }, { - PF_INET, SOCK_STREAM, 0, iov, -1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EMSGSIZE, setup1, cleanup1, "invalid iovec count"} - , -/* 8 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = -1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EMSGSIZE, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec count", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup2, cleanup2, "rights reception"} - , -/* 9 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_valid_msg_control, + .cleanup = cleanup_reset_all, + .desc = "permission reception", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_OOB, (struct sockaddr *)&from, - sizeof(from), -1, EINVAL, setup1, cleanup1, - "invalid MSG_OOB flag set"} - , -/* 10 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_OOB, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_OOB flag set", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_ERRQUEUE, (struct sockaddr *)&from, - sizeof(from), -1, EAGAIN, setup1, cleanup1, - "invalid MSG_ERRQUEUE flag set"} - , -/* 11 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_ERRQUEUE, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EAGAIN, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_ERRQUEUE flag set", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, EINVAL, setup3, cleanup2, "invalid cmsg length"} - , -/* 12 */ - { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup4, cleanup2, "large cmesg length"} -,}; - -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); - -#ifdef UCLINUX -static char *argv0; -#endif - -int main(int argc, char *argv[]) + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_large_msg_control, + .cleanup = cleanup_reset_all, + .desc = "large cmesg length", + }, + +}; + +static void run(unsigned int n) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); -#ifdef UCLINUX - argv0 = argv[0]; - maybe_run_child(&do_child, "dd", &sfd, &ufd); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - if ((tst_kvercmp(3, 17, 0) < 0) - && (tdat[testno].flags & MSG_ERRQUEUE) - && (tdat[testno].type & SOCK_STREAM)) { - tst_resm(TCONF, "skip MSG_ERRQUEUE test, " - "it's supported from 3.17"); - continue; - } + struct tcase *tc = &tcases[n]; + int ret = tc->exp_errno ? -1 : 0; - tdat[testno].setup(); - - /* setup common to all tests */ - iov[0].iov_base = tdat[testno].buf; - iov[0].iov_len = tdat[testno].buflen; - msgdat.msg_name = tdat[testno].from; - msgdat.msg_namelen = tdat[testno].fromlen; - msgdat.msg_iov = tdat[testno].iov; - msgdat.msg_iovlen = tdat[testno].iovcnt; - msgdat.msg_control = control; - msgdat.msg_controllen = controllen; - msgdat.msg_flags = 0; - - TEST(recvmsg(s, tdat[testno].msg, tdat[testno].flags)); - if (TEST_RETURN >= 0) - TEST_RETURN = 0; /* all nonzero equal here */ - if (TEST_RETURN != tdat[testno].retval || - (TEST_RETURN < 0 && - TEST_ERRNO != tdat[testno].experrno)) { - tst_resm(TFAIL, "%s ; returned" - " %ld (expected %d), errno %d (expected" - " %d)", tdat[testno].desc, - TEST_RETURN, tdat[testno].retval, - TEST_ERRNO, tdat[testno].experrno); - } else { - tst_resm(TPASS, "%s successful", - tdat[testno].desc); - } - tdat[testno].cleanup(); - } + if ((tst_kvercmp(3, 17, 0) < 0) + && (tc->flags & MSG_ERRQUEUE) + && (tc->type & SOCK_STREAM)) { + tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17"); + return; + } + + setup_all(); + tc->setup(n); + + iov[0].iov_base = tc->recv_buf; + iov[0].iov_len = tc->buflen; + msgdat.msg_name = tc->from; + msgdat.msg_namelen = tc->fromlen; + msgdat.msg_iov = tc->iov; + msgdat.msg_iovlen = tc->iovcnt; + msgdat.msg_control = control; + msgdat.msg_controllen = controllen; + msgdat.msg_flags = 0; + + TEST(recvmsg(sock, tc->msg, tc->flags)); + if (TST_RET >= 0) + TST_RET = 0; + + if (TST_RET != ret) { + tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld", + tc->desc, ret, TST_RET); + } else if (TST_ERR != tc->exp_errno) { + tst_res(TFAIL | TTERRNO, + "%s: expected %s", + tc->desc, tst_strerrno(tc->exp_errno)); + } else { + tst_res(TPASS, "%s passed", tc->desc); } - cleanup(); - tst_exit(); + tc->cleanup(n); + cleanup_all(); } -pid_t pid; -char tmpsunpath[1024]; -void setup(void) +static void setup_all(void) { int tfd; - TEST_PAUSE; - tst_tmpdir(); + sun1.sun_family = AF_UNIX; + (void)strcpy(tmpsunpath, "udsockXXXXXX"); tfd = mkstemp(tmpsunpath); - close(tfd); - unlink(tmpsunpath); - sun1.sun_family = AF_UNIX; + SAFE_CLOSE(tfd); + SAFE_UNLINK(tmpsunpath); (void)strcpy(sun1.sun_path, tmpsunpath); - - signal(SIGPIPE, SIG_IGN); - + SAFE_SIGNAL(SIGPIPE, SIG_IGN); pid = start_server(&sin1, &sun1); } -void cleanup(void) +static void cleanup_all(void) { if (pid > 0) { (void)kill(pid, SIGKILL); /* kill server */ wait(NULL); } - if (tmpsunpath[0] != '\0') - (void)unlink(tmpsunpath); - tst_rmdir(); + if (tmpsunpath[0] != '\0') + (void)SAFE_UNLINK(tmpsunpath); } -void setup0(void) +static void setup_invalid_sock(int n) { - if (tdat[testno].experrno == EBADF) - s = 400; /* anything not an open file */ - else if ((s = open("/dev/null", O_WRONLY)) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed"); + if (tcases[n].exp_errno == EBADF) + sock = 400; /* anything not an open file */ + else + sock = SAFE_OPEN("/dev/null", O_WRONLY); } -void cleanup0(void) +static void cleanup_invalid_sock(int n) { - s = -1; + if (tcases[n].exp_errno == EBADF) + sock = -1; + else + SAFE_CLOSE(sock); } -void setup1(void) +static void setup_valid_sock(int n) { fd_set rdfds; struct timeval timeout; - int n; - - s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, - tdat[testno].proto); - if (tdat[testno].type == SOCK_STREAM) { - if (tdat[testno].domain == PF_INET) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, - sizeof(sin1)); + + sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol); + + if (tcases[n].type == SOCK_STREAM) { + if (tcases[n].domain == PF_INET) { + SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1)); /* Wait for something to be readable, else we won't detect EFAULT on recv */ FD_ZERO(&rdfds); - FD_SET(s, &rdfds); + FD_SET(sock, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; - n = select(s + 1, &rdfds, 0, 0, &timeout); - if (n != 1 || !FD_ISSET(s, &rdfds)) - tst_brkm(TBROK, cleanup, - "client setup1 failed - no message ready in 2 sec"); - } else if (tdat[testno].domain == PF_UNIX) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sun1, - sizeof(sun1)); + n = select(sock + 1, &rdfds, 0, 0, &timeout); + + if (n != 1 || !FD_ISSET(sock, &rdfds)) + tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec); + + } else if (tcases[n].domain == PF_UNIX) { + SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1)); } } } -void setup2(void) +static void setup_valid_msg_control(int n) { - setup1(); - if (write(s, "R", 1) < 0) - tst_brkm(TBROK | TERRNO, cleanup, "test setup failed: write:"); + setup_valid_sock(n); + SAFE_SEND(1, sock, "R", 1, 0); control = (struct cmsghdr *)cbuf; controllen = control->cmsg_len = sizeof(cbuf); } -void setup3(void) +static void setup_large_msg_control(int n) { - setup2(); - controllen = sizeof(struct cmsghdr) - 1; + setup_valid_msg_control(n); + controllen = CONTROL_LEN; } -void setup4(void) +static void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED) { - setup2(); - controllen = 128 * 1024; + SAFE_CLOSE(sock); } -void cleanup1(void) +static void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED) { - (void)close(s); - close(ufd); - close(sfd); - s = -1; -} + SAFE_CLOSE(sock); -void cleanup2(void) -{ - close(ufd); - close(sfd); - (void)close(s); - s = -1; - - if (passed_fd >= 0) - (void)close(passed_fd); - passed_fd = -1; control = 0; controllen = 0; } @@ -373,63 +365,70 @@ pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) ssin->sin_addr.s_addr = INADDR_ANY; /* set up inet socket */ - sfd = socket(PF_INET, SOCK_STREAM, 0); - if (sfd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server socket failed"); - return -1; - } - if (bind(sfd, (struct sockaddr *)ssin, sizeof(*ssin)) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server bind failed"); - return -1; - } - if (listen(sfd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server listen failed"); - return -1; - } - SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)ssin, &slen); + sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); + SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin)); + SAFE_LISTEN(sfd, 10); + SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen); /* set up UNIX-domain socket */ - ufd = socket(PF_UNIX, SOCK_STREAM, 0); - if (ufd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD socket failed"); - return -1; - } - if (bind(ufd, (struct sockaddr *)ssun, sizeof(*ssun))) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD bind failed"); - return -1; - } - if (listen(ufd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD listen failed"); - return -1; - } + ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0); + SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun)); + SAFE_LISTEN(ufd, 10); - switch ((pid = FORK_OR_VFORK())) { - case 0: /* child */ -#ifdef UCLINUX - if (self_exec(argv0, "dd", sfd, ufd) < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "server self_exec failed"); -#else + pid = SAFE_FORK(); + if (!pid) { do_child(); -#endif - break; - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "server fork failed"); - /* fall through */ - default: /* parent */ - (void)close(sfd); - (void)close(ufd); - return pid; + exit(1); } - exit(1); + + SAFE_CLOSE(sfd); + SAFE_CLOSE(ufd); + + return pid; +} + +/* for permission test */ +static void sender(int fd) +{ + struct msghdr mh = {}; + struct cmsghdr *control; + char tmpfn[BUF_SIZE] = ""; + char snd_cbuf[BUF_SIZE] = ""; + int tfd; + + (void)strcpy(tmpfn, "smtXXXXXX"); + tfd = mkstemp(tmpfn); + if (tfd < 0) + return; + + /* set up cmsghdr */ + control = (struct cmsghdr *)snd_cbuf; + control->cmsg_len = sizeof(struct cmsghdr) + 4; + control->cmsg_level = SOL_SOCKET; + control->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(control) = tfd; + + /* set up msghdr */ + iov[0].iov_base = MSG; + iov[0].iov_len = sizeof(MSG); + mh.msg_iov = iov; + mh.msg_iovlen = 1; + mh.msg_flags = 0; + mh.msg_control = control; + mh.msg_controllen = control->cmsg_len; + + /* do it */ + SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0); + SAFE_CLOSE(tfd); + (void)SAFE_UNLINK(tmpfn); } -void do_child(void) +static void do_child(void) { struct sockaddr_in fsin; struct sockaddr_un fsun; fd_set afds, rfds; - int nfds, cc, fd; + int nfds, fd; FD_ZERO(&afds); FD_SET(sfd, &afds); @@ -455,19 +454,19 @@ void do_child(void) int newfd; fromlen = sizeof(fsin); - newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen); + newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); /* send something back */ - (void)write(newfd, "hoser\n", 6); + SAFE_SEND(1, newfd, "hi", 2, 0); } } if (FD_ISSET(ufd, &rfds)) { int newfd; fromlen = sizeof(fsun); - newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen); + newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); @@ -475,55 +474,22 @@ void do_child(void) } for (fd = 0; fd < nfds; ++fd) if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { - char rbuf[1024]; + char rbuf[BUF_SIZE]; - cc = read(fd, rbuf, sizeof(rbuf)); - if (cc && rbuf[0] == 'R') + TEST(read(fd, rbuf, sizeof(rbuf))); + if (TST_RET > 0 && rbuf[0] == 'R') sender(fd); - if (cc == 0 || (cc < 0 && errno != EINTR)) { - (void)close(fd); + if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) { + close(fd); FD_CLR(fd, &afds); } } } } -#define TM "from recvmsg01 server" - -/* special for rights-passing test */ -void sender(int fd) -{ - struct msghdr mh; - struct cmsghdr *control; - char tmpfn[1024], snd_cbuf[1024]; - int tfd; - - (void)strcpy(tmpfn, "smtXXXXXX"); - tfd = mkstemp(tmpfn); - if (tfd < 0) - return; - - memset(&mh, 0x00, sizeof(mh)); - - /* set up cmsghdr */ - control = (struct cmsghdr *)snd_cbuf; - memset(control, 0x00, sizeof(struct cmsghdr)); - control->cmsg_len = sizeof(struct cmsghdr) + 4; - control->cmsg_level = SOL_SOCKET; - control->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(control) = tfd; - - /* set up msghdr */ - iov[0].iov_base = TM; - iov[0].iov_len = sizeof(TM); - mh.msg_iov = iov; - mh.msg_iovlen = 1; - mh.msg_flags = 0; - mh.msg_control = control; - mh.msg_controllen = control->cmsg_len; - - /* do it */ - (void)sendmsg(fd, &mh, 0); - (void)close(tfd); - (void)unlink(tmpfn); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .forks_child = 1, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/sbrk/sbrk01.c b/testcases/kernel/syscalls/sbrk/sbrk01.c index ce26b1503..c99fb0106 100644 --- a/testcases/kernel/syscalls/sbrk/sbrk01.c +++ b/testcases/kernel/syscalls/sbrk/sbrk01.c @@ -1,111 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - */ -/* - * DESCRIPTION - * 1.) test sbrk(8192) should return successfully. - * 2.) test sbrk(-8192) should return successfully. + * AUTHOR : William Roske, CO-PILOT : Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> - -#include "test.h" +/*\ + * [Description] + * + * Verify that sbrk() successfully increments or decrements the program's + * data break. + */ -char *TCID = "sbrk01"; +#include "tst_test.h" -static struct test_case_t { +static struct tcase { long increment; -} test_cases[] = { +} tcases[] = { + {0}, {8192}, - {-8192}, + {-8192} }; -static void setup(void); -static void sbrk_verify(const struct test_case_t *); -static void cleanup(void); - -int TST_TOTAL = ARRAY_SIZE(test_cases); - -int main(int ac, char **av) +static void run(unsigned int i) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); + struct tcase *tc = &tcases[i]; - setup(); + TESTPTR(sbrk(tc->increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); - -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (TST_RET_PTR == (void *) -1) + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed", tc->increment); + else + tst_res(TPASS, "sbrk(%ld) returned %p", tc->increment, TST_RET_PTR); } -static void sbrk_verify(const struct test_case_t *test) -{ - void *tret; - - tret = sbrk(test->increment); - TEST_ERRNO = errno; - - if (tret == (void *)-1) { - tst_resm(TFAIL | TTERRNO, "sbrk - Increase by %ld bytes failed", - test->increment); - } else { - tst_resm(TPASS, "sbrk - Increase by %ld bytes returned %p", - test->increment, tret); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/sbrk/sbrk02.c b/testcases/kernel/syscalls/sbrk/sbrk02.c index 84744ef90..7fccc4d3a 100644 --- a/testcases/kernel/syscalls/sbrk/sbrk02.c +++ b/testcases/kernel/syscalls/sbrk/sbrk02.c @@ -1,101 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * DESCRIPTION - * Check sbrk() with error condition that should produce ENOMEM. - */ - -#include <errno.h> -#include <unistd.h> -#include "test.h" -#define INC 16*1024*1024 +/*\ + * [Description] + * + * Verify that sbrk() on failure sets errno to ENOMEM. + */ -char *TCID = "sbrk02"; -int TST_TOTAL = 1; -static void setup(void); -static void sbrk_verify(void); -static void cleanup(void); +#include "tst_test.h" +#define INC (16*1024*1024) static long increment = INC; -int main(int argc, char *argv[]) +static void run(void) { - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + TESTPTR(sbrk(increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(); + if (TST_RET_PTR != (void *)-1) { + tst_res(TFAIL, "sbrk(%ld) unexpectedly passed and returned %p, " + "expected (void *)-1 with errno=%d", + increment, TST_RET_PTR, ENOMEM); + return; } - cleanup(); - tst_exit(); + if (TST_ERR == ENOMEM) + tst_res(TPASS | TTERRNO, "sbrk(%ld) failed as expected", increment); + else + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed but unexpected errno, " + "expected errno=%d - %s", + increment, ENOMEM, strerror(ENOMEM)); } static void setup(void) { void *ret = NULL; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* call sbrk until it fails or increment overflows */ while (ret != (void *)-1 && increment > 0) { ret = sbrk(increment); increment += INC; } - tst_resm(TINFO | TERRNO, "setup() bailing inc: %ld, ret: %p, sbrk: %p", - increment, ret, sbrk(0)); - - errno = 0; -} - -static void sbrk_verify(void) -{ - void *tret; - - tret = sbrk(increment); - TEST_ERRNO = errno; - - if (tret != (void *)-1) { - tst_resm(TFAIL, - "sbrk(%ld) returned %p, expected (void *)-1, errno=%d", - increment, tret, ENOMEM); - return; - } - - if (TEST_ERRNO == ENOMEM) { - tst_resm(TPASS | TTERRNO, "sbrk(%ld) failed as expected", - increment); - } else { - tst_resm(TFAIL | TTERRNO, - "sbrk(%ld) failed unexpectedly; expected: %d - %s", - increment, ENOMEM, strerror(ENOMEM)); - } } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .setup = setup +}; diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c index 447242159..597de4665 100644 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c @@ -69,7 +69,7 @@ static void run(void) } if (proc_flag) - TST_ASSERT_INT("/proc/sys/kernel/sched_rr_timeslice_ms", tst_ts_to_ms(tp)); + TST_ASSERT_INT(PROC_SCHED_RR_TIMESLICE_MS, tst_ts_to_ms(tp)); } static struct tst_test test = { @@ -79,6 +79,7 @@ static struct tst_test test = { .needs_root = 1, .tags = (const struct tst_tag[]) { {"linux-git", "975e155ed873"}, + {"linux-git", "c7fcb99877f9"}, {} } }; diff --git a/testcases/kernel/syscalls/sendfile/sendfile04.c b/testcases/kernel/syscalls/sendfile/sendfile04.c index 9a8ec08b9..4fa748137 100644 --- a/testcases/kernel/syscalls/sendfile/sendfile04.c +++ b/testcases/kernel/syscalls/sendfile/sendfile04.c @@ -14,6 +14,7 @@ * [Algorithm] * * Given wrong address or protected buffer as OFFSET argument to sendfile: + * * - a wrong address is created by munmap a buffer allocated by mmap * - a protected buffer is created by mmap with specifying protection */ diff --git a/testcases/kernel/syscalls/setgroups/.gitignore b/testcases/kernel/syscalls/setgroups/.gitignore index 0649a3425..9de928241 100644 --- a/testcases/kernel/syscalls/setgroups/.gitignore +++ b/testcases/kernel/syscalls/setgroups/.gitignore @@ -4,5 +4,3 @@ /setgroups02_16 /setgroups03 /setgroups03_16 -/setgroups04 -/setgroups04_16 diff --git a/testcases/kernel/syscalls/setgroups/setgroups01.c b/testcases/kernel/syscalls/setgroups/setgroups01.c index fed7f8e5a..9a5b77e93 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups01.c +++ b/testcases/kernel/syscalls/setgroups/setgroups01.c @@ -1,202 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* $Id: setgroups01.c,v 1.7 2009/11/02 13:57:18 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : setgroups01 - * - * EXECUTED BY : root - * - * TEST TITLE : Basic test for setgroups(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) setgroups(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the setgroups(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * setgroups(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/param.h> -#include <unistd.h> -#include <grp.h> -#include "test.h" - -#include "compat_16.h" +/*\ + * [Description] + * + * Check the basic functionality of the setgroups() system call. + */ -void setup(); -void cleanup(); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setgroups01); -int TST_TOTAL = 1; +static int len = NGROUPS; -int len = NGROUPS, ngrps = 0; -GID_T list[NGROUPS]; +static GID_T list[NGROUPS]; -int main(int ac, char **av) +static void verify_setgroups(void) { - int lc; - - /*************************************************************** - * parse standard options - ***************************************************************/ - tst_parse_opts(ac, av, NULL, NULL); - - /*************************************************************** - * perform global setup for test - ***************************************************************/ - setup(); - - /*************************************************************** - * check looping state if -c option given - ***************************************************************/ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups(2) - */ - TEST(SETGROUPS(cleanup, ngrps, list)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setgroups(%d, list) Failed, errno=%d : %s", - len, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setgroups(%d, list) returned %ld", - len, TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_POSITIVE(SETGROUPS(1, list), "setgroups()"); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void setup(void) { - - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ngrps = GETGROUPS(cleanup, len, list); - if (ngrps == -1) { - tst_brkm(TBROK, cleanup, - "getgroups(%d, list) Failure. errno=%d : %s", - len, errno, strerror(errno)); - } + len = GETGROUPS(NGROUPS, list); + if (len < 0) + tst_brk(TBROK | TERRNO, "getgroups() Failed"); } -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups02.c b/testcases/kernel/syscalls/setgroups/setgroups02.c index de23a4a7f..2b7f95c87 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups02.c +++ b/testcases/kernel/syscalls/setgroups/setgroups02.c @@ -1,180 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer */ -/* - * Test Name: setgroups02 - * - * Test Description: - * Verify that, only root process can invoke setgroups() system call to - * set the supplementary group IDs of the process. - * - * Expected Result: - * The call succeeds in setting all the supplementary group IDs of the - * calling process. The new group should be set in the process supplemental - * group list. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Check that root process can setgroups() supplementary group ID and verify + * that getgroups() returns the previously set ID. */ -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include <sys/param.h> - -#include "test.h" - -#include "compat_16.h" -#define TESTUSER "nobody" - -TCID_DEFINE(setgroups02); -int TST_TOTAL = 1; /* Total number of test conditions */ -GID_T groups_list[NGROUPS]; /* Array to hold gids for getgroups() */ - -struct passwd *user_info; /* struct. to hold test user info */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) -{ - int lc, i; - int gidsetsize = 1; /* only one GID, the GID of TESTUSER */ - int PASS_FLAG = 0; /* used for checking group array */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups() to set supplimentary group IDs of - * the calling super-user process to gid of TESTUSER. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "setgroups(%d, groups_list) Failed, " - "errno=%d : %s", gidsetsize, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } +#include <pwd.h> - /* - * Call getgroups(2) to verify that - * setgroups(2) successfully set the - * supp. gids of TESTUSER. - */ - groups_list[0] = '\0'; - if (GETGROUPS(cleanup, gidsetsize, groups_list) < 0) { - tst_brkm(TFAIL, cleanup, "getgroups() Fails, " - "error=%d", errno); - } - for (i = 0; i < NGROUPS; i++) { - if (groups_list[i] == user_info->pw_gid) { - tst_resm(TPASS, - "Functionality of setgroups" - "(%d, groups_list) successful", - gidsetsize); - PASS_FLAG = 1; - } - } - if (PASS_FLAG == 0) { - tst_resm(TFAIL, "Supplimentary gid %d not set " - "for the process", user_info->pw_gid); - } - } +#include "tst_test.h" +#include "compat_tst_16.h" - cleanup(); - tst_exit(); -} +static GID_T *groups_get, *groups_set; -/* - * setup() - performs all ONE TIME setup for this test. - * - * Make sure the test process uid is root. - * Get the supplimentrary group id of test user from /etc/passwd file. - */ -void setup(void) +static void verify_setgroups(void) { + groups_set[0] = 42; - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + TST_EXP_PASS(SETGROUPS(1, groups_set)); - TEST_PAUSE; + TST_EXP_VAL(GETGROUPS(1, groups_get), 1); - /* Get the group id info. of TESTUSER from /etc/passwd */ - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } + TST_EXP_EQ_LI(groups_get[0], groups_set[0]); - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - - groups_list[0] = user_info->pw_gid; + groups_get[0] = 0; } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .bufs = (struct tst_buffers []) { + {&groups_get, .size = sizeof(GID_T)}, + {&groups_set, .size = sizeof(GID_T)}, + {}, + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups03.c b/testcases/kernel/syscalls/setgroups/setgroups03.c index 490b06996..fbf8de0bb 100644 --- a/testcases/kernel/syscalls/setgroups/setgroups03.c +++ b/testcases/kernel/syscalls/setgroups/setgroups03.c @@ -1,222 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) Bull S.A. 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer + * 05/2002 Ported by Andre Merlier */ -/* - * Test Name: setgroups03 - * - * Test Description: - * Verify that, - * 1. setgroups() fails with -1 and sets errno to EINVAL if the size - * argument value is > NGROUPS - * 2. setgroups() fails with -1 and sets errno to EPERM if the - * calling process is not super-user. +/*\ + * [Description] * - * Expected Result: - * setgroups() should fail with return value -1 and set expected errno. + * Test for EINVAL, EPERM, EFAULT errors. * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. + * - setgroups() fails with EINVAL if the size argument value is > NGROUPS. * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * if errno set == expected errno - * Issue sys call fails with expected return value and errno. - * Otherwise, - * Issue sys call fails with unexpected errno. - * Otherwise, - * Issue sys call returns unexpected value. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be executed by 'non-super-user' only. + * - setgroups() fails with EPERM if the calling process is not super-user. * + * - setgroups() fails with EFAULT if the list has an invalid address. */ -#include <limits.h> -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include "test.h" +#include <pwd.h> +#include <stdlib.h> -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" #define TESTUSER "nobody" -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +static GID_T *glist1, *glist2, *glist3; +static struct passwd *user_info; -TCID_DEFINE(setgroups03); -int TST_TOTAL = 2; - -GID_T *groups_list; /* Array to hold gids for getgroups() */ - -int setup1(); /* setup function to test error EPERM */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -struct test_case_t { /* test case struct. to hold ref. test cond's */ - size_t gsize_add; - int list; - char *desc; +static struct tcase { + int gsize; + GID_T **glist; int exp_errno; - int (*setupfunc) (); -} Test_cases[] = { - { - 1, 1, "Size is > sysconf(_SC_NGROUPS_MAX)", EINVAL, NULL}, { - 0, 2, "Permission denied, not super-user", EPERM, setup1} +} tcases[] = { + {NGROUPS + 1, &glist1, EINVAL}, + {1, &glist2, EPERM}, + {NGROUPS, &glist3, EFAULT}, }; -int main(int ac, char **av) -{ - int lc; - int gidsetsize; /* total no. of groups */ - int i; - char *test_desc; /* test specific error message */ - int ngroups_max = sysconf(_SC_NGROUPS_MAX); /* max no. of groups in the current system */ - - tst_parse_opts(ac, av, NULL, NULL); - - groups_list = malloc(ngroups_max * sizeof(GID_T)); - if (groups_list == NULL) { - tst_brkm(TBROK, NULL, "malloc failed to alloc %zu errno " - " %d ", ngroups_max * sizeof(GID_T), errno); - } - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - if (Test_cases[i].setupfunc != NULL) { - Test_cases[i].setupfunc(); - } - - gidsetsize = ngroups_max + Test_cases[i].gsize_add; - test_desc = Test_cases[i].desc; - - /* - * Call setgroups() to test different test conditions - * verify that it fails with -1 return value and - * sets appropriate errno. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setgroups(%d) returned %ld, " - "expected -1, errno=%d", gidsetsize, - TEST_RETURN, Test_cases[i].exp_errno); - continue; - } - - if (TEST_ERRNO == Test_cases[i].exp_errno) { - tst_resm(TPASS, - "setgroups(%d) fails, %s, errno=%d", - gidsetsize, test_desc, TEST_ERRNO); - } else { - tst_resm(TFAIL, "setgroups(%d) fails, %s, " - "errno=%d, expected errno=%d", - gidsetsize, test_desc, TEST_ERRNO, - Test_cases[i].exp_errno); - } - } - - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all ONE TIME setup for this test. - * - * Call individual test specific setup functions. - */ -void setup(void) +static void verify_setgroups(unsigned int i) { - tst_require_root(); + struct tcase *tc = &tcases[i]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(user_info->pw_uid); - TEST_PAUSE; + TST_EXP_FAIL(SETGROUPS(tc->gsize, *tc->glist), tc->exp_errno, + "setgroups(%d, groups_list)", tc->gsize); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(0); } -/* - * setup1 - Setup function to test setgroups() which returns -1 - * and sets errno to EPERM. - * - * Get the user info. from /etc/passwd file. - * This function returns 0 on success. - */ -int setup1(void) +static void setup(void) { - struct passwd *user_info; /* struct. to hold test user info */ - -/* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } - - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - groups_list[0] = user_info->pw_gid; - return 0; + user_info = SAFE_GETPWNAM(TESTUSER); + glist2[0] = 42; + glist3 = tst_get_bad_addr(NULL); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test = verify_setgroups, + .tcnt = ARRAY_SIZE(tcases), + .bufs = (struct tst_buffers []) { + {&glist1, .size = sizeof(GID_T) * (NGROUPS + 1)}, + {&glist2, .size = sizeof(GID_T)}, + {&user_info, .size = sizeof(struct passwd)}, + {}, + }, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups04.c b/testcases/kernel/syscalls/setgroups/setgroups04.c deleted file mode 100644 index 971c86bd2..000000000 --- a/testcases/kernel/syscalls/setgroups/setgroups04.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) Bull S.A. 2001 - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * Test Name: setgroups04 - * - * Test Description: - * Verify that, setgroups() fails with -1 and sets errno to EFAULT if the list has an invalid address. - * - * Expected Result: - * setgroups() should fail with return value -1 and set expected errno. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * if errno set == expected errno - * Issue sys call fails with expected return value and errno. - * Otherwise, - * Issue sys call fails with unexpected errno. - * Otherwise, - * Issue sys call returns unexpected value. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: <for command-line> - * setgroups04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 05/2002 Ported by André Merlier - * - * RESTRICTIONS: - * none. - * - */ -#include <sys/types.h> -#include <sys/param.h> -#include <unistd.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> - -#include "test.h" - -#include "compat_16.h" - -TCID_DEFINE(setgroups04); -int TST_TOTAL = 1; - -GID_T groups_list[NGROUPS]; - -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -#if !defined(UCLINUX) - -int main(int ac, char **av) -{ - int lc; - int gidsetsize; /* total no. of groups */ - char *test_desc; /* test specific error message */ - - tst_parse_opts(ac, av, NULL, NULL); - - /* Perform setup for test */ - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - gidsetsize = NGROUPS; - test_desc = "EFAULT"; - - /* - * Call setgroups() to test condition - * verify that it fails with -1 return value and - * sets appropriate errno. - */ - TEST(SETGROUPS(cleanup, gidsetsize, sbrk(0))); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setgroups() returned %ld, " - "expected -1, errno=%d", TEST_RETURN, - EFAULT); - } else { - - if (TEST_ERRNO == EFAULT) { - tst_resm(TPASS, - "setgroups() fails with expected " - "error EFAULT errno:%d", TEST_ERRNO); - } else { - tst_resm(TFAIL, "setgroups() fails, %s, " - "errno=%d, expected errno=%d", - test_desc, TEST_ERRNO, EFAULT); - } - } - - } - - cleanup(); - tst_exit(); - -} - -#else - -int main(void) -{ - tst_resm(TINFO, "test is not available on uClinux"); - tst_exit(); -} - -#endif /* if !defined(UCLINUX) */ - -/* - * setup() - */ -void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - -} - -/* - * cleanup() - */ -void cleanup(void) -{ - -} diff --git a/testcases/kernel/syscalls/setpgid/setpgid02.c b/testcases/kernel/syscalls/setpgid/setpgid02.c index 4b63afee8..b380d7df4 100644 --- a/testcases/kernel/syscalls/setpgid/setpgid02.c +++ b/testcases/kernel/syscalls/setpgid/setpgid02.c @@ -13,15 +13,15 @@ * - EINVAL when given pgid is less than 0. * - ESRCH when pid is not the calling process and not a child of * the calling process. - * - EPERM when an attempt was made to move a process into a process - * group in a different session. + * - EPERM when an attempt was made to move a process into a nonexisting + * process group. */ #include <errno.h> #include <unistd.h> #include "tst_test.h" -static pid_t pgid, pid, ppid, init_pgid; +static pid_t pgid, pid, ppid, inval_pgid; static pid_t negative_pid = -1; static struct tcase { @@ -31,7 +31,7 @@ static struct tcase { } tcases[] = { {&pid, &negative_pid, EINVAL}, {&ppid, &pgid, ESRCH}, - {&pid, &init_pgid, EPERM} + {&pid, &inval_pgid, EPERM} }; static void setup(void) @@ -41,10 +41,10 @@ static void setup(void) pgid = getpgrp(); /* - * Getting pgid of init/systemd process to use it as a - * process group from a different session for EPERM test + * pid_max would not be in use by another process and guarantees that + * it corresponds to an invalid PGID, generating EPERM. */ - init_pgid = SAFE_GETPGID(1); + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &inval_pgid); } static void run(unsigned int n) diff --git a/testcases/kernel/syscalls/setpgid/setpgid03.c b/testcases/kernel/syscalls/setpgid/setpgid03.c index 79ca23e08..9ce2603d8 100644 --- a/testcases/kernel/syscalls/setpgid/setpgid03.c +++ b/testcases/kernel/syscalls/setpgid/setpgid03.c @@ -9,7 +9,9 @@ /*\ * [Description] * - * Tests setpgid() erorrs: + * Tests setpgid(2) errors: + * + * - EPERM The process specified by pid must not be a session leader. * * - EPERM The calling process, process specified by pid and the target * process group must be in the same session. @@ -43,6 +45,8 @@ static void run(void) TST_CHECKPOINT_WAIT(0); TST_EXP_FAIL(setpgid(child_pid, getppid()), EPERM); + /* Child did setsid(), so its PGID is set to its PID. */ + TST_EXP_FAIL(setpgid(0, child_pid), EPERM); TST_CHECKPOINT_WAKE(0); diff --git a/testcases/kernel/syscalls/setreuid/setreuid04.c b/testcases/kernel/syscalls/setreuid/setreuid04.c index 8eed90df0..06ffa32b0 100644 --- a/testcases/kernel/syscalls/setreuid/setreuid04.c +++ b/testcases/kernel/syscalls/setreuid/setreuid04.c @@ -1,141 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * Ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test that root can change the real and effective uid to an - * unpriviledged user. +/*\ + * [Description] + * + * Verify that root user can change the real and effective uid to an + * unprivileged user. */ -#include <errno.h> -#include <stdlib.h> #include <pwd.h> -#include <sys/wait.h> - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(setreuid04); - -static uid_t neg_one = -1; - -static struct passwd nobody, root; - -/* - * The following structure contains all test data. Each structure in the array - * is used for a separate test. The tests are executed in the for loop below. - */ - -struct test_data_t { - uid_t *real_uid; - uid_t *eff_uid; - struct passwd *exp_real_usr; - struct passwd *exp_eff_usr; - char *test_msg; -} test_data[] = { - { - &neg_one, &neg_one, &root, &root, "After setreuid(-1, nobody),"}, { -&nobody.pw_uid, &nobody.pw_uid, &nobody, &nobody, - "After setreuid(-1, -1),"},}; - -int TST_TOTAL = ARRAY_SIZE(test_data); - -static void setup(void); -static void cleanup(void); -static void uid_verify(struct passwd *, struct passwd *, char *); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int i, pid; - - tst_count = 0; +#include "tst_test.h" +#include "compat_tst_16.h" - if ((pid = FORK_OR_VFORK()) == -1) { - tst_brkm(TBROK, cleanup, "fork failed"); - } else if (pid == 0) { /* child */ - - for (i = 0; i < TST_TOTAL; i++) { - - /* Set the real or effective user id */ - TEST(SETREUID(cleanup, *test_data[i].real_uid, - *test_data[i].eff_uid)); - - if (TEST_RETURN != -1) { - tst_resm(TPASS, "setreuid(%d, %d) " - "succeeded as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } else { - tst_resm(TFAIL, "setreuid(%d, %d) " - "did not return as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } - - uid_verify(test_data[i].exp_real_usr, - test_data[i].exp_eff_usr, - test_data[i].test_msg); - } - tst_exit(); - } else { /* parent */ - tst_record_childstatus(cleanup, pid); - } - } - cleanup(); - tst_exit(); -} +static uid_t root_uid, nobody_uid; static void setup(void) { - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - if (getpwnam("nobody") == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); + struct passwd *nobody; - root = *(getpwnam("root")); - UID16_CHECK(root.pw_uid, setreuid, cleanup); + root_uid = getuid(); + nobody = SAFE_GETPWNAM("nobody"); + nobody_uid = nobody->pw_uid; - nobody = *(getpwnam("nobody")); - UID16_CHECK(nobody.pw_uid, setreuid, cleanup); - - TEST_PAUSE; + UID16_CHECK(nobody_uid, setreuid); + UID16_CHECK(root_uid, setreuid); } -static void cleanup(void) +static void run(void) { -} + if (!SAFE_FORK()) { + TST_EXP_PASS(SETREUID(nobody_uid, nobody_uid)); -static void uid_verify(struct passwd *ru, struct passwd *eu, char *when) -{ - if ((getuid() != ru->pw_uid) || (geteuid() != eu->pw_uid)) { - tst_resm(TFAIL, "ERROR: %s real uid = %d; effective uid = %d", - when, getuid(), geteuid()); - tst_resm(TINFO, "Expected: real uid = %d; effective uid = %d", - ru->pw_uid, eu->pw_uid); + TST_EXP_EQ_LI(GETUID(), nobody_uid); + TST_EXP_EQ_LI(GETEUID(), nobody_uid); } + tst_reap_children(); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid07.c b/testcases/kernel/syscalls/setreuid/setreuid07.c index ff222cd00..5faf3cb7f 100644 --- a/testcases/kernel/syscalls/setreuid/setreuid07.c +++ b/testcases/kernel/syscalls/setreuid/setreuid07.c @@ -1,192 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-later /* * Copyright (c) Kerlabs 2008. * Copyright (c) International Business Machines Corp., 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * Created by Renaud Lottiaux + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* +/*\ + * [Description] + * * Check if setreuid behaves correctly with file permissions. * The test creates a file as ROOT with permissions 0644, does a setreuid * and then tries to open the file with RDWR permissions. * The same test is done in a fork to check if new UIDs are correctly - * passed to the son. + * passed to the child process. */ -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <unistd.h> #include <pwd.h> +#include <stdlib.h> -#include "test.h" -#include "safe_macros.h" -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setreuid07); -int TST_TOTAL = 1; +#define TEMPFILE "testfile" -static char testfile[256] = ""; static struct passwd *ltpuser; -static int fd = -1; - -static void setup(void); -static void cleanup(void); -static void do_master_child(void); - -int main(int ac, char **av) +static void setup(void) { - pid_t pid; + int fd; - tst_parse_opts(ac, av, NULL, NULL); + ltpuser = SAFE_GETPWNAM("nobody"); - setup(); - - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) - do_master_child(); - - tst_record_childstatus(cleanup, pid); - - cleanup(); - tst_exit(); + UID16_CHECK(ltpuser->pw_uid, setreuid); + fd = SAFE_OPEN(TEMPFILE, O_CREAT | O_RDWR, 0644); + SAFE_CLOSE(fd); } -static void do_master_child(void) +static void run(void) { - int lc; - int pid; - int status; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int tst_fd; - - tst_count = 0; - - if (SETREUID(NULL, 0, ltpuser->pw_uid) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } - - /* Test 1: Check the process with new uid cannot open the file - * with RDWR permissions. - */ - TEST(tst_fd = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("open succeeded unexpectedly\n"); - close(tst_fd); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - } else { - perror("open failed unexpectedly"); - exit(TFAIL); - } - - /* Test 2: Check a son process cannot open the file - * with RDWR permissions. - */ - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) { - int tst_fd2; - - /* Test to open the file in son process */ - TEST(tst_fd2 = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("call succeeded unexpectedly\n"); - close(tst_fd2); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - exit(TPASS); - } else { - printf("open failed unexpectedly\n"); - exit(TFAIL); - } - } else { - /* Wait for son completion */ - if (waitpid(pid, &status, 0) == -1) { - perror("waitpid failed"); - exit(TFAIL); - } - if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - exit(WEXITSTATUS(status)); - } - - /* Test 3: Fallback to initial uid and check we can again open - * the file with RDWR permissions. - */ - tst_count++; - if (SETREUID(NULL, 0, 0) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } + pid_t pid; - TEST(tst_fd = open(testfile, O_RDWR)); + TST_EXP_PASS_SILENT(SETREUID(-1, ltpuser->pw_uid)); + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); - if (TEST_RETURN == -1) { - perror("open failed unexpectedly"); - exit(TFAIL); - } else { - printf("open call succeeded\n"); - close(tst_fd); - } + pid = SAFE_FORK(); + if (pid == 0) { + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); + exit(0); } - exit(TPASS); -} + tst_reap_children(); -static void setup(void) -{ - tst_require_root(); - - ltpuser = getpwnam("nobody"); - if (ltpuser == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); - - tst_tmpdir(); - - sprintf(testfile, "setreuid07file%d.tst", getpid()); - - /* Create test file */ - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS_SILENT(SETREUID(-1, 0)); + TST_EXP_FD(open(TEMPFILE, O_RDWR)); + SAFE_CLOSE(TST_RET); } -static void cleanup(void) -{ - close(fd); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt02.c b/testcases/kernel/syscalls/setsockopt/setsockopt02.c index e7621538b..3349c9970 100644 --- a/testcases/kernel/syscalls/setsockopt/setsockopt02.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt02.c @@ -96,4 +96,8 @@ static struct tst_test test = { .needs_root = 1, .setup = setup, .cleanup = cleanup, + .tags = (const struct tst_tag[]) { + {"CVE", "2017-7308"}, + {} + } }; diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt08.c b/testcases/kernel/syscalls/setsockopt/setsockopt08.c index 5fc1a8b8e..7f8243de1 100644 --- a/testcases/kernel/syscalls/setsockopt/setsockopt08.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt08.c @@ -26,57 +26,63 @@ * ->targetsize: if OTOH the user specified ->u.user.target_size is * too small, then the memset() destination address calculated by * adding ->targetsize to the payload start will not point at, but - * into or even past the padding. For the table's last entry's target - * record, this will result in an out-of-bounds write past the - * destination buffer allocated for the converted table. The code - * below will create a (compat) table such that the converted table's - * calculated size will fit exactly into a slab size of 1024 bytes and - * that the memset() in xt_compat_target_from_user() will write past - * this slab. + * into or even past the padding. + * + * For the table's last entry's target record, this will result in an + * out-of-bounds write past the destination buffer allocated for the converted + * table. The code below will create a (compat) table such that the converted + * table's calculated size will fit exactly into a slab size of 1024 bytes and + * that the memset() in xt_compat_target_from_user() will write past this slab. * * The table will consist of - * - the mandatory struct compat_ipt_replace header, - * - a single entry consisting of - * - the mandatory compat_ipt_entry header - * - a single 'state' match entry of appropriate size for + * + * * the mandatory struct compat_ipt_replace header, + * * a single entry consisting of + * ** the mandatory compat_ipt_entry header + * ** a single 'state' match entry of appropriate size for * controlling the out-of-bounds write when converting * the target entry following next, - * - a single 'REJECT' target entry. + * ** a single 'REJECT' target entry. + * * The kernel will transform this into a buffer containing (in * this order) - * - a xt_table_info - * - a single entry consisting of - * - its ipt_entry header - * - a single 'state' match entry - * - followed by a single 'REJECT' target entry. + * + * * a xt_table_info + * * a single entry consisting of + * ** its ipt_entry header + * ** a single 'state' match entry + * ** followed by a single 'REJECT' target entry. * * The expected sizes for the 'state' match entries as well as the * 'REJECT' target are the size of the base header struct (32 bytes) - * plus the size of an unsigned int (4 bytes) each. In the course of - * the compat => non-compat conversion, the kernel will insert four - * bytes of padding after the unsigned int payload (c.f. 'off' - * adjustments via xt_compat_match_offset() and - * xt_compat_target_offset() in xt_compat_match_from_user() and - * xt_compat_target_from_user() resp.). This code is based on the - * premise that the user sets the given ->u.user.match_size or - * ->u.user.target_size consistent to the COMPAT_XT_ALIGN()ed payload - * size as specified by the corresponding xt_match instance's - * ->matchsize or xt_target instance's ->targetsize. That is, the - * padding gets inserted unconditionally during the transformation, + * plus the size of an unsigned int (4 bytes) each. + * + * In the course of the compat => non-compat conversion, the kernel will insert + * four bytes of padding after the unsigned int payload (c.f. 'off' adjustments + * via xt_compat_match_offset() and xt_compat_target_offset() in + * xt_compat_match_from_user() and xt_compat_target_from_user() resp.). + * + * This code is based on the premise that the user sets the given + * ->u.user.match_size or ->u.user.target_size consistent to the + * COMPAT_XT_ALIGN()ed payload size as specified by the corresponding xt_match + * instance's ->matchsize or xt_target instance's ->targetsize. + * + * That is, the padding gets inserted unconditionally during the transformation, * independent of the actual values of ->u.user.match_size or - * ->u.user.target_size and the result ends up getting layed out with - * proper alignment only if said values match the expectations. That's - * not a problem in itself, but this unconditional insertion of - * padding must be taken into account in the match_size calculation - * below. + * ->u.user.target_size and the result ends up getting layed out with proper + * alignment only if said values match the expectations. + * + * That's not a problem in itself, but this unconditional insertion of padding + * must be taken into account in the match_size calculation below. * * For the match_size calculation below, note that the chosen * target slab size is 1024 and that - * - sizeof(xt_table_info) = 64 - * - sizeof(ipt_entry) = 112 - * - the kernel will insert four bytes of padding + * + * * sizeof(xt_table_info) = 64 + * * sizeof(ipt_entry) = 112 + * * the kernel will insert four bytes of padding * after the match and target entries each. - * - sizeof(struct xt_entry_target) = 32 + * * sizeof(struct xt_entry_target) = 32 */ #include <netinet/in.h> diff --git a/testcases/kernel/syscalls/sockioctl/sockioctl01.c b/testcases/kernel/syscalls/sockioctl/sockioctl01.c index 51dac9c16..ff3738f32 100644 --- a/testcases/kernel/syscalls/sockioctl/sockioctl01.c +++ b/testcases/kernel/syscalls/sockioctl/sockioctl01.c @@ -52,7 +52,7 @@ static struct ifreq ifr; static int sinlen; static int optval; -static char buf[8192]; +static struct ifreq buf[200]; static void setup(void); static void setup0(void); @@ -218,7 +218,7 @@ static void setup2(void) s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, tdat[testno].proto); ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; + ifc.ifc_buf = (char *)buf; } static void setup3(void) diff --git a/testcases/kernel/syscalls/stat/stat01.c b/testcases/kernel/syscalls/stat/stat01.c index e0dbfbf2f..365cdac8a 100644 --- a/testcases/kernel/syscalls/stat/stat01.c +++ b/testcases/kernel/syscalls/stat/stat01.c @@ -8,9 +8,9 @@ /*\ * [Description] * - * Verify that, stat(2) succeeds to get the status of a file and fills the - * stat structure elements regardless of whether process has or doesn't - * have read access to the file. + * Verify that, stat(2) succeeds to get the status of a file and fills the + * stat structure elements regardless of whether process has or doesn't + * have read access to the file. */ #include <pwd.h> diff --git a/testcases/kernel/syscalls/statvfs/statvfs02.c b/testcases/kernel/syscalls/statvfs/statvfs02.c index 8aaa47318..6f36530bf 100644 --- a/testcases/kernel/syscalls/statvfs/statvfs02.c +++ b/testcases/kernel/syscalls/statvfs/statvfs02.c @@ -10,6 +10,7 @@ * [Description] * * Verify that statvfs() fails with: + * * - EFAULT when path points to an invalid address. * - ELOOP when too many symbolic links were encountered in translating path. * - ENAMETOOLONG when path is too long. diff --git a/testcases/kernel/syscalls/statx/.gitignore b/testcases/kernel/syscalls/statx/.gitignore index 1cea43c0d..f6a423eed 100644 --- a/testcases/kernel/syscalls/statx/.gitignore +++ b/testcases/kernel/syscalls/statx/.gitignore @@ -7,3 +7,6 @@ /statx07 /statx08 /statx09 +/statx10 +/statx11 +/statx12 diff --git a/testcases/kernel/syscalls/statx/statx01.c b/testcases/kernel/syscalls/statx/statx01.c index 68f56549f..f9c2748d2 100644 --- a/testcases/kernel/syscalls/statx/statx01.c +++ b/testcases/kernel/syscalls/statx/statx01.c @@ -33,6 +33,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #include "tst_safe_stdio.h" #include <string.h> #include <inttypes.h> diff --git a/testcases/kernel/syscalls/statx/statx02.c b/testcases/kernel/syscalls/statx/statx02.c index a8e868d7a..5ed80894d 100644 --- a/testcases/kernel/syscalls/statx/statx02.c +++ b/testcases/kernel/syscalls/statx/statx02.c @@ -28,6 +28,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_temp" #define LINK_FILE "test_temp_ln" diff --git a/testcases/kernel/syscalls/statx/statx03.c b/testcases/kernel/syscalls/statx/statx03.c index b88809063..2465d8773 100644 --- a/testcases/kernel/syscalls/statx/statx03.c +++ b/testcases/kernel/syscalls/statx/statx03.c @@ -24,6 +24,7 @@ #include "tst_safe_macros.h" #include "tst_get_bad_addr.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_file" #define MODE 0644 diff --git a/testcases/kernel/syscalls/statx/statx04.c b/testcases/kernel/syscalls/statx/statx04.c index 3923b7f8e..58296bd24 100644 --- a/testcases/kernel/syscalls/statx/statx04.c +++ b/testcases/kernel/syscalls/statx/statx04.c @@ -52,10 +52,11 @@ */ #define _GNU_SOURCE +#include <stdlib.h> #include "tst_test.h" #include "lapi/fs.h" -#include <stdlib.h> #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR MOUNT_POINT "/testdir" diff --git a/testcases/kernel/syscalls/statx/statx05.c b/testcases/kernel/syscalls/statx/statx05.c index f62dadd5c..9781b3e70 100644 --- a/testcases/kernel/syscalls/statx/statx05.c +++ b/testcases/kernel/syscalls/statx/statx05.c @@ -27,6 +27,7 @@ #include "tst_test.h" #include "lapi/fs.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MNTPOINT "mnt_point" #define TESTDIR_FLAGGED MNTPOINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx06.c b/testcases/kernel/syscalls/statx/statx06.c index fa75982b0..1771dff49 100644 --- a/testcases/kernel/syscalls/statx/statx06.c +++ b/testcases/kernel/syscalls/statx/statx06.c @@ -111,10 +111,10 @@ static void test_statx(unsigned int test_nr) clock_wait_tick(); SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &after_time); - TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_ALL, &buff)); + TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)); if (TST_RET != 0) { tst_brk(TFAIL | TTERRNO, - "statx(AT_FDCWD, %s, 0, STATX_ALL, &buff)", + "statx(AT_FDCWD, %s, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)", TEST_FILE); } diff --git a/testcases/kernel/syscalls/statx/statx07.c b/testcases/kernel/syscalls/statx/statx07.c index 8cb3e9b6d..4dbf83e18 100644 --- a/testcases/kernel/syscalls/statx/statx07.c +++ b/testcases/kernel/syscalls/statx/statx07.c @@ -27,12 +27,7 @@ * but mode has been chaged in server file. * * The support for SYNC flags was implemented in NFS in: - * - * commit 9ccee940bd5b766b6dab6c1a80908b9490a4850d - * Author: Trond Myklebust <trond.myklebust@primarydata.com> - * Date: Thu Jan 4 17:46:09 2018 -0500 - * - * Support statx() mask and query flags parameters + * 9ccee940bd5b ("Support statx() mask and query flags parameters") */ #define _GNU_SOURCE @@ -44,6 +39,7 @@ #include <sys/mount.h> #include "tst_test.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MODE(X) (X & (~S_IFMT)) #define FLAG_NAME(x) .flag = x, .flag_name = #x @@ -67,15 +63,15 @@ static int get_mode(char *file_name, int flag_type, char *flag_name) { struct statx buf; - TEST(statx(AT_FDCWD, file_name, flag_type, STATX_ALL, &buf)); + TEST(statx(AT_FDCWD, file_name, flag_type, STATX_BASIC_STATS, &buf)); if (TST_RET == -1) { tst_brk(TFAIL | TST_ERR, - "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf)", + "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf)", file_name, flag_name); } - tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf) = %o", + tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf) = %o", file_name, flag_name, buf.stx_mode); return buf.stx_mode; diff --git a/testcases/kernel/syscalls/statx/statx08.c b/testcases/kernel/syscalls/statx/statx08.c index 10b1ca460..64b36986d 100644 --- a/testcases/kernel/syscalls/statx/statx08.c +++ b/testcases/kernel/syscalls/statx/statx08.c @@ -26,6 +26,7 @@ #include "lapi/fs.h" #include <stdlib.h> #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR_FLAGGED MOUNT_POINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx09.c b/testcases/kernel/syscalls/statx/statx09.c index aea329e08..6e75ff3ec 100644 --- a/testcases/kernel/syscalls/statx/statx09.c +++ b/testcases/kernel/syscalls/statx/statx09.c @@ -20,10 +20,12 @@ #define _GNU_SOURCE #include <sys/mount.h> #include <stdlib.h> +#include <stdio.h> #include "tst_test.h" #include "lapi/fs.h" #include "lapi/fsverity.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #include <inttypes.h> #define MNTPOINT "mnt_point" @@ -79,8 +81,10 @@ static void flag_setup(void) { int fd, attr, ret; struct fsverity_enable_arg enable; + struct stat statbuf; fd = SAFE_OPEN(TESTFILE_FLAGGED, O_RDONLY, 0664); + SAFE_FSTAT(fd, &statbuf); ret = ioctl(fd, FS_IOC_GETFLAGS, &attr); if (ret < 0) { @@ -93,7 +97,7 @@ static void flag_setup(void) memset(&enable, 0, sizeof(enable)); enable.version = 1; enable.hash_algorithm = hash_algorithms[0]; - enable.block_size = 4096; + enable.block_size = statbuf.st_blksize; enable.salt_size = 0; enable.salt_ptr = (intptr_t)NULL; enable.sig_size = 0; @@ -117,6 +121,12 @@ static void flag_setup(void) static void setup(void) { + char opt_bsize[32]; + const char *const fs_opts[] = {"-O verity", opt_bsize, NULL}; + + snprintf(opt_bsize, sizeof(opt_bsize), "-b %i", getpagesize()); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); + TEST(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL)); if (TST_RET) { if (TST_ERR == EINVAL) @@ -144,10 +154,9 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, + .needs_device = 1, .mntpoint = MNTPOINT, - .format_device = 1, .dev_fs_type = "ext4", - .dev_fs_opts = (const char *const []){"-O verity", NULL}, .needs_kconfigs = (const char *[]) { "CONFIG_FS_VERITY", NULL diff --git a/testcases/kernel/syscalls/statx/statx10.c b/testcases/kernel/syscalls/statx/statx10.c new file mode 100644 index 000000000..42106285e --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx10.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on ext4 and xfs filesystem. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * Check these two values are nonzero under dio situation when STATX_DIOALIGN + * in the request mask. + * + * On ext4, files that use certain filesystem features (data journaling, + * encryption, and verity) fall back to buffered I/O. But ltp creates own + * filesystem by enabling mount_device in tst_test struct. If we set block + * device to LTP_DEV environment, we use this block device to mount by using + * default mount option. Otherwise, use loop device to simuate it. So it can + * avoid these above situations and don't fall back to buffered I/O. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include "tst_test.h" +#include "lapi/stat.h" +#include "lapi/fcntl.h" + +#define MNTPOINT "mnt_point" +#define TESTFILE MNTPOINT"/testfile" + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, TESTFILE, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", TESTFILE); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + if (buf.stx_dio_mem_align != 0) + tst_res(TPASS, "stx_dio_mem_align:%u", buf.stx_dio_mem_align); + else + tst_res(TFAIL, "stx_dio_mem_align was 0, but DIO should be supported"); + + if (buf.stx_dio_offset_align != 0) + tst_res(TPASS, "stx_dio_offset_align:%u", buf.stx_dio_offset_align); + else + tst_res(TFAIL, "stx_dio_offset_align was 0, but DIO should be supported"); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + int fd = -1; + + if (strcmp(tst_device->fs_type, "xfs") && strcmp(tst_device->fs_type, "ext4")) + tst_brk(TCONF, "This test only supports ext4 and xfs"); + + SAFE_FILE_PRINTF(TESTFILE, "AAAA"); + fd = open(TESTFILE, O_RDWR | O_DIRECT); + if (fd == -1) { + if (errno == EINVAL) + tst_brk(TCONF, + "The regular file is not on a filesystem that support DIO"); + else + tst_brk(TBROK | TERRNO, + "The regular file is open with O_RDWR | O_DIRECT failed"); + } + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_root = 1, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx11.c b/testcases/kernel/syscalls/statx/statx11.c new file mode 100644 index 000000000..653050855 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx11.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on block device. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * These two values are tightly coupled to the kernel's current DIO + * restrictions on block devices. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/mount.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include "tst_test.h" +#include "lapi/stat.h" + +static char sys_bdev_dma_path[1024], sys_bdev_logical_path[1024]; + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tst_device->dev, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", tst_device->dev); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + /* + * This test is tightly coupled to the kernel's current DIO restrictions + * on block devices. The general rule of DIO needing to be aligned to the + * block device's logical block size was relaxed to allow user buffers + * (but not file offsets) aligned to the DMA alignment instead. See v6.0 + * commit bf8d08532bc1 ("iomap: add support for dma aligned direct-io") and + * they are subject to further change in the future. + * Also can see commit 2d985f8c6b9 ("vfs: support STATX_DIOALIGN on block devices). + */ + TST_ASSERT_ULONG(sys_bdev_dma_path, buf.stx_dio_mem_align - 1); + TST_ASSERT_ULONG(sys_bdev_logical_path, buf.stx_dio_offset_align); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + char full_name[256]; + char *dev_name; + + strcpy(full_name, tst_device->dev); + dev_name = SAFE_BASENAME(full_name); + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + + /* + * Since /sys/block/%s/queue doesn't exist for partition, we need to + * use a while to search block device instead of partition. + */ + while (access(sys_bdev_logical_path, F_OK) != 0) { + dev_name[strlen(dev_name)-1] = '\0'; + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + } + + sprintf(sys_bdev_dma_path, "/sys/block/%s/queue/dma_alignment", dev_name); + if (access(sys_bdev_dma_path, F_OK) != 0) + tst_brk(TCONF, "dma_alignment sysfs file doesn't exist"); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_device = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx12.c b/testcases/kernel/syscalls/statx/statx12.c new file mode 100644 index 000000000..432f1cb77 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx12.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@fujitsu.com> + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_ATTR_MOUNT_ROOT flag. + * + * This flag indicates whether the path or fd refers to the root of a mount + * or not. + * + * Minimum Linux version required is v5.8. + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include "tst_test.h" +#include "lapi/stat.h" + +#define MNTPOINT "mntpoint" +#define TESTFILE MNTPOINT"/testfile" + +static int dir_fd = -1, file_fd = -1; + +static struct tcase { + const char *path; + bool mnt_root; + int *fd; +} tcases[] = { + {MNTPOINT, 1, &dir_fd}, + {TESTFILE, 0, &file_fd} +}; + +static void verify_statx(unsigned int n) +{ + struct tcase *tc = &tcases[n/2]; + struct statx buf; + bool flag = n % 2; + + if (flag) { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by fd", + tc->path); + TST_EXP_PASS_SILENT(statx(*tc->fd, "", AT_EMPTY_PATH, 0, &buf)); + } else { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by path", + tc->path); + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tc->path, 0, 0, &buf)); + } + + if (!(buf.stx_attributes_mask & STATX_ATTR_MOUNT_ROOT)) { + tst_res(TCONF, "Filesystem does not support STATX_ATTR_MOUNT_ROOT"); + return; + } + + if (buf.stx_attributes & STATX_ATTR_MOUNT_ROOT) { + tst_res(tc->mnt_root ? TPASS : TFAIL, + "STATX_ATTR_MOUNT_ROOT flag is set"); + } else { + tst_res(tc->mnt_root ? TFAIL : TPASS, + "STATX_ATTR_MOUNT_ROOT flag is not set"); + } +} + +static void setup(void) +{ + SAFE_CREAT(TESTFILE, 0755); + dir_fd = SAFE_OPEN(MNTPOINT, O_DIRECTORY); + file_fd = SAFE_OPEN(TESTFILE, O_RDWR); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_statx, + .setup = setup, + .cleanup = cleanup, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, + .needs_root = 1, + .tcnt = 2 * ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/switch/endian_switch01.c b/testcases/kernel/syscalls/switch/endian_switch01.c index bee35184a..fac9e2382 100644 --- a/testcases/kernel/syscalls/switch/endian_switch01.c +++ b/testcases/kernel/syscalls/switch/endian_switch01.c @@ -2,7 +2,7 @@ /* * Copyright (c) International Business Machines Corp., 2008 * Copyright (c) Paul Mackerras, IBM Corp., 2008 - * Copyright (c) 2018 Linux Test Project + * Copyright (c) 2018-2023 Linux Test Project */ /* @@ -17,14 +17,17 @@ #include <elf.h> #include <sys/types.h> #include <sys/wait.h> + #include "tst_test.h" #if defined(__powerpc64__) || defined(__powerpc__) + # ifndef PPC_FEATURE_TRUE_LE -# define PPC_FEATURE_TRUE_LE 0x00000002 +# define PPC_FEATURE_TRUE_LE 0x00000002 # endif -# define TST_NO_DEFAULT_MAIN +# ifdef HAVE_GETAUXVAL +# include <sys/auxv.h> /* * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not @@ -42,6 +45,9 @@ void check_le_switch_supported(void) exit(errno); } + if (!(getauxval(AT_HWCAP) & PPC_FEATURE_TRUE_LE)) + tst_brk(TCONF, "Processor does not support little-endian mode"); + SAFE_WAIT(&status); if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); @@ -96,18 +102,9 @@ static struct tst_test test = { .forks_child = 1, }; -int main4(int argc, char **argv, LTP_ATTRIBUTE_UNUSED char **envp, - unsigned long *auxv) -{ - for (; *auxv != AT_NULL && *auxv != AT_HWCAP; auxv += 2) - ; - - if (!(auxv[0] == AT_HWCAP && (auxv[1] & PPC_FEATURE_TRUE_LE))) - tst_brk(TCONF, "Processor does not support little-endian mode"); - - tst_run_tcases(argc, argv, &test); - return 0; -} +# else +TST_TEST_TCONF("Toolchain does not have <sys/auxv.h>"); +# endif /* HAVE_GETAUXVAL */ #else /* defined (__powerpc64__) || (__powerpc__) */ TST_TEST_TCONF("This system does not support running of switch() syscall"); diff --git a/testcases/kernel/syscalls/symlink/symlink01.c b/testcases/kernel/syscalls/symlink/symlink01.c index eba64f9bd..8cf0c8f1c 100644 --- a/testcases/kernel/syscalls/symlink/symlink01.c +++ b/testcases/kernel/syscalls/symlink/symlink01.c @@ -658,10 +658,10 @@ int creat_symlink(char *path1, char *path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "symlink(%s, %s) was succesful.\n", path1, path2); + sprintf(Buf, "symlink(%s, %s) was successful.\n", path1, path2); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "symlink(%s, %s) was succesful.", path1, path2); + tst_resm(TPASS, "symlink(%s, %s) was successful.", path1, path2); #endif } return 1; @@ -685,10 +685,10 @@ int creat_object(char *path1, char *_path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "creat(%s, %#o) was succesful.\n", path1, MODE); + sprintf(Buf, "creat(%s, %#o) was successful.\n", path1, MODE); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "creat(%s, %#o) was succesful.", path1, MODE); + tst_resm(TPASS, "creat(%s, %#o) was successful.", path1, MODE); #endif } if (close(fd) == -1) { diff --git a/testcases/kernel/syscalls/timerfd/timerfd_create01.c b/testcases/kernel/syscalls/timerfd/timerfd_create01.c index 3d70b84f0..18a233586 100644 --- a/testcases/kernel/syscalls/timerfd/timerfd_create01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_create01.c @@ -1,95 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. - * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Zeng Linggang <zenglg.jy@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * DESCRIPTION - * Verify that, - * 1. The clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, - * EINVAL would return. - * 2. flags is invalid, EINVAL would return. +/*\ + * [Description] + * + * This test verifies that: + * - clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, + * EINVAL would return. + * - flags is invalid, EINVAL would return. */ -#define _GNU_SOURCE - #include <errno.h> -#include "test.h" -#include "lapi/timerfd.h" - -char *TCID = "timerfd_create01"; +#include "tst_test.h" +#include "tst_safe_timerfd.h" static struct test_case_t { int clockid; int flags; int exp_errno; -} test_cases[] = { - {-1, 0, EINVAL}, - {0, -1, EINVAL}, +} tcases[] = { + { -1, 0, EINVAL }, + { 0, -1, EINVAL }, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void timerfd_create_verify(const struct test_case_t *); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void run(unsigned int i) { - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); + struct test_case_t *test = &tcases[i]; - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - timerfd_create_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); + TST_EXP_FAIL(timerfd_create(test->clockid, test->flags), test->exp_errno); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -static void timerfd_create_verify(const struct test_case_t *test) -{ - TEST(timerfd_create(test->clockid, test->flags)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "timerfd_create() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, - "timerfd_create() failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "timerfd_create() failed unexpectedly; expected: " - "%d - %s", test->exp_errno, strerror(test->exp_errno)); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/uname/uname04.c b/testcases/kernel/syscalls/uname/uname04.c index 2d0851c8b..885368c24 100644 --- a/testcases/kernel/syscalls/uname/uname04.c +++ b/testcases/kernel/syscalls/uname/uname04.c @@ -79,4 +79,8 @@ static void run(unsigned int test_nr) static struct tst_test test = { .test = run, .tcnt = 2, + .tags = (const struct tst_tag[]) { + {"CVE", "2012-0957"}, + {} + } }; diff --git a/testcases/kernel/syscalls/utils/compat_uid.h b/testcases/kernel/syscalls/utils/compat_uid.h index 94e54f310..7a345a654 100644 --- a/testcases/kernel/syscalls/utils/compat_uid.h +++ b/testcases/kernel/syscalls/utils/compat_uid.h @@ -26,7 +26,7 @@ #include "tst_common.h" #ifdef TST_USE_COMPAT16_SYSCALL -typedef __kernel_old_uid_t UID_T; +typedef unsigned short UID_T; int UID_SIZE_CHECK(uid_t uid) { /* See high2lowuid in linux/highuid.h diff --git a/testcases/kernel/syscalls/utils/ioprio.h b/testcases/kernel/syscalls/utils/ioprio.h deleted file mode 100644 index 07220945c..000000000 --- a/testcases/kernel/syscalls/utils/ioprio.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __IOPRIO_H__ -#define __IOPRIO_H__ - -//---------------------------------------------------------------------------- -// Copy of the 2.6.18 kernel header (linux/ioprio.h) -// - -/* - * Gives us 8 prio classes with 13-bits of data for each class - */ -#define IOPRIO_BITS (16) -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) - -#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -/* - * 8 best effort priority levels are supported - */ -#define IOPRIO_BE_NR (8) - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; -//----------------------------------------------------------------------------- - -#endif /* __IOPRIO_H__ */ diff --git a/testcases/kernel/syscalls/utime/utime02.c b/testcases/kernel/syscalls/utime/utime02.c index 54693899e..fdcd40f66 100644 --- a/testcases/kernel/syscalls/utime/utime02.c +++ b/testcases/kernel/syscalls/utime/utime02.c @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the current time, * under the following constraints: + * * - The times argument is NULL. * - The user ID of the process is not "root". * - The file is owned by the user ID of the process. diff --git a/testcases/kernel/syscalls/utime/utime04.c b/testcases/kernel/syscalls/utime/utime04.c index 67e40127d..7b820ab06 100644 --- a/testcases/kernel/syscalls/utime/utime04.c +++ b/testcases/kernel/syscalls/utime/utime04.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 ported by John George - * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ /*\ @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the values specified by * times argument, under the following constraints: + * * - The times argument is not NULL. * - The user ID of the process is "root". */ diff --git a/testcases/kernel/syscalls/utime/utime05.c b/testcases/kernel/syscalls/utime/utime05.c index ce0aa5dbf..941a3ccee 100644 --- a/testcases/kernel/syscalls/utime/utime05.c +++ b/testcases/kernel/syscalls/utime/utime05.c @@ -11,6 +11,7 @@ * Verify that the system call utime() successfully changes the last * access and modification times of a file to the values specified by * times argument, under the following constraints: + * * - The times argument is not NULL. * - The user ID of the process is not "root". * - The file is owned by the user ID of the process. diff --git a/testcases/kernel/syscalls/utime/utime06.c b/testcases/kernel/syscalls/utime/utime06.c index 9057c29da..3ba62a316 100644 --- a/testcases/kernel/syscalls/utime/utime06.c +++ b/testcases/kernel/syscalls/utime/utime06.c @@ -9,11 +9,12 @@ * [Description] * * Verify that system call utime() fails with - * - EACCES when times argument is NULL and user does not have rights - * to modify the file. + * + * - EACCES when times argument is NULL and user does not have rights to modify + * the file. * - ENOENT when specified file does not exist. - * - EPERM when times argument is not NULL and user does not have rights - * to modify the file. + * - EPERM when times argument is not NULL and user does not have rights to + * modify the file. * - EROFS when the path resides on a read-only filesystem. */ diff --git a/testcases/kernel/syscalls/utimensat/utimensat01.c b/testcases/kernel/syscalls/utimensat/utimensat01.c index 71a0e8d0e..efcb5c7a4 100644 --- a/testcases/kernel/syscalls/utimensat/utimensat01.c +++ b/testcases/kernel/syscalls/utimensat/utimensat01.c @@ -233,7 +233,7 @@ static void run(unsigned int i) dfd = SAFE_OPEN(TEST_DIR, tc->oflags); if (tc->pathname) { - fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT); + fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT, 0200); pathname = tc->pathname; SAFE_CHMOD(tc->pathname, tc->mode); reset_time(pathname, dfd, tc->flags, i); diff --git a/testcases/kernel/syscalls/write/write02.c b/testcases/kernel/syscalls/write/write02.c index 2f630ab65..ab38dce77 100644 --- a/testcases/kernel/syscalls/write/write02.c +++ b/testcases/kernel/syscalls/write/write02.c @@ -2,27 +2,24 @@ /* * Copyright (c) 2017 Carlo Marcelo Arenas Belon <carlo@gmail.com> * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2003-2023 */ -/* + +/*\ + * [Description] + * * Tests for a special case NULL buffer with size 0 is expected to return 0. */ -#include <errno.h> #include "tst_test.h" static int fd; static void verify_write(void) { - TEST(write(fd, NULL, 0)); - - if (TST_RET != 0) { - tst_res(TFAIL | TTERRNO, - "write() should have succeeded with ret=0"); - return; - } + TST_EXP_POSITIVE(write(fd, NULL, 0)); - tst_res(TPASS, "write(fd, NULL, 0) == 0"); + TST_EXP_EXPR(TST_RET == 0, "write(fd, NULL, %ld) == %d", TST_RET, 0); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write04.c b/testcases/kernel/syscalls/write/write04.c index afbac0f09..a5d62e0f5 100644 --- a/testcases/kernel/syscalls/write/write04.c +++ b/testcases/kernel/syscalls/write/write04.c @@ -28,7 +28,7 @@ static void verify_write(void) { char wbuf[8 * page_size]; - TST_EXP_FAIL(write(wfd, wbuf, sizeof(wbuf)), EAGAIN); + TST_EXP_FAIL2(write(wfd, wbuf, sizeof(wbuf)), EAGAIN); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write05.c b/testcases/kernel/syscalls/write/write05.c index 79769621c..b907624a8 100644 --- a/testcases/kernel/syscalls/write/write05.c +++ b/testcases/kernel/syscalls/write/write05.c @@ -1,19 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 Ported by John George - * 04/2002 wjhuie sigset cleanups - * 08/2007 Ricardo Salveti de Araujo <rsalveti@linux.vnet.ibm.com> + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by John George + * 04/2002 wjhuie sigset cleanups + * 08/2007 Ricardo Salveti de Araujo <rsalveti@linux.vnet.ibm.com> + * Copyright (c) Linux Test Project, 2002-2023 */ -/* - * DESCRIPTION +/*\ + * [Description] + * * Check the return value, and errnos of write(2) + * * - when the file descriptor is invalid - EBADF * - when the buf parameter is invalid - EFAULT * - on an attempt to write to a pipe that is not open for reading - EPIPE */ + #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -42,7 +45,7 @@ static struct tcase { {&pipefd[1], &buf, sizeof(buf), EPIPE}, }; -static int sigpipe_cnt; +static volatile int sigpipe_cnt; static void sighandler(int sig) { @@ -56,26 +59,12 @@ static void verify_write(unsigned int i) sigpipe_cnt = 0; - TEST(write(*tc->fd, *tc->buf, tc->size)); - - if (TST_RET != -1) { - tst_res(TFAIL, "write() succeeded unexpectedly"); - return; - } - - if (TST_ERR != tc->exp_errno) { - tst_res(TFAIL | TTERRNO, - "write() failed unexpectedly, expected %s", - tst_strerrno(tc->exp_errno)); + TST_EXP_FAIL2(write(*tc->fd, *tc->buf, tc->size), tc->exp_errno); + if (TST_RET != -1) return; - } - if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) { + if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) tst_res(TFAIL, "sigpipe_cnt = %i", sigpipe_cnt); - return; - } - - tst_res(TPASS | TTERRNO, "write() failed expectedly"); } static void setup(void) diff --git a/testcases/lib/.gitignore b/testcases/lib/.gitignore index 34dea272d..e8afd06f3 100644 --- a/testcases/lib/.gitignore +++ b/testcases/lib/.gitignore @@ -3,17 +3,23 @@ /tst_check_kconfigs /tst_checkpoint /tst_device +/tst_fsfreeze /tst_getconf /tst_get_free_pids /tst_get_median /tst_get_unused_port +/tst_hexdump /tst_kvcmp +/tst_lockdown_enabled /tst_net_iface_prefix /tst_net_ip_prefix /tst_net_vars +/tst_ns_create +/tst_ns_exec +/tst_ns_ifmove /tst_random /tst_rod +/tst_secureboot_enabled /tst_sleep /tst_supported_fs -/tst_hexdump /tst_timeout_kill diff --git a/testcases/lib/Makefile b/testcases/lib/Makefile index f4f8c8524..990b46089 100644 --- a/testcases/lib/Makefile +++ b/testcases/lib/Makefile @@ -12,6 +12,7 @@ MAKE_TARGETS := tst_sleep tst_random tst_checkpoint tst_rod tst_kvcmp\ tst_device tst_net_iface_prefix tst_net_ip_prefix tst_net_vars\ tst_getconf tst_supported_fs tst_check_drivers tst_get_unused_port\ tst_get_median tst_hexdump tst_get_free_pids tst_timeout_kill\ - tst_check_kconfigs tst_cgctl + tst_check_kconfigs tst_cgctl tst_fsfreeze tst_ns_create tst_ns_exec\ + tst_ns_ifmove tst_lockdown_enabled tst_secureboot_enabled include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/lib/tst_fsfreeze.c b/testcases/lib/tst_fsfreeze.c new file mode 100644 index 000000000..4b0b12cba --- /dev/null +++ b/testcases/lib/tst_fsfreeze.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2010 Hajime Taira <htaira@redhat.com> + * Masatake Yamato <yamato@redhat.com> + * Copyright (c) 2023 Petr Vorel <pvorel@suse.cz> + * + * Based on fsfreeze from util-linux. + */ + +#include <linux/fs.h> +#include <stdio.h> + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_macros.h" + +static void help(void) +{ + printf("Freeze and unfreeze the device.\n"); + printf("Usage: tst_fsfreeze device\n"); +} + +int main(int argc, char *argv[]) +{ + int fd; + + if (argc < 2) { + help(); + return 1; + } + + fd = SAFE_OPEN(argv[1], O_RDONLY); + SAFE_IOCTL(fd, FIFREEZE, 0); + SAFE_IOCTL(fd, FITHAW, 0); + SAFE_CLOSE(fd); + + return 0; +} diff --git a/testcases/lib/tst_get_free_pids.c b/testcases/lib/tst_get_free_pids.c index d7b68c620..370ec3e26 100644 --- a/testcases/lib/tst_get_free_pids.c +++ b/testcases/lib/tst_get_free_pids.c @@ -2,7 +2,7 @@ #define TST_NO_DEFAULT_MAIN #include <stdio.h> -#include <tst_test.h> +#include "tst_test.h" extern struct tst_test *tst_test; diff --git a/testcases/lib/tst_kvcmp.c b/testcases/lib/tst_kvcmp.c index 0f5793ef1..afc4b5ce3 100644 --- a/testcases/lib/tst_kvcmp.c +++ b/testcases/lib/tst_kvcmp.c @@ -7,7 +7,7 @@ #include <stdio.h> #include <stdlib.h> #include <sys/utsname.h> -#include <tst_test.h> +#include "tst_test.h" enum op { EQ, diff --git a/testcases/lib/tst_lockdown_enabled.c b/testcases/lib/tst_lockdown_enabled.c new file mode 100644 index 000000000..30abe3e5e --- /dev/null +++ b/testcases/lib/tst_lockdown_enabled.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel <pvorel@suse.cz> + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + return tst_lockdown_enabled() <= 0; +} diff --git a/testcases/lib/tst_net.sh b/testcases/lib/tst_net.sh index e6bb09d81..6168db86b 100644 --- a/testcases/lib/tst_net.sh +++ b/testcases/lib/tst_net.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2014-2017 Oracle and/or its affiliates. All Rights Reserved. -# Copyright (c) 2016-2022 Petr Vorel <pvorel@suse.cz> +# Copyright (c) 2016-2023 Petr Vorel <pvorel@suse.cz> # Author: Alexey Kodanev <alexey.kodanev@oracle.com> [ -n "$TST_LIB_NET_LOADED" ] && return 0 @@ -59,7 +59,7 @@ tst_net_remote_tmpdir() tst_net_setup() { - [ "$TST_IPVER" = 6 ] && tst_net_require_ipv6 + [ "$TST_IPV6" ] && tst_net_require_ipv6 tst_net_remote_tmpdir [ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER @@ -73,52 +73,93 @@ tst_net_setup() fi } -if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then - tst_res TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)" - unset TST_PARSE_ARGS_CALLER -fi -if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then - tst_res TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)" - unset TST_SETUP_CALLER -fi -if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then - tst_res TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)" - unset TST_USAGE_CALLER -fi - -if [ -n "$TST_USE_LEGACY_API" ]; then - tst_net_read_opts "$@" -fi - # old vs. new API compatibility layer tst_res_() { [ -z "$TST_USE_LEGACY_API" ] && tst_res $@ || tst_resm $@ } + tst_brk_() { [ -z "$TST_USE_LEGACY_API" ] && tst_brk $@ || tst_brkm $@ } +# Detect IPv6 disabled via 1) CONFIG_IPV6=n or 2) ipv6.disable=1 kernel cmdline +# parameter or 3) sysctl net.ipv6.conf.all.disable_ipv6=1 (disables IPv6 on all +# interfaces (including both already created and later created). +# $TST_NET_IPV6_ENABLED: 1 on IPv6 enabled, 0 on IPv6 disabled. tst_net_detect_ipv6() { local type="${1:-lhost}" local cmd='[ -f /proc/net/if_inet6 ]' - local ret + local disabled iface ret if [ "$type" = "lhost" ]; then $cmd else tst_rhost_run -c "$cmd" fi - ret=$? - if [ $ret -eq 0 ]; then - TST_NET_IPV6_ENABLED=1 + if [ $? -ne 0 ]; then + TST_NET_IPV6_ENABLED=0 + tst_res_ TINFO "IPv6 disabled on $type via kernel command line or not compiled in" + return + fi + + cmd='cat /proc/sys/net/ipv6/conf/all/disable_ipv6' + if [ "$type" = "lhost" ]; then + disabled=$($cmd) + else + disabled=$(tst_rhost_run -c "$cmd") + fi + if [ $disabled = 1 ]; then + tst_res_ TINFO "IPv6 disabled on $type net.ipv6.conf.all.disable_ipv6=1" + TST_NET_IPV6_ENABLED=0 + return + fi + + TST_NET_IPV6_ENABLED=1 +} + +# Detect IPv6 disabled on interface via sysctl +# net.ipv6.conf.$iface.disable_ipv6=1. +# $TST_NET_IPV6_ENABLED: 1 on IPv6 enabled, 0 on IPv6 disabled. +# return: 0 on IPv6 enabled, 1 on IPv6 disabled. +tst_net_detect_ipv6_iface() +{ + [ "$TST_NET_IPV6_ENABLED" = 1 ] || return 1 + + local iface="$1" + local type="${2:-lhost}" + local check="cat /proc/sys/net/ipv6/conf/$iface/disable_ipv6" + local disabled + + if [ "$type" = "lhost" ]; then + disabled=$($check) else + disabled=$(tst_rhost_run -c "$check") + fi + if [ $disabled = 1 ]; then + tst_res_ TINFO "IPv6 disabled on $type on $iface" TST_NET_IPV6_ENABLED=0 - tst_res TINFO "IPv6 disabled on $type" + return 1 fi + + return 0 +} + +# Detect IPv6 disabled on used interfaces. +tst_net_check_ifaces_ipv6() +{ + local iface + + for iface in $(tst_get_ifaces); do + tst_net_detect_ipv6_iface $iface || return + done + + for iface in $(tst_get_ifaces rhost); do + tst_net_detect_ipv6_iface $iface rhost || return + done } tst_net_require_ipv6() @@ -131,18 +172,18 @@ init_ltp_netspace() local pid if [ ! -f /var/run/netns/ltp_ns -a -z "$LTP_NETNS" ]; then - tst_require_cmds ip ns_create ns_exec ns_ifmove + tst_require_cmds ip tst_ns_create tst_ns_exec tst_ns_ifmove tst_require_root tst_require_drivers veth ROD ip link add name ltp_ns_veth1 type veth peer name ltp_ns_veth2 - pid="$(ROD ns_create net,mnt)" + pid="$(ROD tst_ns_create net,mnt)" mkdir -p /var/run/netns ROD ln -s /proc/$pid/ns/net /var/run/netns/ltp_ns - ROD ns_exec $pid net,mnt mount --make-rprivate /sys - ROD ns_exec $pid net,mnt mount -t sysfs none /sys - ROD ns_ifmove ltp_ns_veth1 $pid - ROD ns_exec $pid net,mnt ip link set lo up + ROD tst_ns_exec $pid net,mnt mount --make-rprivate /sys + ROD tst_ns_exec $pid net,mnt mount -t sysfs none /sys + ROD tst_ns_ifmove ltp_ns_veth1 $pid + ROD tst_ns_exec $pid net,mnt ip link set lo up elif [ -n "$LTP_NETNS" ]; then tst_res_ TINFO "using not default LTP netns: '$LTP_NETNS'" fi @@ -150,10 +191,8 @@ init_ltp_netspace() LHOST_IFACES="${LHOST_IFACES:-ltp_ns_veth2}" RHOST_IFACES="${RHOST_IFACES:-ltp_ns_veth1}" - export TST_INIT_NETNS="no" - pid="$(echo $(readlink /var/run/netns/ltp_ns) | cut -f3 -d'/')" - export LTP_NETNS="${LTP_NETNS:-ns_exec $pid net,mnt}" + export LTP_NETNS="${LTP_NETNS:-tst_ns_exec $pid net,mnt}" tst_restore_ipaddr tst_restore_ipaddr rhost @@ -460,7 +499,7 @@ tst_ipaddr_un() ;; m) ! tst_is_int "$OPTARG" || [ "$OPTARG" -lt 0 ]|| [ "$OPTARG" -gt $max_net_id ] && \ - tst_brk TBROK "tst_ipaddr_un: -m must be integer <0,$max_net_id> ($OPTARG)" + tst_brk_ TBROK "tst_ipaddr_un: -m must be integer <0,$max_net_id> ($OPTARG)" [ "$OPTARG" -gt $max_net_id ] && \ tst_brk_ TBROK "tst_ipaddr_un: -m cannot be higher than $max_net_id ($OPTARG)" max_host_id="$OPTARG" @@ -481,16 +520,16 @@ tst_ipaddr_un() ! tst_is_int "$min_host_id" || ! tst_is_int "$max_host_id" || \ [ $min_host_id -lt 0 -o $min_host_id -gt $default_max ] || \ [ $max_host_id -lt 0 -o $max_host_id -gt $default_max ] && \ - tst_brk TBROK "tst_ipaddr_un: HOST_ID must be int in range <0,$default_max> ($min_host_id,$max_host_id)" + tst_brk_ TBROK "tst_ipaddr_un: HOST_ID must be int in range <0,$default_max> ($min_host_id,$max_host_id)" ! tst_is_int "$min_net_id" || ! tst_is_int "$max_net_id" || \ [ $min_net_id -lt 0 -o $min_net_id -gt $default_max ] || \ [ $max_net_id -lt 0 -o $max_net_id -gt $default_max ] && \ - tst_brk TBROK "tst_ipaddr_un: NET_ID must be int in range <0,$default_max> ($min_net_id,$max_net_id)" + tst_brk_ TBROK "tst_ipaddr_un: NET_ID must be int in range <0,$default_max> ($min_net_id,$max_net_id)" [ $min_host_id -gt $max_host_id ] && \ - tst_brk TBROK "tst_ipaddr_un: max HOST_ID ($max_host_id) must be >= min HOST_ID ($min_host_id)" + tst_brk_ TBROK "tst_ipaddr_un: max HOST_ID ($max_host_id) must be >= min HOST_ID ($min_host_id)" [ $min_net_id -gt $max_net_id ] && \ - tst_brk TBROK "tst_ipaddr_un: max NET_ID ($max_net_id) must be >= min NET_ID ($min_net_id)" + tst_brk_ TBROK "tst_ipaddr_un: max NET_ID ($max_net_id) must be >= min NET_ID ($min_net_id)" # counter host_range=$((max_host_id - min_host_id + 1)) @@ -533,7 +572,9 @@ tst_init_iface() local type="${1:-lhost}" local link_num="${2:-0}" local iface="$(tst_iface $type $link_num)" + tst_res_ TINFO "initialize '$type' '$iface' interface" + tst_net_detect_ipv6_iface $iface $type if [ "$type" = "lhost" ]; then if ip xfrm state 1>/dev/null 2>&1; then @@ -584,7 +625,7 @@ tst_add_ipaddr() d) action="del" ;; q) quiet=1 ;; s) lsafe="ROD"; rsafe="-s" ;; - *) tst_brk TBROK "tst_add_ipaddr: unknown option: $OPTARG" ;; + *) tst_brk_ TBROK "tst_add_ipaddr: unknown option: $OPTARG" ;; esac done shift $((OPTIND - 1)) @@ -593,6 +634,8 @@ tst_add_ipaddr() local link_num="${2:-0}" local iface=$(tst_iface $type $link_num) + tst_net_detect_ipv6_iface $iface $type + if [ "$TST_IPV6" ]; then dad="nodad" [ "$type" = "lhost" ] && mask=$IPV6_LPREFIX || mask=$IPV6_RPREFIX @@ -969,43 +1012,25 @@ tst_default_max_pkt() echo "$((mtu + mtu / 10))" } -[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh - -# detect IPv6 support on lhost for tests which don't use test links -tst_net_detect_ipv6 - -[ -n "$TST_NET_SKIP_VARIABLE_INIT" ] && return 0 - -# Management Link -[ -z "$RHOST" ] && TST_USE_NETNS="yes" -export RHOST="$RHOST" -export PASSWD="${PASSWD:-}" -# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead. -export LTP_RSH="${LTP_RSH:-ssh -nq}" - -# Test Links -# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix), -# but if you use IP/prefix form, /prefix will be removed by tst_net_vars. -IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}" -IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}" -IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}" -IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}" - -# tst_net_ip_prefix +# Setup LTP network. +# +# Used tools: +# * tst_net_ip_prefix # Strip prefix from IP address and save both If no prefix found sets # default prefix. -# -# tst_net_iface_prefix reads prefix and interface from rtnetlink. +# * tst_net_iface_prefix reads prefix and interface from rtnetlink. # If nothing found sets default prefix value. -# -# tst_net_vars exports environment variables related to test links and +# * tst_net_vars exports environment variables related to test links and # networks that aren't reachable through the test links. # # For full list of exported environment variables see: # tst_net_ip_prefix -h # tst_net_iface_prefix -h # tst_net_vars -h -if [ -z "$_tst_net_parse_variables" ]; then +tst_net_setup_network() +{ + tst_require_cmds tst_net_iface_prefix tst_net_ip_prefix tst_net_vars + eval $(tst_net_ip_prefix $IPV4_LHOST || echo "exit $?") eval $(tst_net_ip_prefix -r $IPV4_RHOST || echo "exit $?") @@ -1015,25 +1040,20 @@ if [ -z "$_tst_net_parse_variables" ]; then eval $(tst_net_ip_prefix $IPV6_LHOST || echo "exit $?") eval $(tst_net_ip_prefix -r $IPV6_RHOST || echo "exit $?") fi -fi -[ -n "$TST_USE_NETNS" -a "$TST_INIT_NETNS" != "no" ] && init_ltp_netspace + tst_net_use_netns && init_ltp_netspace -if [ -z "$_tst_net_parse_variables" ]; then eval $(tst_net_iface_prefix $IPV4_LHOST || echo "exit $?") eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV4_RHOST \ || echo "exit $?") + eval $(tst_net_vars $IPV4_LHOST/$IPV4_LPREFIX \ + $IPV4_RHOST/$IPV4_RPREFIX || echo "exit $?") if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + tst_net_check_ifaces_ipv6 eval $(tst_net_iface_prefix $IPV6_LHOST || echo "exit $?") eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV6_RHOST \ || echo "exit $?") - fi - - eval $(tst_net_vars $IPV4_LHOST/$IPV4_LPREFIX \ - $IPV4_RHOST/$IPV4_RPREFIX || echo "exit $?") - - if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then eval $(tst_net_vars $IPV6_LHOST/$IPV6_LPREFIX \ $IPV6_RHOST/$IPV6_RPREFIX || echo "exit $?") fi @@ -1043,9 +1063,56 @@ if [ -z "$_tst_net_parse_variables" ]; then tst_res_ TINFO "$IPV4_LHOST/$IPV4_LPREFIX -- $IPV4_RHOST/$IPV4_RPREFIX" tst_res_ TINFO "$IPV6_LHOST/$IPV6_LPREFIX -- $IPV6_RHOST/$IPV6_RPREFIX" - export _tst_net_parse_variables="yes" + if [ -n "$TST_USE_LEGACY_API" ]; then + [ "$TST_IPV6" ] && tst_net_require_ipv6 + tst_net_remote_tmpdir + fi +} + +[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh + +if [ -n "$TST_USE_LEGACY_API" ]; then + tst_net_read_opts "$@" +else + if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then + tst_res_ TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)" + unset TST_PARSE_ARGS_CALLER + fi + if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then + tst_res_ TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)" + unset TST_SETUP_CALLER + fi + if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then + tst_res_ TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)" + unset TST_USAGE_CALLER + fi fi +# detect IPv6 support on lhost for tests which don't use test links +tst_net_detect_ipv6 + +[ -n "$TST_NET_SKIP_VARIABLE_INIT" ] && return 0 + +# Management Link +[ -z "$RHOST" ] && TST_USE_NETNS="yes" +export RHOST="$RHOST" +export PASSWD="${PASSWD:-}" +# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead. +export LTP_RSH="${LTP_RSH:-ssh -nq}" + +# Test Links +# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix), +# but if you use IP/prefix form, /prefix will be removed by tst_net_vars. +IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}" +IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}" +IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}" +IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}" + +tst_net_setup_network + +# More information about network parameters can be found +# in the following document: testcases/network/stress/README + export TST_NET_DATAROOT="$LTPROOT/testcases/bin/datafiles" export TST_NETLOAD_CLN_REQUESTS="${TST_NETLOAD_CLN_REQUESTS:-10000}" @@ -1090,13 +1157,6 @@ export RHOST_HWADDRS="${RHOST_HWADDRS:-$(tst_get_hwaddrs rhost)}" export NS_ICMPV4_SENDER_DATA_MAXSIZE=1472 export NS_ICMPV6_SENDER_DATA_MAXSIZE=1452 -# More information about network parameters can be found -# in the following document: testcases/network/stress/README - -if [ -n "$TST_USE_LEGACY_API" ]; then - tst_net_remote_tmpdir -fi - if [ -z "$TST_USE_LEGACY_API" ] && ! tst_cmd_available ping6; then ping6() { diff --git a/testcases/kernel/containers/share/ns_common.h b/testcases/lib/tst_ns_common.h index 813cd3388..358db5141 100644 --- a/testcases/kernel/containers/share/ns_common.h +++ b/testcases/lib/tst_ns_common.h @@ -3,8 +3,8 @@ * Copyright (c) Linux Test Project, 2015-2023 */ -#ifndef __NS_COMMON_H__ -#define __NS_COMMON_H__ +#ifndef TST_NS_COMMON_H__ +#define TST_NS_COMMON_H__ #include <sched.h> #include "lapi/sched.h" @@ -39,4 +39,4 @@ static struct param *get_param(const char *name) return NULL; } -#endif +#endif /* TST_NS_COMMON_H__ */ diff --git a/testcases/lib/tst_ns_create.c b/testcases/lib/tst_ns_create.c new file mode 100644 index 000000000..1c6258cd1 --- /dev/null +++ b/testcases/lib/tst_ns_create.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Red Hat, Inc. + * Matus Marhefka <mmarhefk@redhat.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + * Copyright (c) Linux Test Project, 2020-2023 + */ + +/*\ + * [Description] + * + * Creates a child process in the new specified namespace(s), child is then + * daemonized and is running in the background. PID of the daemonized child + * process is printed on the stdout. As the new namespace(s) is(are) maintained + * by the daemonized child process it(they) can be removed by killing this + * process. + */ + +#define TST_NO_DEFAULT_MAIN + +#include <stdio.h> +#include <string.h> +#include "tst_test.h" +#include "tst_ns_common.h" + +extern struct tst_test *tst_test; + +static struct tst_test test = { + .forks_child = 1, /* Needed by SAFE_CLONE */ +}; + +static void print_help(void) +{ + int i; + + printf("usage: tst_ns_create <%s", params[0].name); + + for (i = 1; params[i].name; i++) + printf("|,%s", params[i].name); + + printf(">\n"); +} + +static void child_fn(void) +{ + int i; + + SAFE_SETSID(); + SAFE_CHDIR("/"); + + for (i = 0; i < SAFE_SYSCONF(_SC_OPEN_MAX); i++) + close(i); + + printf("pausing child\n"); + pause(); +} + +int main(int argc, char *argv[]) +{ + struct tst_clone_args args = { 0, SIGCHLD }; + char *token; + int pid; + + if (argc < 2) { + print_help(); + return 1; + } + + tst_test = &test; + + while ((token = strsep(&argv[1], ","))) { + struct param *p = get_param(token); + + if (!p) { + printf("Unknown namespace: %s\n", token); + print_help(); + return 1; + } + + args.flags |= p->flag; + } + + pid = SAFE_CLONE(&args); + if (!pid) { + child_fn(); + return 0; + } + + printf("%d", pid); + + return 0; +} diff --git a/testcases/lib/tst_ns_exec.c b/testcases/lib/tst_ns_exec.c new file mode 100644 index 000000000..66a4e69d3 --- /dev/null +++ b/testcases/lib/tst_ns_exec.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Red Hat, Inc. + * Matus Marhefka <mmarhefk@redhat.com> + * Copyright (c) Linux Test Project, 2015-2023 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * Enters the namespace(s) of a process specified by a PID and then executes + * the indicated program inside that namespace(s). + */ + +#define TST_NO_DEFAULT_MAIN + +#include <stdio.h> +#include <sys/wait.h> +#include "tst_test.h" +#include "tst_ns_common.h" + +extern struct tst_test *tst_test; + +static struct tst_test test = { + .forks_child = 1, /* Needed by SAFE_CLONE */ +}; + +static int ns_fd[NS_TOTAL]; +static int ns_fds; + +static void print_help(void) +{ + int i; + + printf("usage: tst_ns_exec <NS_PID> <%s", params[0].name); + + for (i = 1; params[i].name; i++) + printf("|,%s", params[i].name); + + printf("> <PROGRAM> [ARGS]\nSecond argument indicates the types" + " of a namespaces maintained by NS_PID\nand is specified" + " as a comma separated list.\n" + "Example: tst_ns_exec 1234 net,ipc ip a\n"); +} + +static void open_ns_fd(const char *pid, const char *ns) +{ + int fd; + char file_buf[64]; + + sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns); + + fd = SAFE_OPEN(file_buf, O_RDONLY); + ns_fd[ns_fds] = fd; + + ++ns_fds; +} + +static void close_ns_fd(void) +{ + int i; + + for (i = 0; i < ns_fds; i++) + SAFE_CLOSE(ns_fd[i]); +} + +int main(int argc, char *argv[]) +{ + struct tst_clone_args args = { 0, SIGCHLD }; + int i, status, pid; + char *token; + + tst_test = &test; + + if (argc < 4) { + print_help(); + return 1; + } + + memset(ns_fd, 0, sizeof(ns_fd)); + + while ((token = strsep(&argv[2], ","))) { + struct param *p = get_param(token); + + if (!p) { + printf("Unknown namespace: %s\n", token); + print_help(); + return 1; + } + + open_ns_fd(argv[1], token); + } + + if (!ns_fds) { + printf("no namespace entries in /proc/%s/ns/\n", argv[1]); + return 1; + } + + for (i = 0; i < ns_fds; i++) + SAFE_SETNS(ns_fd[i], 0); + + pid = SAFE_CLONE(&args); + if (!pid) + SAFE_EXECVP(argv[3], argv+3); + + SAFE_WAITPID(pid, &status, 0); + + close_ns_fd(); + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + + return 0; +} diff --git a/testcases/lib/tst_ns_ifmove.c b/testcases/lib/tst_ns_ifmove.c new file mode 100644 index 000000000..03531fc9b --- /dev/null +++ b/testcases/lib/tst_ns_ifmove.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2015 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2015-2022 + * Copyright (c) 2023 Petr Vorel <pvorel@suse.cz> + * Written by Matus Marhefka <mmarhefk@redhat.com> + */ + +/*\ + * [Description] + * + * Moves a network interface to the namespace of a process specified by a PID. + */ + +#include "config.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_safe_net.h" + +#include <linux/if.h> +#include <linux/rtnetlink.h> +#include <net/ethernet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_DECL_IFLA_NET_NS_PID + +static struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + char attrbuf[512]; +} req; + + +static int get_intf_index_from_name(const char *intf_name) +{ + struct ifreq ifr; + int sock_fd; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, intf_name, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; + + sock_fd = SAFE_SOCKET(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + /* interface index */ + SAFE_IOCTL(sock_fd, SIOCGIFINDEX, &ifr); + SAFE_CLOSE(sock_fd); + + return ifr.ifr_ifindex; +} + +int main(int argc, char **argv) +{ + struct rtattr *rta; + int intf_index, pid, rtnetlink_socket; + + if (argc != 3) { + printf("tst_ns_ifmove <INTERFACE_NAME> <NAMESPACE_PID>\n"); + return 1; + } + + intf_index = get_intf_index_from_name(argv[1]); + pid = atoi(argv[2]); + rtnetlink_socket = SAFE_SOCKET(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST; + req.nh.nlmsg_type = RTM_NEWLINK; + req.ifi.ifi_family = AF_UNSPEC; + req.ifi.ifi_index = intf_index; + req.ifi.ifi_change = 0xffffffff; + rta = (struct rtattr *)(((char *) &req) + + NLMSG_ALIGN(req.nh.nlmsg_len)); + rta->rta_type = IFLA_NET_NS_PID; + rta->rta_len = RTA_LENGTH(sizeof(int)); + req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + + RTA_LENGTH(sizeof(pid)); + memcpy(RTA_DATA(rta), &pid, sizeof(pid)); + + SAFE_SEND(1, rtnetlink_socket, &req, req.nh.nlmsg_len, 0); + SAFE_CLOSE(rtnetlink_socket); + + return 0; +} + +#else + TST_TEST_TCONF("IFLA_NET_NS_PID not defined in linux/if_link.h"); +#endif diff --git a/testcases/lib/tst_secureboot_enabled.c b/testcases/lib/tst_secureboot_enabled.c new file mode 100644 index 000000000..dadc0413c --- /dev/null +++ b/testcases/lib/tst_secureboot_enabled.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel <pvorel@suse.cz> + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + return tst_secureboot_enabled() <= 0; +} diff --git a/testcases/lib/tst_test.sh b/testcases/lib/tst_test.sh index 3bd68a63a..b3f451a21 100644 --- a/testcases/lib/tst_test.sh +++ b/testcases/lib/tst_test.sh @@ -532,7 +532,7 @@ _tst_cleanup_timer() { if [ -n "$_tst_setup_timer_pid" ]; then kill -TERM $_tst_setup_timer_pid 2>/dev/null - # kill is succesful only on test timeout + # kill is successful only on test timeout wait $_tst_setup_timer_pid 2>/dev/null || true fi } @@ -682,7 +682,7 @@ tst_run() CHECKPOINT_WAIT|CHECKPOINT_WAKE);; CHECKPOINT_WAKE2|CHECKPOINT_WAKE_AND_WAIT);; DEV_EXTRA_OPTS|DEV_FS_OPTS|FORMAT_DEVICE|MOUNT_DEVICE);; - SKIP_FILESYSTEMS);; + SKIP_FILESYSTEMS|SKIP_IN_LOCKDOWN|SKIP_IN_SECUREBOOT);; *) tst_res TWARN "Reserved variable TST_$_tst_i used!";; esac done @@ -702,6 +702,14 @@ tst_run() [ "$TST_NEEDS_ROOT" = 1 ] && tst_require_root + if [ "$TST_SKIP_IN_SECUREBOOT" = 1 ] && tst_secureboot_enabled; then + tst_brk TCONF "SecureBoot enabled, skipping test" + fi + + if [ "$TST_SKIP_IN_LOCKDOWN" = 1 ] && tst_lockdown_enabled; then + tst_brk TCONF "Kernel is locked down, skipping test" + fi + [ "$TST_DISABLE_APPARMOR" = 1 ] && tst_disable_apparmor [ "$TST_DISABLE_SELINUX" = 1 ] && tst_disable_selinux @@ -726,6 +734,8 @@ tst_run() fi TST_TMPDIR=$(mktemp -d "$TMPDIR/LTP_$TST_ID.XXXXXXXXXX") + # remove possible trailing slash or double slashes from TMPDIR + TST_TMPDIR=$(echo "$TST_TMPDIR" | sed 's~/\+~/~g') chmod 777 "$TST_TMPDIR" diff --git a/testcases/network/iptables/iptables_lib.sh b/testcases/network/iptables/iptables_lib.sh index ab76cbd41..767008869 100755 --- a/testcases/network/iptables/iptables_lib.sh +++ b/testcases/network/iptables/iptables_lib.sh @@ -22,7 +22,7 @@ NFRUN() if [ "$use_iptables" = 1 ]; then ip${TST_IPV6}tables $@ else - $(ip${TST_IPV6}tables-translate $@ | sed 's,\\,,g') + $(ip${TST_IPV6}tables-translate $@ | sed "s/[\']//g") fi } @@ -66,9 +66,9 @@ init() cleanup() { if lsmod | grep -q "ip${TST_IPV6}_tables"; then - NFTRUN -F -t filter > /dev/null 2>&1 - NFTRUN -F -t nat > /dev/null 2>&1 - NFTRUN -F -t mangle > /dev/null 2>&1 + NFRUN -F -t filter > /dev/null 2>&1 + NFRUN -F -t nat > /dev/null 2>&1 + NFRUN -F -t mangle > /dev/null 2>&1 rmmod -v ipt_limit ipt_multiport ipt_LOG ipt_REJECT \ ip${TST_IPV6}table_mangle ip${TST_IPV6}table_nat ip_conntrack \ ip${TST_IPV6}table_filter ip${TST_IPV6}_tables nf_nat_ipv${TST_IPVER} nf_nat \ diff --git a/testcases/network/lib6/asapi_01.c b/testcases/network/lib6/asapi_01.c index a34b8aee6..ac1de5418 100644 --- a/testcases/network/lib6/asapi_01.c +++ b/testcases/network/lib6/asapi_01.c @@ -33,7 +33,7 @@ #include "test.h" #include "safe_macros.h" -char *TCID = "asapi_04"; +char *TCID = "asapi_01"; static pid_t pid; diff --git a/testcases/network/lib6/asapi_02.c b/testcases/network/lib6/asapi_02.c index f8c30f1df..7808b2c3a 100644 --- a/testcases/network/lib6/asapi_02.c +++ b/testcases/network/lib6/asapi_02.c @@ -1,102 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2015 Fujitsu Ltd. + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. * Copyright (c) International Business Machines Corp., 2001 + * Author: David L Stevens + */ + +/*\ + * [Description] * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Basic test for ICMP6_FILTER. * - * This program 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 General Public License for more details. + * For ICMP6_FILTER usage, refer to: https://man.openbsd.org/icmp6. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * Because of the extra functionality of ICMPv6 in comparison to ICMPv4, a + * larger number of messages may be potentially received on an ICMPv6 socket. + * Input filters may therefore be used to restrict input to a subset of the + * incoming ICMPv6 messages so only interesting messages are returned by the + * recv(2) family of calls to an application. + + * The icmp6_filter structure may be used to refine the input message set + * according to the ICMPv6 type. By default, all messages types are allowed + * on newly created raw ICMPv6 sockets. The following macros may be used to + * refine the input set, thus being tested: * - * Author: David L Stevens + * void ICMP6_FILTER_SETPASSALL(struct icmp6_filter *filterp) + * – Allow all incoming messages. filterp is modified to allow all message types. + * + * void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *filterp) + * – Ignore all incoming messages. filterp is modified to ignore all message types. + * + * void ICMP6_FILTER_SETPASS(int, struct icmp6_filter *filterp) + * – Allow ICMPv6 messages with the given type. filterp is modified to allow such + * messages. + * + * void ICMP6_FILTER_SETBLOCK(int, struct icmp6_filter *filterp) + * – Ignore ICMPv6 messages with the given type. filterp is modified to ignore + * such messages. + * + * int ICMP6_FILTER_WILLPASS(int, const struct icmp6_filter *filterp) + * – Determine if the given filter will allow an ICMPv6 message of the given type. + * + * int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *) + * – Determine if the given filter will ignore an ICMPv6 message of the given type. + * + * The getsockopt(2) and setsockopt(2) calls may be used to obtain and install + * the filter on ICMPv6 sockets at option level IPPROTO_ICMPV6 and name ICMP6_FILTER + * with a pointer to the icmp6_filter structure as the option value. */ -#include <stdio.h> -#include <unistd.h> -#include <errno.h> - -#include <sys/wait.h> -#include <sys/socket.h> - -#include <netinet/in.h> -#include <netinet/ip6.h> #include <netinet/icmp6.h> +#include "tst_test.h" -#include "test.h" -#include "safe_macros.h" +static int sall = -1, sf = -1; -char *TCID = "asapi_05"; - -static void setup(void); - -static void icmp6_ft(void); - -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) - icmp6_ft(); - - tst_exit(); -} - -static void setup(void) -{ - TEST_PAUSE; - tst_require_root(); -} - -enum tt { - T_WILLPASS, - T_WILLBLOCK, - T_SETPASS, - T_SETBLOCK, - T_SETPASSALL, - T_SETBLOCKALL +enum filter_macro { + FILTER_SETPASS, + FILTER_SETBLOCK, + FILTER_PASSALL, + FILTER_BLOCKALL, + FILTER_WILLBLOCK, + FILTER_WILLPASS }; -static struct ftent { - char *ft_tname; /* test name, for logging */ - unsigned char ft_sndtype; /* send type field */ - unsigned char ft_flttype; /* filter type field */ - enum tt ft_test; /* what macro to test */ - int ft_expected; /* packet should pass? */ -} ftab[] = { - {"ICMP6_FILTER_SETPASS s 20 f 20", 20, 20, T_SETPASS, 1}, - {"ICMP6_FILTER_SETPASS s 20 f 21", 20, 21, T_SETPASS, 0}, - {"ICMP6_FILTER_SETBLOCK s 20 f 20", 20, 20, T_SETBLOCK, 0}, - {"ICMP6_FILTER_SETBLOCK s 20 f 21", 20, 21, T_SETBLOCK, 1}, - {"ICMP6_FILTER_PASSALL s 20", 20, 0, T_SETPASSALL, 1}, - {"ICMP6_FILTER_PASSALL s 20", 21, 0, T_SETPASSALL, 1}, - {"ICMP6_FILTER_BLOCKALL s 20", 20, 0, T_SETBLOCKALL, 0}, - {"ICMP6_FILTER_BLOCKALL s 20", 21, 0, T_SETBLOCKALL, 0}, - {"ICMP6_FILTER_WILLBLOCK s 20 f 21", 20, 21, T_WILLBLOCK, 0}, - {"ICMP6_FILTER_WILLBLOCK s 20 f 20", 20, 20, T_WILLBLOCK, 1}, - {"ICMP6_FILTER_WILLPASS s 20 f 21", 20, 21, T_WILLPASS, 0}, - {"ICMP6_FILTER_WILLPASS s 22 f 22", 22, 22, T_WILLPASS, 1}, +#define DESC(x, y, z) .tname = "ICMP6_" #x ", send type: " #y ", filter type: " \ + #z, .send_type = y, .filter_type = z, .test_macro = x + +static struct tcase { + char *tname; + unsigned char send_type; + unsigned char filter_type; + enum filter_macro test_macro; + int pass_packet; +} tcases[] = { + {DESC(FILTER_SETPASS, 20, 20), .pass_packet = 1}, + {DESC(FILTER_SETPASS, 20, 21)}, + {DESC(FILTER_SETBLOCK, 20, 20)}, + {DESC(FILTER_SETBLOCK, 20, 21), .pass_packet = 1}, + {DESC(FILTER_PASSALL, 20, 20), .pass_packet = 1}, + {DESC(FILTER_PASSALL, 21, 0), .pass_packet = 1}, + {DESC(FILTER_BLOCKALL, 20, 0)}, + {DESC(FILTER_BLOCKALL, 21, 0)}, + {DESC(FILTER_WILLBLOCK, 20, 21)}, + {DESC(FILTER_WILLBLOCK, 20, 20), .pass_packet = 1}, + {DESC(FILTER_WILLPASS, 20, 21)}, + {DESC(FILTER_WILLPASS, 22, 22), .pass_packet = 1}, }; -#define FTCOUNT ARRAY_SIZE(ftab) - -static int ic6_send1(char *tname, unsigned char type) +static void ic6_send(unsigned char type) { struct sockaddr_in6 sin6; struct icmp6_hdr ic6; int s; - s = SAFE_SOCKET(NULL, AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + s = SAFE_SOCKET(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); memset(&ic6, 0, sizeof(ic6)); ic6.icmp6_type = type; @@ -105,22 +101,15 @@ static int ic6_send1(char *tname, unsigned char type) memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_addr = in6addr_loopback; - if (sendto(s, &ic6, sizeof(ic6), 0, (struct sockaddr *)&sin6, - sizeof(sin6)) == -1) { - tst_resm(TBROK | TERRNO, "%s: sendto failed", tname); - return 1; - } - return 0; + SAFE_SENDTO(0, s, &ic6, sizeof(ic6), 0, (struct sockaddr *)&sin6, sizeof(sin6)); } -static int ic6_recv1(char *tname, int sall, int sf) +static int ic6_recv(void) { fd_set readfds, readfds_saved; struct timeval tv; - int maxfd, nfds; - int gotall, gotone; - int cc; - static unsigned char rbuf[2048]; + int maxfd, nfds, gotall, gotone; + unsigned char rbuf[2048]; tv.tv_sec = 0; tv.tv_usec = 250000; @@ -133,129 +122,120 @@ static int ic6_recv1(char *tname, int sall, int sf) memcpy(&readfds, &readfds_saved, sizeof(readfds)); gotall = gotone = 0; - /* - * Note: this relies on linux-specific behavior (select - * updating tv with time elapsed) - */ + while (!gotall || !gotone) { struct icmp6_hdr *pic6 = (struct icmp6_hdr *)rbuf; nfds = select(maxfd + 1, &readfds, 0, 0, &tv); if (nfds == 0) - break; /* timed out */ + break; + if (nfds < 0) { if (errno == EINTR) continue; - tst_resm(TBROK | TERRNO, "%s: select failed", tname); + tst_brk(TBROK | TERRNO, "select failed"); } + if (FD_ISSET(sall, &readfds)) { - cc = recv(sall, rbuf, sizeof(rbuf), 0); - if (cc < 0) { - tst_resm(TBROK | TERRNO, - "%s: recv(sall, ..) failed", tname); - return -1; - } - /* if packet check succeeds... */ + SAFE_RECV(0, sall, rbuf, sizeof(rbuf), 0); if (htonl(pic6->icmp6_data32[0]) == (uint32_t)getpid()) gotall = 1; } + if (FD_ISSET(sf, &readfds)) { - cc = recv(sf, rbuf, sizeof(rbuf), 0); - if (cc < 0) { - tst_resm(TBROK | TERRNO, - "%s: recv(sf, ..) failed", tname); - return -1; - } - /* if packet check succeeds... */ + SAFE_RECV(0, sf, rbuf, sizeof(rbuf), 0); if (htonl(pic6->icmp6_data32[0]) == (uint32_t)getpid()) gotone = 1; } memcpy(&readfds, &readfds_saved, sizeof(readfds)); } + if (!gotall) { - tst_resm(TBROK, "%s: recv all timed out", tname); + tst_res(TFAIL, "recv all time out"); return -1; } + if (gotone) return 1; + return 0; } -/* functional tests */ -static void icmp6_ft(void) +static void verify_icmp6_filter(unsigned int n) { + struct tcase *tc = &tcases[n]; struct icmp6_filter i6f; - int sall, sf; - unsigned int i; + int rc; + + tst_res(TINFO, "Testing %s", tc->tname); + + switch (tc->test_macro) { + case FILTER_SETPASS: + ICMP6_FILTER_SETBLOCKALL(&i6f); + ICMP6_FILTER_SETPASS(tc->filter_type, &i6f); + break; + case FILTER_PASSALL: + ICMP6_FILTER_SETPASSALL(&i6f); + break; + case FILTER_SETBLOCK: + ICMP6_FILTER_SETPASSALL(&i6f); + ICMP6_FILTER_SETBLOCK(tc->filter_type, &i6f); + break; + case FILTER_BLOCKALL: + ICMP6_FILTER_SETBLOCKALL(&i6f); + break; + case FILTER_WILLBLOCK: + ICMP6_FILTER_SETPASSALL(&i6f); + ICMP6_FILTER_SETBLOCK(tc->filter_type, &i6f); + rc = ICMP6_FILTER_WILLBLOCK(tc->send_type, &i6f); + TST_EXP_EXPR(rc == tc->pass_packet, "%d (%d)", tc->pass_packet, rc); + return; + case FILTER_WILLPASS: + ICMP6_FILTER_SETBLOCKALL(&i6f); + ICMP6_FILTER_SETPASS(tc->filter_type, &i6f); + rc = ICMP6_FILTER_WILLPASS(tc->send_type, &i6f); + TST_EXP_EXPR(rc == tc->pass_packet, "%d (%d)", tc->pass_packet, rc); + return; + default: + tst_brk(TBROK, "unknown test type %d", tc->filter_type); + break; + } - sall = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + SAFE_SETSOCKOPT(sf, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)); + ic6_send(tc->send_type); - ICMP6_FILTER_SETPASSALL(&i6f); - if (setsockopt(sall, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, - sizeof(i6f)) < 0) { - tst_resm(TBROK | TERRNO, - "setsockopt pass all ICMP6_FILTER failed"); - } + rc = ic6_recv(); + if (rc < 0) + return; - sf = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + TST_EXP_EXPR(rc == tc->pass_packet, "%s packet type %d", + rc ? "pass" : "block", tc->send_type); +} - int rv; +static void setup(void) +{ + struct icmp6_filter i6f; - for (i = 0; i < FTCOUNT; ++i) { + sall = SAFE_SOCKET(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + ICMP6_FILTER_SETPASSALL(&i6f); + SAFE_SETSOCKOPT(sall, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)); - rv = -1; + sf = SAFE_SOCKET(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); +} - switch (ftab[i].ft_test) { - case T_SETPASS: - ICMP6_FILTER_SETBLOCKALL(&i6f); - ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); - break; - case T_SETPASSALL: - ICMP6_FILTER_SETPASSALL(&i6f); - break; - case T_SETBLOCK: - ICMP6_FILTER_SETPASSALL(&i6f); - ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); - break; - case T_SETBLOCKALL: - ICMP6_FILTER_SETBLOCKALL(&i6f); - break; - case T_WILLBLOCK: - ICMP6_FILTER_SETPASSALL(&i6f); - ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); - rv = ICMP6_FILTER_WILLBLOCK(ftab[i].ft_sndtype, &i6f); - break; - case T_WILLPASS: - ICMP6_FILTER_SETBLOCKALL(&i6f); - ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); - rv = ICMP6_FILTER_WILLPASS(ftab[i].ft_sndtype, &i6f); - break; - default: - tst_resm(TBROK, "%s: unknown test type %d", - ftab[i].ft_tname, ftab[i].ft_test); - continue; - } - if (ftab[i].ft_test != T_WILLBLOCK && - ftab[i].ft_test != T_WILLPASS) { - if (setsockopt(sf, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, - sizeof(i6f)) < 0) { - tst_resm(TFAIL | TERRNO, - "setsockopt ICMP6_FILTER"); - continue; - } - if (ic6_send1(ftab[i].ft_tname, ftab[i].ft_sndtype)) - continue; - rv = ic6_recv1(ftab[i].ft_tname, sall, sf); - } else { - rv = -1; - } +static void cleanup(void) +{ + if (sall > -1) + SAFE_CLOSE(sall); - if (rv < 0) - continue; - if (rv != ftab[i].ft_expected) - tst_resm(TFAIL, "%s: rv %d != expected %d", - ftab[i].ft_tname, rv, ftab[i].ft_expected); - else - tst_resm(TPASS, "%s", ftab[i].ft_tname); - } + if (sf > -1) + SAFE_CLOSE(sf); } + +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test = verify_icmp6_filter, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/network/lib6/asapi_03.c b/testcases/network/lib6/asapi_03.c index 2124ba7d9..87d050add 100644 --- a/testcases/network/lib6/asapi_03.c +++ b/testcases/network/lib6/asapi_03.c @@ -43,7 +43,7 @@ #include "test.h" #include "safe_macros.h" -char *TCID = "asapi_06"; +char *TCID = "asapi_03"; int TST_TOTAL = 1; diff --git a/testcases/network/netstress/netstress.c b/testcases/network/netstress/netstress.c index 6a888f2ee..fb6281cd0 100644 --- a/testcases/network/netstress/netstress.c +++ b/testcases/network/netstress/netstress.c @@ -384,6 +384,7 @@ void *client_fn(void *id) inf.raddr_len = sizeof(inf.raddr); inf.etime_cnt = 0; + inf.eshutdown_cnt = 0; inf.timeout = wait_timeout; inf.pmtu_err_cnt = 0; diff --git a/testcases/network/nfs/nfs_stress/Makefile b/testcases/network/nfs/nfs_stress/Makefile index 8cd095867..5b396dede 100644 --- a/testcases/network/nfs/nfs_stress/Makefile +++ b/testcases/network/nfs/nfs_stress/Makefile @@ -9,13 +9,6 @@ include $(top_srcdir)/include/mk/testcases.mk nfs04_create_file: CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE nfs05_make_tree: LDLIBS += -lpthread -INSTALL_TARGETS := nfs_lib.sh \ - nfs01.sh \ - nfs02.sh \ - nfs03.sh \ - nfs04.sh \ - nfs05.sh \ - nfs06.sh \ - nfs07.sh +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/network/nfs/nfs_stress/nfs03.sh b/testcases/network/nfs/nfs_stress/nfs03.sh index e5f4de67c..e9ef5fb78 100755 --- a/testcases/network/nfs/nfs_stress/nfs03.sh +++ b/testcases/network/nfs/nfs_stress/nfs03.sh @@ -66,11 +66,13 @@ do_test() cd ../dir1 wait $pid1 rm_files & + pid3=$! tst_res TINFO "cd dir2 & removing files" cd ../dir2 wait $pid2 rm_files + wait $pid3 tst_res TPASS "test done" } diff --git a/testcases/network/nfs/nfs_stress/nfs05.sh b/testcases/network/nfs/nfs_stress/nfs05.sh index c18ef1ab4..760b585e4 100755 --- a/testcases/network/nfs/nfs_stress/nfs05.sh +++ b/testcases/network/nfs/nfs_stress/nfs05.sh @@ -8,9 +8,9 @@ # # Created by: Robbie Williamson (robbiew@us.ibm.com) -DIR_NUM=${DIR_NUM:-"10"} -FILE_NUM=${FILE_NUM:-"30"} -THREAD_NUM=${THREAD_NUM:-"8"} +DIR_NUM=${DIR_NUM:-"5"} +FILE_NUM=${FILE_NUM:-"20"} +THREAD_NUM=${THREAD_NUM:-"5"} TST_NEEDS_CMDS="make gcc" TST_TESTFUNC="do_test" diff --git a/testcases/network/nfs/nfs_stress/nfs06.sh b/testcases/network/nfs/nfs_stress/nfs06.sh index d51f7dc82..560df05b1 100755 --- a/testcases/network/nfs/nfs_stress/nfs06.sh +++ b/testcases/network/nfs/nfs_stress/nfs06.sh @@ -11,7 +11,8 @@ TST_TESTFUNC="do_test" TST_CLEANUP="do_cleanup" -THREAD_NUM=${THREAD_NUM:-"2"} +THREAD_NUM="${THREAD_NUM:-2}" +OPERATION_NUM="${OPERATION_NUM:-1000}" do_cleanup() { @@ -26,7 +27,7 @@ do_test() local n=0 local pids for i in $VERSION; do - fsstress -l 1 -d $TST_TMPDIR/$i/$n -n 1000 -p $THREAD_NUM -r -c > /dev/null & + fsstress -l 1 -d $TST_TMPDIR/$i/$n -n $OPERATION_NUM -p $THREAD_NUM -r -c > /dev/null & pids="$pids $!" n=$(( n + 1 )) done diff --git a/testcases/network/nfs/nfs_stress/nfs08.sh b/testcases/network/nfs/nfs_stress/nfs08.sh new file mode 100755 index 000000000..759b4e418 --- /dev/null +++ b/testcases/network/nfs/nfs_stress/nfs08.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 Petr Vorel <pvorel@suse.cz> +# Test for broken NFS cache invalidation for directories. +# Kernel patch broke cache invalidation, which caused the second 'ls' +# not shown '2'. +# https://lore.kernel.org/linux-nfs/167649314509.15170.15885497881041431304@noble.neil.brown.name/ +# Based on reproducer from Neil Brown <neilb@suse.de> + +TST_TESTFUNC="do_test" + +do_test() +{ + tst_res TINFO "testing NFS cache invalidation for directories" + + touch 1 + EXPECT_PASS 'ls | grep 1' + touch 2 + EXPECT_PASS 'ls | grep 2' +} + +. nfs_lib.sh +tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs_lib.sh b/testcases/network/nfs/nfs_stress/nfs_lib.sh index af7d46a21..a996f7cc8 100644 --- a/testcases/network/nfs/nfs_stress/nfs_lib.sh +++ b/testcases/network/nfs/nfs_stress/nfs_lib.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) Linux Test Project, 2016-2022 +# Copyright (c) Linux Test Project, 2016-2023 # Copyright (c) 2015-2018 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2001 @@ -28,7 +28,10 @@ NFS_PARSE_ARGS_CALLER="$TST_PARSE_ARGS" TST_OPTS="v:t:$TST_OPTS" TST_PARSE_ARGS=nfs_parse_args TST_USAGE=nfs_usage -TST_NEEDS_TMPDIR=1 +TST_ALL_FILESYSTEMS=1 +TST_SKIP_FILESYSTEMS="exfat,ext2,ext3,fuse,ntfs,vfat,tmpfs" +TST_MOUNT_DEVICE=1 +TST_FORMAT_DEVICE=1 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="$TST_NEEDS_CMDS mount exportfs mount.nfs" TST_SETUP="${TST_SETUP:-nfs_setup}" @@ -53,6 +56,24 @@ get_socket_type() done } +# directory mounted by NFS client +get_local_dir() +{ + local v="$1" + local n="$2" + + echo "$TST_TMPDIR/$v/$n" +} + +# directory on NFS server +get_remote_dir() +{ + local v="$1" + local n="$2" + + echo "$TST_MNTPOINT/$v/$n" +} + nfs_get_remote_path() { local v @@ -63,7 +84,7 @@ nfs_get_remote_path() done v=${1:-$v} - echo "$TST_TMPDIR/$v/$type" + echo "$(get_remote_dir $v $type)" } nfs_server_udp_enabled() @@ -78,8 +99,8 @@ nfs_server_udp_enabled() nfs_setup_server() { - - local fsid="$1" + local remote_dir="$1" + local fsid="$2" local export_cmd="exportfs -i -o fsid=$fsid,no_root_squash,rw *:$remote_dir" [ -z "$fsid" ] && tst_brk TBROK "empty fsid" @@ -97,10 +118,14 @@ nfs_setup_server() nfs_mount() { - local opts="$1" + local local_dir="$1" + local remote_dir="$2" + local opts="$3" local host_type=rhost local mount_dir + mkdir -p "$local_dir" + tst_net_use_netns && host_type= if [ $TST_IPV6 ]; then @@ -131,6 +156,8 @@ nfs_mount() tst_brk TBROK "mount command failed" fi + + cd "$local_dir" } nfs_setup() @@ -162,20 +189,14 @@ nfs_setup() tst_brk TCONF "UDP support disabled on NFS server" fi - local_dir="$TST_TMPDIR/$i/$n" - remote_dir="$TST_TMPDIR/$i/$type" - mkdir -p $local_dir - - nfs_setup_server $(($$ + n)) - - nfs_mount "-o proto=$type,vers=$i" + remote_dir="$(get_remote_dir $i $type)" + nfs_setup_server "$remote_dir" "$(($$ + n))" + local_dir="$(get_local_dir $i $n)" + tst_res TINFO "Mounting $local_dir" + nfs_mount "$local_dir" "$remote_dir" "-o proto=$type,vers=$i" n=$(( n + 1 )) done - - if [ "$n" -eq 1 ]; then - cd ${VERSION}/0 - fi } nfs_cleanup() @@ -190,17 +211,32 @@ nfs_cleanup() local n=0 for i in $VERSION; do - local_dir="$TST_TMPDIR/$i/$n" - grep -q "$local_dir" /proc/mounts && umount $local_dir + local_dir="$(get_local_dir $i $n)" + if grep -q "$local_dir" /proc/mounts; then + tst_res TINFO "Unmounting $local_dir" + umount $local_dir + fi n=$(( n + 1 )) done + sleep 2 n=0 for i in $VERSION; do type=$(get_socket_type $n) - remote_dir="$TST_TMPDIR/$i/$type" - tst_rhost_run -c "test -d $remote_dir && exportfs -u *:$remote_dir" - tst_rhost_run -c "test -d $remote_dir && rm -rf $remote_dir" + remote_dir="$(get_remote_dir $i $type)" + + if tst_net_use_netns; then + if test -d $remote_dir; then + exportfs -u *:$remote_dir + sleep 1 + rm -rf $remote_dir + fi + else + tst_rhost_run -c "test -d $remote_dir && exportfs -u *:$remote_dir" + sleep 1 + tst_rhost_run -c "test -d $remote_dir && rm -rf $remote_dir" + fi + n=$(( n + 1 )) done } diff --git a/testcases/network/nfs/nfslock01/nfs_flock.c b/testcases/network/nfs/nfslock01/nfs_flock.c index a7673c751..02f105b22 100644 --- a/testcases/network/nfs/nfslock01/nfs_flock.c +++ b/testcases/network/nfs/nfslock01/nfs_flock.c @@ -1,7 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2001-2023 + * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] + * * Program for testing file locking. The original data file consists of * characters from 'A' to 'Z'. The data file after running this program * would consist of lines with 1's in even lines and 0's in odd lines. + * + * Used in nfslock01.sh. */ #include "nfs_flock.h" @@ -10,69 +20,91 @@ #include <stdlib.h> #include <unistd.h> -#define BYTES 64 -#define LINES 16384 - int main(int argc, char **argv) { - int i, fd, mac; + int i, fd, mac, nchars, nlines; int offset = 0; char buf[BUFSIZ]; - if (argc != 3) { - fprintf(stderr, "Usage: %s <mac num> <file name>\n", argv[0]); + if (argc != 5) { + fprintf(stderr, "Usage: %s <mac num> <file name> <nchars> <nlines>\n", + argv[0]); exit(2); } - if ((fd = open(argv[2], O_RDWR)) < 0) { + fd = open(argv[2], O_RDWR); + if (fd < 0) { perror("opening a file"); exit(1); } mac = atoi(argv[1]); + nchars = atoi(argv[3]); + nlines = atoi(argv[4]); + + if (nchars > BUFSIZ) { + fprintf(stderr, "Exceeded the maximum limit of the buffer (%d)\n", BUFSIZ); + exit(3); + } + + if (nchars < 1) { + fprintf(stderr, "<char/line> must be > 0\n"); + exit(3); + } + + if (nlines < 1) { + fprintf(stderr, "<lines> must be > 0\n"); + exit(3); + } /* * Replace a line of characters by 1's if it is process one - * else with 0's. Number of charcters in any line are BYTES-1, + * else with 0's. Number of charcters in any line are nchars-1, * the last character being a newline character. */ - for (i = 0; i < BYTES - 1; i++) { + for (i = 0; i < nchars - 1; i++) { if (mac == 1) buf[i] = '1'; else buf[i] = '0'; } - buf[BYTES - 1] = '\n'; + buf[nchars - 1] = '\n'; - for (i = 0; i < LINES; i++) { + for (i = 0; i < nlines; i++) { if (mac == 1) { /* Set the offset to even lines */ if ((i % 2) == 0) { if (i == 0) offset = 0; else - offset += 2 * BYTES; + offset += 2 * nchars; } else continue; } else { /* Set the offset to odd lines */ if ((i % 2) == 1) { if (i == 1) - offset = BYTES; + offset = nchars; else - offset += 2 * BYTES; + offset += 2 * nchars; } else continue; } - if (writeb_lock(fd, offset, SEEK_SET, BYTES) < 0) - printf("failed in writeb_lock, Errno = %d", errno); + if (writeb_lock(fd, offset, SEEK_SET, nchars) < 0) { + fprintf(stderr, "failed in writeb_lock, errno = %d\n", errno); + exit(1); + } lseek(fd, offset, SEEK_SET); - /* write to the test file */ - write(fd, buf, BYTES); + if (write(fd, buf, nchars) < 0) { + fprintf(stderr, "failed to write buffer to test file, errno = %d\n", errno); + exit(1); + } - if (unb_lock(fd, offset, SEEK_SET, BYTES) < 0) - printf("failed in unb_lock, Errno = %d", errno); + if (unb_lock(fd, offset, SEEK_SET, nchars) < 0) { + fprintf(stderr, "failed in unb_lock, errno = %d\n", errno); + exit(1); + } } exit(0); } diff --git a/testcases/network/nfs/nfslock01/nfs_flock.h b/testcases/network/nfs/nfslock01/nfs_flock.h index 09e3845f4..fba4a7f02 100644 --- a/testcases/network/nfs/nfslock01/nfs_flock.h +++ b/testcases/network/nfs/nfslock01/nfs_flock.h @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2009 + * Copyright (c) International Business Machines Corp., 2001 + */ + #include <stdio.h> #include <sys/stat.h> #include <errno.h> diff --git a/testcases/network/nfs/nfslock01/nfs_flock_dgen.c b/testcases/network/nfs/nfslock01/nfs_flock_dgen.c index 2b33ca974..6ecdcdc4f 100644 --- a/testcases/network/nfs/nfslock01/nfs_flock_dgen.c +++ b/testcases/network/nfs/nfslock01/nfs_flock_dgen.c @@ -1,5 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * This program generates data for testing file locking + * Copyright (c) Linux Test Project, 2001-2023 + * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] + * + * Tool to generate data for testing file locking. + * Used in nfslock01.sh. */ #include <stdio.h> @@ -13,32 +22,39 @@ int main(int argc, char **argv) FILE *fp; if (argc != 5) { - printf - ("usage: <nfs_flock_dgen> <file> <char/line> <lines> <ctype>\n"); + fprintf(stderr, "usage: <nfs_flock_dgen> <file> <char/line> <lines> <ctype>\n"); exit(2); } fp = fopen(argv[1], "w"); nchars = atoi(argv[2]); + nlines = atoi(argv[3]); + ctype = atoi(argv[4]); + if (nchars > BUFSIZ) { - printf("Exceeded the maximum limit of the buffer (%d)\n", - BUFSIZ); + fprintf(stderr, "Exceeded the maximum limit of the buffer (%d)\n", BUFSIZ); + exit(3); + } + + if (nchars < 1) { + fprintf(stderr, "<char/line> must be > 0\n"); + exit(3); + } + + if (nlines < 1) { + fprintf(stderr, "<lines> must be > 0\n"); exit(3); } - nlines = atoi(argv[3]); - ctype = atoi(argv[4]); k = 0; for (i = 1; i <= nlines; i++) { - if (ctype) c = ((i % 2) ? '1' : '0'); else c = 'A' + k; - for (j = 0; j < nchars; j++) - + for (j = 0; j < nchars - 1; j++) buf[j] = c; fprintf(fp, "%s\n", buf); @@ -53,5 +69,6 @@ int main(int argc, char **argv) } fclose(fp); - return (0); + + return 0; } diff --git a/testcases/network/nfs/nfslock01/nfs_flock_func.c b/testcases/network/nfs/nfslock01/nfs_flock_func.c index 811136188..aee66f40b 100644 --- a/testcases/network/nfs/nfslock01/nfs_flock_func.c +++ b/testcases/network/nfs/nfslock01/nfs_flock_func.c @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2012 + * Copyright (c) International Business Machines Corp., 2001 + */ + #include <stdlib.h> #include <unistd.h> diff --git a/testcases/network/nfs/nfslock01/nfslock01.sh b/testcases/network/nfs/nfslock01/nfslock01.sh index fbcc3c00f..01d59ce85 100755 --- a/testcases/network/nfs/nfslock01/nfslock01.sh +++ b/testcases/network/nfs/nfslock01/nfslock01.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) Linux Test Project, 2002-2022 +# Copyright (c) Linux Test Project, 2002-2023 # Copyright (c) 2016-2018 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2001 # @@ -13,19 +13,42 @@ TST_SETUP="do_setup" TST_TESTFUNC="do_test" +NCHARS=${NCHARS:-64} +NLINES=${NLINES:-16384} + +generate_file() +{ + local file="$1" + local nchars="$2" + local nlines="$3" + local val="$4" + local exp_size="$((nchars*nlines))" + local size + + ROD nfs_flock_dgen $file $nchars $nlines $val + + size="$(wc -c $file | awk '{print $1}')" + if [ $size -ne $exp_size ]; then + tst_brk TBROK "could not create '$file' (size: $size, expected: $exp_size)" + fi +} + do_setup() { - nfs_setup + if ! tst_is_int $NCHARS || [ $NCHARS -lt 1 ]; then + tst_res TBROK "NCHARS must be > 0" + fi - tst_res TINFO "creating test files" - ROD nfs_flock_dgen flock_data 63 16384 0 - ROD nfs_flock_dgen flock_odata 63 16384 1 + if ! tst_is_int $NLINES || [ $NLINES -lt 1 ]; then + tst_res TBROK "NLINES must be > 0" + fi + + nfs_setup - [ "$(wc -c flock_data | awk '{print $1}')" -ne 1048576 ] && \ - tst_brk TBROK "could not create 'flock_data'" + tst_res TINFO "creating test files (chars: $NCHARS, lines: $NLINES)" - [ "$(wc -c flock_odata | awk '{print $1}')" -ne 1048576 ] && \ - tst_brk TBROK "could not create 'flock_odata'" + generate_file flock_data $NCHARS $NLINES 0 + generate_file flock_odata $NCHARS $NLINES 1 } do_test() @@ -36,9 +59,9 @@ do_test() tst_res TINFO "locking 'flock_idata' file and writing data" - nfs_flock 0 flock_idata & + nfs_flock 0 flock_idata $NCHARS $NLINES & local pids=$! - nfs_flock 1 flock_idata & + nfs_flock 1 flock_idata $NCHARS $NLINES & pids="$pids $!" tst_res TINFO "waiting for pids: $pids" diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c index 5f024f113..80d5f045a 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c @@ -59,7 +59,8 @@ int main(int argn, char *argc[]) //Call broadcast routine cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, - (xdrproc_t) xdr_int, (char *)&varRec, eachResult); + (xdrproc_t) xdr_int, (char *)&varRec, + (resultproc_t) eachResult); test_status = (cs == RPC_SUCCESS) ? 0 : 1; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c index c6e55cd81..e1bb8fcc5 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c @@ -78,7 +78,8 @@ int main(int argn, char *argc[]) //Call broadcast routine cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, - (xdrproc_t) xdr_int, (char *)&varRec, eachResult); + (xdrproc_t) xdr_int, (char *)&varRec, + (resultproc_t) eachResult); if (currentAnswer == maxAnswer) test_status = 0; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c index fdf1e31a2..e1f7bcb6a 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c @@ -72,7 +72,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, INTPROCNUM, (xdrproc_t) xdr_int, (char *)&intSnd, - (xdrproc_t) xdr_int, (char *)&intRec, eachResult); + (xdrproc_t) xdr_int, (char *)&intRec, + (resultproc_t) eachResult); if (intSnd != intRec) test_status = 1; @@ -84,7 +85,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, INTPROCNUM, (xdrproc_t) xdr_int, (char *)&intSnd, - (xdrproc_t) xdr_int, (char *)&intRec, eachResult); + (xdrproc_t) xdr_int, (char *)&intRec, + (resultproc_t) eachResult); if (intSnd != intRec) test_status = 1; @@ -96,7 +98,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_long, (char *)&lngSnd, - (xdrproc_t) xdr_long, (char *)&lngRec, eachResult); + (xdrproc_t) xdr_long, (char *)&lngRec, + (resultproc_t) eachResult); if (lngSnd != lngRec) test_status = 1; @@ -108,7 +111,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_double, (char *)&dblSnd, - (xdrproc_t) xdr_double, (char *)&dblRec, eachResult); + (xdrproc_t) xdr_double, (char *)&dblRec, + (resultproc_t) eachResult); if (dblSnd != dblRec) test_status = 1; @@ -121,7 +125,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_wrapstring, (char *)&strSnd, - (xdrproc_t) xdr_wrapstring, (char *)&strRec, eachResult); + (xdrproc_t) xdr_wrapstring, (char *)&strRec, + (resultproc_t) eachResult); if (strcmp(strSnd, strRec)) test_status = 1; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c index 11ba64fab..d733e72ef 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c @@ -114,7 +114,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs != RPC_SUCCESS) clnt_perrno(cs); diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c index 57ea25349..4455c1173 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c @@ -114,7 +114,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs != RPC_SUCCESS) clnt_perrno(cs); diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c index d5d7d85d1..933305482 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c @@ -65,7 +65,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs == RPC_SUCCESS) nbOk++; } diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c index 3becf4600..c6fb3e0f6 100644 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c @@ -67,9 +67,8 @@ int main(int argn, char *argc[]) svcr = svcudp_create(RPC_ANYSOCK); //call routine - rslt = - registerrpc(progNum, VERSNUM, PROCNUM, simplePing, xdr_int, - xdr_int); + rslt = registerrpc(progNum, VERSNUM, PROCNUM, simplePing, + (xdrproc_t) xdr_int, (xdrproc_t) xdr_int); if (run_mode) { printf("SVC : %p\n", svcr); diff --git a/testcases/network/sctp/sctp_big_chunk.c b/testcases/network/sctp/sctp_big_chunk.c index a6a326ea2..467486846 100644 --- a/testcases/network/sctp/sctp_big_chunk.c +++ b/testcases/network/sctp/sctp_big_chunk.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. +/* + * Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2019-2023 + */ + +/*\ + * [Description] * - * Regression test-case for the crash caused by over-sized SCTP chunk, + * Regression test for the crash caused by over-sized SCTP chunk, * fixed by upstream commit 07f2c7ab6f8d ("sctp: verify size of a new - * chunk in _sctp_make_chunk()") + * chunk in _sctp_make_chunk()"). */ #include <stdlib.h> @@ -34,6 +40,26 @@ static int addr_num = 3273; static void setup_server(void) { + const char hmac_algo_path[] = "/proc/sys/net/sctp/cookie_hmac_alg"; + char hmac_algo[CHAR_MAX]; + int hmac_algo_changed = 0; + int fd; + + /* Disable md5 if fips is enabled. Set it to none */ + if (tst_fips_enabled()) { + /* Load sctp module */ + if (access(hmac_algo_path, F_OK) < 0) { + fd = SAFE_SOCKET(PF_INET, SOCK_STREAM, IPPROTO_SCTP); + SAFE_CLOSE(fd); + } + + if (!access(hmac_algo_path, F_OK)) { + SAFE_FILE_SCANF(hmac_algo_path, "%s", hmac_algo); + SAFE_FILE_PRINTF(hmac_algo_path, "%s", "none"); + hmac_algo_changed = 1; + } + } + loc.sin6_family = AF_INET6; loc.sin6_addr = in6addr_loopback; @@ -46,6 +72,9 @@ static void setup_server(void) SAFE_LISTEN(sfd, 1); srand(port); + + if (hmac_algo_changed) + SAFE_FILE_PRINTF(hmac_algo_path, "%s", hmac_algo); } static void update_packet_field(size_t *off, void *buf, size_t buf_len) diff --git a/testcases/network/sockets/vsock01.c b/testcases/network/sockets/vsock01.c index 1e688df19..7be71a83b 100644 --- a/testcases/network/sockets/vsock01.c +++ b/testcases/network/sockets/vsock01.c @@ -8,10 +8,11 @@ * * Reproducer of CVE-2021-26708 * - * Based on POC https://github.com/jordan9001/vsock_poc + * Based on POC https://github.com/jordan9001/vsock_poc. * Fuzzy Sync has been substituted for userfaultfd. * * Fixed by: c518adafa39f ("vsock: fix the race conditions in multi-transport support") + * * Fixes: c0cfa2d8a788fcf4 ("vsock: add multi-transports support") * * Note that in many testing environments this will reproduce the race diff --git a/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 b/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 index 92af9e438..c0d50efaf 100644 --- a/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 +++ b/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 @@ -230,7 +230,7 @@ while [ $ipaddr_pair_num -lt $IP_TOTAL_FOR_TCPIP ]; do # Set IPv6 addresses to the interfaces ip addr add ${lhost_addr}/${network_mask} dev $lhost_ifname - if [ $ret -eq 2 ]; then + if [ $? -eq 2 ]; then ip addr del ${lhost_addr}/${network_mask} dev $lhost_ifname 2>&1 ip addr add ${lhost_addr}/${network_mask} dev $lhost_ifname fi diff --git a/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh b/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh index 644a1fb8d..e67ff5cc8 100755 --- a/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh +++ b/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh @@ -25,7 +25,7 @@ do_setup() if [ -n "$TST_IPV6" ]; then tst_brk TCONF "'arp' doesn't support IPv6" fi - SHOW_CMD="arp -a" + SHOW_CMD="arp -an" DEL_CMD="ROD arp -d $(tst_ipaddr rhost) -i $(tst_iface)" ;; *) diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c index 8a6c024a9..e0fecd805 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c @@ -10,7 +10,7 @@ * assertion: * * The aio_read() function shall return the value -1 and set errno to - * indicate error if the operation is not succesfully queued. + * indicate error if the operation is not successfully queued. * * method: * diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml index e23c6bcf6..ae2062221 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml @@ -28,7 +28,7 @@ </assertion> <assertion id="8" tag="ref:XSH6TC2:4155:4155"> The aio_read() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. </assertion> <assertion id="9" tag="ref:XSH6TC2:4158:4159"> aio_read() shall fail with [EAGAIN] if: @@ -46,16 +46,16 @@ value, or aio_nbytes is an invalid value. </assertion> <assertion id="12" tag="ref:XSH6TC2:4174:4174"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EBADF] if the aio_fildes argument is not a valid file descriptor open for reading. </assertion> <assertion id="13" tag="ref:XSH6TC2:4375:4376"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [ECANCELED] if The requested I/O was canceled before the I/O completed. </assertion> <assertion id="14" tag="ref:XSH6TC2:4177:4177"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EINVAL] if aio_offset would be invalid, or aio_reqprio is not a valid value, or aio_nbytes is an invalid value. </assertion> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c index 2948552c4..60428ce27 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c @@ -10,7 +10,7 @@ * assertion: * * The aio_write() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. * * method: * @@ -18,7 +18,6 @@ * aiocb with invalid aio_reqprio * - call aio_write * - check aio_write return value - * */ #include <stdio.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml index 86694021f..e00774c61 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml @@ -21,7 +21,7 @@ </assertion> <assertion id="6" tag="ref:XSH6TC2:4348:4349"> The aio_write() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. </assertion> <assertion id="7" tag="ref:XSH6TC2:4352:4353"> aio_write() shall fail with [EAGAIN] if: @@ -38,17 +38,17 @@ aio_nbytes is an invalid value. </assertion> <assertion id="10" tag="ref:XSH6TC2:4369:4369"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EBADF] if the aio_fildes argument is not a valid file descriptor open for writing. </assertion> <assertion id="11" tag="ref:XSH6TC2:4370:4370"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EINVAL] if aio_offset would be invalid, or aio_reqprio is not a valid value, or aio_nbytes is an invalid value. </assertion> <assertion id="12" tag="ref:XSH6TC2:4371:4372"> - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [ECANCELED] The requested I/O was canceled before the I/O completed. </assertion> <assertion id="13" tag="ref:XSH6TC2:4374:4376"> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml index 48abbfbe8..64793fc3f 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml @@ -83,7 +83,7 @@ </assertion> <assertion id="23" tag="ref:XSH6TC2:13060:13062"> fork() returns 0 to the child and the child PID to the parent process when - succesful. + successful. </assertion> <assertion id="24" tag="ref:XSH6TC2:13063:13069"> fork() returns -1, errno is set to EAGAIN, and no child process diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c index 33915a440..48754f815 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c @@ -10,7 +10,7 @@ * assertion: * * if mode is LIO_WAIT, lio_listio() shall return the value -1 and set - * errno to indicate error if the operation is not succesfully queued. + * errno to indicate error if the operation is not successfully queued. * * method: * diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml index 8832fdd3c..5aaa78a18 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml @@ -36,7 +36,7 @@ </assertion> <assertion id="11" tag="ref:XSH6TC2:23084:23085"> if mode is LIO_NOWAIT, lio_listio() shall return the value -1 and set - errno to indicate error if the operation is not succesfully queued. + errno to indicate error if the operation is not successfully queued. </assertion> <assertion id="12" tag="ref:XSH6TC2:23086:23087"> if mode is LIO_WAIT, lio_listio() shall return the value zero when diff --git a/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c b/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c index 33c0575c5..a27c91e46 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c @@ -71,7 +71,7 @@ int main(void) munmap(pa, size); close(fd); - printf("Succesfully mapped readonly file with " + printf("Successfully mapped readonly file with " "PROT_WRITE, MAP_PRIVATE\n" "Test PASSED\n"); return PTS_PASS; } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml index 9b2c14717..a15504bd6 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml @@ -4,7 +4,7 @@ pthread_attr_getinheritsched shall get the inheritsched attribute in the attr ar PTHREAD_INHERIT_SCHED and PTHREAD_EXPLICIT_SCHED are valid value. </assertion> <assertion id="2" tag="ref:XSH6:31347:31347"> -If succesful, the pthread_attr_getinheritsched shall return zero. +If successful, the pthread_attr_getinheritsched shall return zero. </assertion> <assertion id="3" tag="ref:XSH6:31348:31348"> If fail, the pthread_attr_getinheritsched shall return an error number. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml index c201c4449..f6733520c 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml @@ -4,7 +4,7 @@ pthread_attr_getscope shall get the inheritsched attribute in the attr argument The contentionscope attribute may have the values PTHREAD_SCOPE_SYSTEM, signifying system scheduling contention scope, or PTHREAD_SCOPE_PROCESS, signifying process scheduling contention scope. </assertion> <assertion id="2" tag="ref:XSH6:31492:31492"> -If succesful, the pthread_attr_getscope shall return zero. +If successful, the pthread_attr_getscope shall return zero. </assertion> <assertion id="3" tag="ref:XSH6:31493:31493"> If fail, the pthread_attr_getscope shall return an error number. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c index d07a199cb..a618e98c8 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_cond_destroy() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c index f0402648f..886d0f04b 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_cond_init() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c index 4217afa4b..80cd2ad96 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c @@ -6,14 +6,12 @@ * source tree. * Test that pthread_detach() - * - * Upon succesful completion, it shall return a 0; + * Upon successful completion, it shall return 0. * * STEPS: * 1.Create a joinable thread * 2.Detach that thread * 3.Check the return value - * */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c index 9ce4ca105..a8b032c53 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_destroy() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c index d7b4f204e..1df6e5af2 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_init() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c index 7e8827c4a..a8123ba58 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_lock() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c index 32151322d..ea81f99ca 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_trylock() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c index 4053388be..cb0ae72b6 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_unlock() - * Upon succesful completion, it shall return zero - * + * Upon successful completion, it shall return zero */ #include <pthread.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c index 63f6721c8..12f522e1f 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c @@ -5,7 +5,7 @@ * of this license, see the COPYING file at the top level of this * source tree. -The resulting set shall be the the signal set pointed to by set +The resulting set shall be the signal set pointed to by set Steps: 1. Have main create a new thread and wait for its termination. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c index 1dfee2efe..005f46a4b 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c @@ -5,7 +5,7 @@ * of this license, see the COPYING file at the top level of this * source tree. - * Test that the the raise() function does not return until after the + * Test that the raise() function does not return until after the * signal handler it calls returns. * This test is only performed on one signal. All other signals are * considered to be in the same equivalence class. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c index fb19ff6a4..ee106c677 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c @@ -24,10 +24,10 @@ * 5. Both children and father increment a counter in a basic loop. * 6. The father send SIGTERM to the last child and get its counter. If child * counter is reasonably lower than the fathers one, the test is - * succesfull. + * successful. * 7. The father kill all other children. - * */ + #include "affinity.h" #include <sched.h> diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c index 6c68120c3..c81ffd374 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c @@ -24,9 +24,8 @@ * 5. Both children and father increment a counter in a basic loop. * 6. The father send SIGTERM to the last child and get its counter. If child * counter is reasonably lower than the fathers one, the test is - * succesfull. + * successful. * 7. The father kill all other children. - * */ #include "affinity.h" diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml index 37b96641b..86fc1d544 100644 --- a/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml @@ -5,7 +5,7 @@ </assertion> <assertion id="2" tag="ref:XSH6:42291:42293 pt:RTS"> Error checking is performed but no signal is actually sent, if signo is zero (the null signal). - Using the null signal can be used to check the the validity of pid. + Using the null signal can be used to check the validity of pid. </assertion> <assertion id="3" tag="ref:XSH6:42294:42295 pt:RTS"> For a process to have permission to queue a signal to another process diff --git a/testcases/realtime/func/matrix_mult/matrix_mult.c b/testcases/realtime/func/matrix_mult/matrix_mult.c index e2a55628a..c32092344 100644 --- a/testcases/realtime/func/matrix_mult/matrix_mult.c +++ b/testcases/realtime/func/matrix_mult/matrix_mult.c @@ -100,7 +100,7 @@ static void matrix_mult(struct matrices *matrices) matrix_init(matrices->A, matrices->B); for (i = 0; i < MATRIX_SIZE; i++) { - int i_m = MATRIX_SIZE - i; + int i_m = MATRIX_SIZE - i - 1; for (j = 0; j < MATRIX_SIZE; j++) { double sum = matrices->A[i_m][j] * matrices->B[j][i]; for (k = 0; k < MATRIX_SIZE; k++) diff --git a/testcases/realtime/tools/ftqviz.py b/testcases/realtime/tools/ftqviz.py index 5ac094cbd..f56d41aa6 100644 --- a/testcases/realtime/tools/ftqviz.py +++ b/testcases/realtime/tools/ftqviz.py @@ -45,7 +45,7 @@ def smooth(x, wlen): # generate the smoothed signal y = convolve(w/w.sum(), s, mode='same') - # recenter the the smoothed signal over the originals (slide along x) + # recenter the smoothed signal over the originals (slide along x) y1 = y[wlen-1:-wlen+1] return y1 |