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 0757b38cc29..384101577fd 100755 --- a/test/TEST-06-SELINUX/test.sh +++ b/test/TEST-06-SELINUX/test.sh @@ -6,57 +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" +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/... - - 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 + # 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" } 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 c57d8b94888..7fc3c379e57 100755 --- a/test/units/testsuite-06.sh +++ b/test/units/testsuite-06.sh @@ -3,14 +3,41 @@ set -eux set -o pipefail -echo 1 >/sys/fs/selinux/enforce || { - echo "Can't make selinux enforcing, skipping test" - touch /testok - exit -} +# Note: ATTOW the following checks should work with both Fedora and upstream reference policy +# (with or without MCS/MLS) -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 +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