From bbe865b2feea548ea090c30ecf9d5087b049c86b Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Tue, 14 Nov 2023 10:52:24 +0100 Subject: [PATCH 1/2] test: switch SELinux to permissive in the config file The config file has (unfortunately) precedence over the kernel command line, so let's tweak the config file if necessary. --- test/TEST-06-SELINUX/test.sh | 5 ++++- test/units/testsuite-06.sh | 6 ------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh index 0757b38cc29..c7eaae8ab4a 100755 --- a/test/TEST-06-SELINUX/test.sh +++ b/test/TEST-06-SELINUX/test.sh @@ -22,7 +22,7 @@ test -f /usr/share/selinux/devel/include/system/systemd.if && find /etc/selinux . "${TEST_BASE_DIR:?}/test-functions" SETUP_SELINUX=yes -KERNEL_APPEND="${KERNEL_APPEND:=} selinux=1 security=selinux" +KERNEL_APPEND="${KERNEL_APPEND:=} selinux=1 security=selinux enforcing=0" test_append_files() { local workspace="${1:?}" @@ -53,6 +53,9 @@ test_append_files() { image_install -o /usr/libexec/selinux/hll/pp # Fedora/RHEL/... image_install -o /usr/lib/selinux/hll/pp # Debian/Ubuntu/... + # Config file has (unfortunately) always precedence, so let's switch it there as well + sed -i '/^SELINUX=disabled$/s/disabled/permissive/' "$workspace/etc/selinux/config" + if ! chroot "$workspace" make -C /systemd-test-module -f /usr/share/selinux/devel/Makefile clean load systemd_test.pp QUIET=n; then dfatal "Failed to build the systemd test module" exit 1 diff --git a/test/units/testsuite-06.sh b/test/units/testsuite-06.sh index c57d8b94888..73ae4850418 100755 --- a/test/units/testsuite-06.sh +++ b/test/units/testsuite-06.sh @@ -3,12 +3,6 @@ set -eux set -o pipefail -echo 1 >/sys/fs/selinux/enforce || { - echo "Can't make selinux enforcing, skipping test" - touch /testok - exit -} - runcon -t systemd_test_start_t systemctl start hola runcon -t systemd_test_reload_t systemctl reload hola runcon -t systemd_test_stop_t systemctl stop hola From 5ef964f88c9702656e848d5757c48dd7ddd03f11 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Tue, 14 Nov 2023 12:53:51 +0100 Subject: [PATCH 2/2] test: make TEST-06-SELINUX work with the refpolicy and beef it up a bit Currently the test works only with policy shipped by Fedora, which makes it pretty much useless in most of our CIs. Let's drop the custom module and make the test more generic, so it works with the refpolicy as well, which should allow us to run it on Arch and probably even in Ubuntu CI. --- test/TEST-06-SELINUX/systemd_test.fc | 2 - test/TEST-06-SELINUX/systemd_test.if | 9 ----- test/TEST-06-SELINUX/systemd_test.te | 51 ----------------------- test/TEST-06-SELINUX/test.sh | 60 +++++++++------------------- test/test-functions | 23 +++++------ test/units/testsuite-06.sh | 39 ++++++++++++++++-- 6 files changed, 65 insertions(+), 119 deletions(-) delete mode 100644 test/TEST-06-SELINUX/systemd_test.fc delete mode 100644 test/TEST-06-SELINUX/systemd_test.if delete mode 100644 test/TEST-06-SELINUX/systemd_test.te diff --git a/test/TEST-06-SELINUX/systemd_test.fc b/test/TEST-06-SELINUX/systemd_test.fc deleted file mode 100644 index 2aa442ce772..00000000000 --- a/test/TEST-06-SELINUX/systemd_test.fc +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -/usr/lib/systemd/tests/testdata/testsuite-06\.units(/.*)? system_u:object_r:systemd_unit_file_t:s0 diff --git a/test/TEST-06-SELINUX/systemd_test.if b/test/TEST-06-SELINUX/systemd_test.if deleted file mode 100644 index 1e74e1d7499..00000000000 --- a/test/TEST-06-SELINUX/systemd_test.if +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -template(`systemd_test_base_template', ` - gen_require(` - attribute systemd_test_domain_type; - ') - - type $1_t, systemd_test_domain_type; - domain_type($1_t) -') diff --git a/test/TEST-06-SELINUX/systemd_test.te b/test/TEST-06-SELINUX/systemd_test.te deleted file mode 100644 index 43dbf3e8f44..00000000000 --- a/test/TEST-06-SELINUX/systemd_test.te +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -policy_module(systemd_test, 0.0.1) - -# declarations -attribute systemd_test_domain_type; - -systemd_test_base_template(systemd_test) -systemd_test_base_template(systemd_test_status) -systemd_test_base_template(systemd_test_start) -systemd_test_base_template(systemd_test_stop) -systemd_test_base_template(systemd_test_reload) - -# systemd_test_domain_type - -require { - role system_r; - role unconfined_r; - type bin_t; - type initrc_t; - type systemd_systemctl_exec_t; - type unconfined_service_t; -} - -role system_r types systemd_test_domain_type; -role unconfined_r types systemd_test_domain_type; - -allow systemd_test_domain_type bin_t: file entrypoint; -allow systemd_test_domain_type systemd_systemctl_exec_t: file entrypoint; -allow initrc_t systemd_test_domain_type: process transition; -allow unconfined_service_t systemd_test_domain_type: process transition; -corecmd_exec_bin(systemd_test_domain_type) -init_signal_script(systemd_test_domain_type) -init_sigchld_script(systemd_test_domain_type) -systemd_exec_systemctl(systemd_test_domain_type) -userdom_use_user_ttys(systemd_test_domain_type) -userdom_use_user_ptys(systemd_test_domain_type) - -optional_policy(` - dbus_system_bus_client(systemd_test_domain_type) - init_dbus_chat(systemd_test_domain_type) -') - -# systemd_test_*_t -require { - type systemd_unit_file_t; -} - -allow systemd_test_status_t systemd_unit_file_t: service { status }; -allow systemd_test_start_t systemd_unit_file_t: service { start }; -allow systemd_test_stop_t systemd_unit_file_t: service { stop }; -allow systemd_test_reload_t systemd_unit_file_t: service { reload }; diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh index c7eaae8ab4a..384101577fd 100755 --- a/test/TEST-06-SELINUX/test.sh +++ b/test/TEST-06-SELINUX/test.sh @@ -6,60 +6,38 @@ TEST_DESCRIPTION="SELinux tests" IMAGE_NAME="selinux" TEST_NO_NSPAWN=1 -# Requirements: -# A selinux policy is installed. Preferably selinux-policy-targeted, but it could work with others -# selinux-policy-devel +if [[ -e /etc/selinux/config ]]; then + SEPOLICY="$(awk -F= '/^SELINUXTYPE=/ {print $2; exit}' /etc/selinux/config)" -# Check if -# - selinux-policy-devel is installed and -# - some selinux policy is installed. To keep this generic just check for the -# existence of a directory below /etc/selinux/, indicating a SELinux policy is -# installed -# otherwise bail out early instead of failing -test -f /usr/share/selinux/devel/include/system/systemd.if && find /etc/selinux -mindepth 1 -maxdepth 1 -not -empty -type d | grep -q . || exit 0 + # C8S doesn't set SELINUXTYPE in /etc/selinux/config, so default to 'targeted' + if [[ -z "$SEPOLICY" ]]; then + echo "Failed to parse SELinux policy from /etc/selinux/config, falling back to 'targeted'" + SEPOLICY="targeted" + fi + + if [[ ! -d "/etc/selinux/$SEPOLICY" ]]; then + echo "Missing policy directory /etc/selinux/$SEPOLICY, skipping the test" + exit 0 + fi + + echo "Using SELinux policy '$SEPOLICY'" +else + echo "/etc/selinux/config is missing, skipping the test" + exit 0 +fi # shellcheck source=test/test-functions . "${TEST_BASE_DIR:?}/test-functions" SETUP_SELINUX=yes -KERNEL_APPEND="${KERNEL_APPEND:=} selinux=1 security=selinux enforcing=0" +KERNEL_APPEND="${KERNEL_APPEND:-} selinux=1 enforcing=0 lsm=selinux" test_append_files() { local workspace="${1:?}" - local policy_headers_dir=/usr/share/selinux/devel - local modules_dir=/var/lib/selinux setup_selinux - # Make sure we never expand this to "/..." - rm -rf "${workspace:?}/$modules_dir" - - if ! cp -ar "$modules_dir" "$workspace/$modules_dir"; then - dfatal "Failed to copy $modules_dir" - exit 1 - fi - - rm -rf "${workspace:?}/$policy_headers_dir" - inst_dir /usr/share/selinux - - if ! cp -ar "$policy_headers_dir" "$workspace/$policy_headers_dir"; then - dfatal "Failed to copy $policy_headers_dir" - exit 1 - fi - - mkdir "$workspace/systemd-test-module" - cp -v systemd_test.* "$workspace/systemd-test-module/" - image_install checkmodule load_policy m4 make sefcontext_compile semodule semodule_package runcon - image_install -o sesearch - image_install -o /usr/libexec/selinux/hll/pp # Fedora/RHEL/... - image_install -o /usr/lib/selinux/hll/pp # Debian/Ubuntu/... - # Config file has (unfortunately) always precedence, so let's switch it there as well sed -i '/^SELINUX=disabled$/s/disabled/permissive/' "$workspace/etc/selinux/config" - - if ! chroot "$workspace" make -C /systemd-test-module -f /usr/share/selinux/devel/Makefile clean load systemd_test.pp QUIET=n; then - dfatal "Failed to build the systemd test module" - exit 1 - fi } do_test "$@" diff --git a/test/test-functions b/test/test-functions index 3cb08fb47a9..7375d3465c7 100644 --- a/test/test-functions +++ b/test/test-functions @@ -924,16 +924,13 @@ setup_selinux() { return 0 fi - local conf_dir=/etc/selinux - local fixfiles_tools=(awk bash cat chcon expr egrep find grep head secon setfiles rm sort uname uniq) - - # Make sure the following statement can't expand to "/" to prevent - # a potential where-are-my-backups situation - rm -rf "${initdir:?}/$conf_dir" - if ! cp -ar "$conf_dir" "$initdir/$conf_dir"; then - dfatal "Failed to copy $conf_dir" - exit 1 - fi + for dir in /etc/selinux /usr/share/selinux; do + rm -rf "${initdir:?}/$dir" + if ! cp -ar "$dir" "$initdir/$dir"; then + dfatal "Failed to copy $dir" + exit 1 + fi + done # We use a custom autorelabel service instead of the SELinux provided set # of units & a generator, since the generator overrides the default target @@ -944,13 +941,13 @@ setup_selinux() { # and does the relabeling unconditionally which always ends with a reboot, so # we end up in a reboot loop (and it also spews quite a lot of errors as it # wants /etc/fstab and dracut-initramfs-restore). - touch "$initdir/.autorelabel" mkdir -p "$initdir/usr/lib/systemd/tests/testdata/units/basic.target.wants" ln -sf ../autorelabel.service "$initdir/usr/lib/systemd/tests/testdata/units/basic.target.wants/" - image_install "${fixfiles_tools[@]}" - image_install fixfiles sestatus + # Tools requires by fixfiles + image_install awk bash cat chcon expr egrep find grep head secon setfiles rm sort uname uniq + image_install fixfiles getenforce load_policy selinuxenabled sestatus } install_valgrind() { diff --git a/test/units/testsuite-06.sh b/test/units/testsuite-06.sh index 73ae4850418..7fc3c379e57 100755 --- a/test/units/testsuite-06.sh +++ b/test/units/testsuite-06.sh @@ -3,8 +3,41 @@ set -eux set -o pipefail -runcon -t systemd_test_start_t systemctl start hola -runcon -t systemd_test_reload_t systemctl reload hola -runcon -t systemd_test_stop_t systemctl stop hola +# Note: ATTOW the following checks should work with both Fedora and upstream reference policy +# (with or without MCS/MLS) + +sestatus + +# We should end up in permissive mode +[[ "$(getenforce)" == "Permissive" ]] + +# Check PID 1's context +PID1_CONTEXT="$(ps -h -o label 1)" +[[ "$PID1_CONTEXT" =~ ^system_u:system_r:init_t(:s0)?$ ]] +# The same label should be attached to all PID 1's journal messages +journalctl -q -b -p info -n 5 --grep . _SELINUX_CONTEXT="$PID1_CONTEXT" + +# Check context on a couple of arbitrarily-selected files/directories +[[ "$(stat --printf %C /run/systemd/journal/)" =~ ^system_u:object_r:(syslogd_runtime_t|syslogd_var_run_t)(:s0)?$ ]] +[[ "$(stat --printf %C /run/systemd/notify)" =~ ^system_u:object_r:(init_runtime_t|init_var_run_t)(:s0)?$ ]] +[[ "$(stat --printf %C /run/systemd/sessions/)" =~ ^system_u:object_r:(systemd_sessions_runtime_t|systemd_logind_sessions_t)(:s0)?$ ]] + +# Check if our SELinux-related functionality works +# +# Since the SELinux policies vary wildly, use a context from some existing file +# as our test context +CONTEXT="$(stat -c %C /proc/sys/kernel/core_pattern)" + +[[ "$(systemd-run --wait --pipe -p SELinuxContext="$CONTEXT" cat /proc/self/attr/current | tr -d '\0')" == "$CONTEXT" ]] +(! systemd-run --wait --pipe -p SELinuxContext="foo:bar:baz" cat /proc/self/attr/current) +(! systemd-run --wait --pipe -p ConditionSecurity='selinux' false) +systemd-run --wait --pipe -p ConditionSecurity='!selinux' false + +NSPAWN_ARGS=(systemd-nspawn -q --volatile=yes --directory=/ --bind-ro=/etc --inaccessible=/etc/machine-id) +[[ "$("${NSPAWN_ARGS[@]}" cat /proc/self/attr/current | tr -d '\0')" != "$CONTEXT" ]] +[[ "$("${NSPAWN_ARGS[@]}" --selinux-context="$CONTEXT" cat /proc/self/attr/current | tr -d '\0')" == "$CONTEXT" ]] +[[ "$("${NSPAWN_ARGS[@]}" stat --printf %C /run)" != "$CONTEXT" ]] +[[ "$("${NSPAWN_ARGS[@]}" --selinux-apifs-context="$CONTEXT" stat --printf %C /run)" == "$CONTEXT" ]] +[[ "$("${NSPAWN_ARGS[@]}" --selinux-apifs-context="$CONTEXT" --tmpfs=/tmp stat --printf %C /tmp)" == "$CONTEXT" ]] touch /testok