diff options
Diffstat (limited to 'testcases/lib')
-rw-r--r-- | testcases/lib/.gitignore | 8 | ||||
-rw-r--r-- | testcases/lib/Makefile | 3 | ||||
-rw-r--r-- | testcases/lib/tst_fsfreeze.c | 38 | ||||
-rw-r--r-- | testcases/lib/tst_get_free_pids.c | 2 | ||||
-rw-r--r-- | testcases/lib/tst_kvcmp.c | 2 | ||||
-rw-r--r-- | testcases/lib/tst_lockdown_enabled.c | 12 | ||||
-rw-r--r-- | testcases/lib/tst_net.sh | 228 | ||||
-rw-r--r-- | testcases/lib/tst_ns_common.h | 42 | ||||
-rw-r--r-- | testcases/lib/tst_ns_create.c | 92 | ||||
-rw-r--r-- | testcases/lib/tst_ns_exec.c | 115 | ||||
-rw-r--r-- | testcases/lib/tst_ns_ifmove.c | 92 | ||||
-rw-r--r-- | testcases/lib/tst_secureboot_enabled.c | 12 | ||||
-rw-r--r-- | testcases/lib/tst_test.sh | 14 |
13 files changed, 570 insertions, 90 deletions
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/lib/tst_ns_common.h b/testcases/lib/tst_ns_common.h new file mode 100644 index 000000000..358db5141 --- /dev/null +++ b/testcases/lib/tst_ns_common.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2015-2023 + */ + +#ifndef TST_NS_COMMON_H__ +#define TST_NS_COMMON_H__ +#include <sched.h> +#include "lapi/sched.h" + +#define PROC_PATH "/proc" + +struct param { + const char *name; + int flag; +}; + +static struct param params[] = { + {"ipc", CLONE_NEWIPC}, + {"mnt", CLONE_NEWNS}, + {"net", CLONE_NEWNET}, + {"pid", CLONE_NEWPID}, + {"user", CLONE_NEWUSER}, + {"uts", CLONE_NEWUTS}, + {NULL, 0} +}; + +#define NS_TOTAL (ARRAY_SIZE(params) - 1) + +static struct param *get_param(const char *name) +{ + int i; + + for (i = 0; params[i].name; i++) { + if (!strcasecmp(params[i].name, name)) + return params + i; + } + + return NULL; +} + +#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" |