diff options
author | Luca Boccassi <bluca@debian.org> | 2024-11-05 19:42:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-05 19:42:28 +0100 |
commit | 7af37f3a9020ae5c3ef2278649eb767aa3806163 (patch) | |
tree | 157eb24670dc72acdcbe71bdbb721ee40a7bd02d /test | |
parent | Translations update from Fedora Weblate (#35031) (diff) | |
parent | core: Introduce PrivatePIDs= (diff) | |
download | systemd-7af37f3a9020ae5c3ef2278649eb767aa3806163.tar.xz systemd-7af37f3a9020ae5c3ef2278649eb767aa3806163.zip |
Add PrivatePIDs= (continued) (#34940)
Diffstat (limited to 'test')
-rwxr-xr-x | test/TEST-07-PID1/test.sh | 5 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.private-pids.sh | 161 |
2 files changed, 166 insertions, 0 deletions
diff --git a/test/TEST-07-PID1/test.sh b/test/TEST-07-PID1/test.sh index 2513406e0d..66e1b684ea 100755 --- a/test/TEST-07-PID1/test.sh +++ b/test/TEST-07-PID1/test.sh @@ -6,12 +6,17 @@ TEST_DESCRIPTION="Tests for core PID1 functionality" # for testing PrivateNetwork=yes NSPAWN_ARGUMENTS="--capability=CAP_NET_ADMIN" +# for testing PrivatePIDs=yes +TEST_INSTALL_VERITY_MINIMAL=1 # shellcheck source=test/test-functions . "${TEST_BASE_DIR:?}/test-functions" test_append_files() { image_install logger socat + inst_binary mksquashfs + inst_binary unsquashfs + install_verity_minimal } do_test "$@" diff --git a/test/units/TEST-07-PID1.private-pids.sh b/test/units/TEST-07-PID1.private-pids.sh new file mode 100755 index 0000000000..6f16820aee --- /dev/null +++ b/test/units/TEST-07-PID1.private-pids.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +HAS_EXISTING_SCSI_MOUNT=no +if findmnt --mountpoint /proc/scsi; then + HAS_EXISTING_SCSI_MOUNT=yes +fi + +at_exit() { + set +e + + # Unmount any file systems + if [[ "$HAS_EXISTING_SCSI_MOUNT" == "no" ]]; then + umount /proc/scsi + fi + umount /tmp/TEST-07-PID1-private-pids-proc + rm -rf /tmp/TEST-07-PID1-private-pids-proc + # Remove any test files + rm -rf /tmp/TEST-07-PID1-private-pids-services + rm -rf /tmp/TEST-07-PID1-private-pids-root + # Stop any test services + systemctl kill --signal=KILL TEST-07-PID1-private-pid.service + # Remove any failed transient units + systemctl reset-failed +} + +trap at_exit EXIT + +testcase_basic() { + # Verify current process is PID1 in new namespace + assert_eq "$(systemd-run -p PrivatePIDs=yes --wait --pipe readlink /proc/self)" "1" + # Verify we are only processes in new namespace + assert_eq "$(systemd-run -p PrivatePIDs=yes --wait --pipe ps aux --no-heading | wc -l)" "1" + # Verify procfs mount + systemd-run -p PrivatePIDs=yes --wait --pipe \ + bash -xec '[[ "$$(findmnt --mountpoint /proc --noheadings -o VFS-OPTIONS)" =~ rw ]]; + [[ "$$(findmnt --mountpoint /proc --noheadings -o VFS-OPTIONS)" =~ nosuid ]]; + [[ "$$(findmnt --mountpoint /proc --noheadings -o VFS-OPTIONS)" =~ nodev ]]; + [[ "$$(findmnt --mountpoint /proc --noheadings -o VFS-OPTIONS)" =~ noexec ]];' + + # Verify main PID is correct + systemd-run -p PrivatePIDs=yes --remain-after-exit --unit TEST-07-PID1-private-pid sleep infinity + # Wait for ExecMainPID to be correctly populated as there might be a race between spawning service + # and actual exec child process + sleep 2 + pid=$(systemctl show TEST-07-PID1-private-pid.service -p ExecMainPID --value) + kill -9 "$pid" + timeout 10s bash -xec 'while [[ "$(systemctl show -P SubState TEST-07-PID1-private-pid.service)" != "failed" ]]; do sleep .5; done' + assert_eq "$(systemctl show -P Result TEST-07-PID1-private-pid.service)" "signal" + assert_eq "$(systemctl show -P ExecMainStatus TEST-07-PID1-private-pid.service)" "9" + systemctl reset-failed +} + +testcase_analyze() { + mkdir -p /tmp/TEST-07-PID1-private-pids-services + + # Verify other services are compatible with PrivatePIDs=yes + cat <<EOF >/tmp/TEST-07-PID1-private-pids-services/oneshot-valid.service +[Service] +ExecStart=echo hello +PrivatePIDs=yes +Type=oneshot +EOF + + # Verify Type=forking services are not compatible with PrivatePIDs=yes + cat <<EOF >/tmp/TEST-07-PID1-private-pids-services/forking-invalid.service +[Service] +ExecStart=echo hello +PrivatePIDs=yes +Type=forking +EOF + + systemd-analyze --recursive-errors=no verify /tmp/TEST-07-PID1-private-pids-services/oneshot-valid.service + (! systemd-analyze --recursive-errors=no verify /tmp/TEST-07-PID1-private-pids-services/forking-invalid.service) + + + rm -rf /tmp/TEST-07-PID1-private-pids-services +} + +testcase_multiple_features() { + unsquashfs -no-xattrs -d /tmp/TEST-07-PID1-private-pids-root /usr/share/minimal_0.raw + + systemd-run \ + -p PrivatePIDs=yes \ + -p RootDirectory=/tmp/TEST-07-PID1-private-pids-root \ + -p ProcSubset=pid \ + -p BindReadOnlyPaths=/usr/share \ + -p NoNewPrivileges=yes \ + -p ProtectSystem=strict \ + -p User=testuser\ + -p Group=testuser \ + -p RuntimeDirectory=abc \ + -p StateDirectory=qed \ + -p InaccessiblePaths=/usr/include \ + -p TemporaryFileSystem=/home \ + -p PrivateTmp=yes \ + -p PrivateDevices=yes \ + -p PrivateNetwork=yes \ + -p PrivateUsersEx=self \ + -p PrivateIPC=yes \ + -p ProtectHostname=yes \ + -p ProtectClock=yes \ + -p ProtectKernelTunables=yes \ + -p ProtectKernelModules=yes \ + -p ProtectKernelLogs=yes \ + -p ProtectControlGroupsEx=private \ + -p LockPersonality=yes \ + -p Environment=ABC=QED \ + --wait \ + --pipe \ + grep MARKER=1 /etc/os-release + + rm -rf /tmp/TEST-07-PID1-private-pids-root +} + +testcase_unpriv() { + if [ ! -f /usr/lib/systemd/user/dbus.socket ] && [ ! -f /etc/systemd/user/dbus.socket ]; then + echo "Per-user instances are not supported, skipping unprivileged PrivatePIDs=yes test" + return 0 + fi + + if [[ "$(sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" -eq 1 ]]; then + echo "Cannot create unprivileged user namespaces, skipping unprivileged PrivatePIDs=yes test" + return 0 + fi + + # The kernel has a restriction for unprivileged user namespaces where they cannot mount a less restrictive + # instance of /proc/. So if /proc/ is masked (e.g. /proc/kmsg is over-mounted with tmpfs as systemd-nspawn does), + # then mounting a new /proc/ will fail and we will still see the host's /proc/. Thus, to allow tests to run in + # a VM or nspawn, we mount a new proc on a temporary directory with no masking to bypass this kernel restriction. + mkdir -p /tmp/TEST-07-PID1-private-pids-proc + mount -t proc proc /tmp/TEST-07-PID1-private-pids-proc + + # Verify running as unprivileged user can unshare PID namespace and mounts /proc properly. + assert_eq "$(runas testuser systemd-run --wait --user --pipe -p PrivatePIDs=yes readlink /proc/self)" "1" + assert_eq "$(runas testuser systemd-run --wait --user --pipe -p PrivatePIDs=yes ps aux --no-heading | wc -l)" "1" + + umount /tmp/TEST-07-PID1-private-pids-proc + rm -rf /tmp/TEST-07-PID1-private-pids-proc + + # Now verify the behavior with masking - units should fail as PrivatePIDs=yes has no graceful fallback. + if [[ "$HAS_EXISTING_SCSI_MOUNT" == "no" ]]; then + mount -t tmpfs tmpfs /proc/scsi + fi + + (! runas testuser systemd-run --wait --user --pipe -p PrivatePIDs=yes true) + + if [[ "$HAS_EXISTING_SCSI_MOUNT" == "no" ]]; then + umount /proc/scsi + fi +} + +run_testcases |