#!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later set -eux set -o pipefail systemd-analyze log-level debug runas() { declare userid=$1 shift # shellcheck disable=SC2016 su "$userid" -s /bin/sh -c 'XDG_RUNTIME_DIR=/run/user/$UID exec "$@"' -- sh "$@" } runas testuser systemd-run --wait --user --unit=test-private-users \ -p PrivateUsers=yes -P echo hello runas testuser systemctl --user log-level debug runas testuser systemd-run --wait --user --unit=test-private-tmp-innerfile \ -p PrivateUsers=yes -p PrivateTmp=yes \ -P touch /tmp/innerfile.txt # File should not exist outside the job's tmp directory. test ! -e /tmp/innerfile.txt touch /tmp/outerfile.txt # File should not appear in unit's private tmp. runas testuser systemd-run --wait --user --unit=test-private-tmp-outerfile \ -p PrivateUsers=yes -p PrivateTmp=yes \ -P test ! -e /tmp/outerfile.txt # Confirm that creating a file in home works runas testuser systemd-run --wait --user --unit=test-unprotected-home \ -P touch /home/testuser/works.txt test -e /home/testuser/works.txt # Confirm that creating a file in home is blocked under read-only runas testuser systemd-run --wait --user --unit=test-protect-home-read-only \ -p PrivateUsers=yes -p ProtectHome=read-only \ -P bash -c ' test -e /home/testuser/works.txt || exit 10 touch /home/testuser/blocked.txt && exit 11 ' \ && { echo 'unexpected success'; exit 1; } test ! -e /home/testuser/blocked.txt # Check that tmpfs hides the whole directory runas testuser systemd-run --wait --user --unit=test-protect-home-tmpfs \ -p PrivateUsers=yes -p ProtectHome=tmpfs \ -P test ! -e /home/testuser # Confirm that home, /root, and /run/user are inaccessible under "yes" # shellcheck disable=SC2016 runas testuser systemd-run --wait --user --unit=test-protect-home-yes \ -p PrivateUsers=yes -p ProtectHome=yes \ -P bash -c ' test "$(stat -c %a /home)" = "0" test "$(stat -c %a /root)" = "0" test "$(stat -c %a /run/user)" = "0" ' # Confirm we cannot change groups because we only have one mapping in the user # namespace (no CAP_SETGID in the parent namespace to write the additional # mapping of the user supplied group and thus cannot change groups to an # unmapped group ID) runas testuser systemd-run --wait --user --unit=test-group-fail \ -p PrivateUsers=yes -p Group=daemon \ -P true \ && { echo 'unexpected success'; exit 1; } # Check that with a new user namespace we can bind mount # files and use a different root directory runas testuser systemd-run --wait --user --unit=test-bind-mount \ -p PrivateUsers=yes -p BindPaths=/dev/null:/etc/os-release \ test ! -s /etc/os-release runas testuser systemd-run --wait --user --unit=test-read-write \ -p PrivateUsers=yes -p ReadOnlyPaths=/ \ -p ReadWritePaths="/var /run /tmp" \ -p NoExecPaths=/ -p ExecPaths=/usr \ test ! -w /etc/os-release runas testuser systemd-run --wait --user --unit=test-caps \ -p PrivateUsers=yes -p AmbientCapabilities=CAP_SYS_ADMIN \ -p CapabilityBoundingSet=CAP_SYS_ADMIN \ test -s /etc/os-release runas testuser systemd-run --wait --user --unit=test-devices \ -p PrivateUsers=yes -p PrivateDevices=yes -p PrivateIPC=yes \ sh -c "ls -1 /dev/ | wc -l | grep -q -F 18" # Same check as test/test-execute/exec-privatenetwork-yes.service runas testuser systemd-run --wait --user --unit=test-network \ -p PrivateUsers=yes -p PrivateNetwork=yes \ /bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -Ev ": (lo|(erspan|gre|gretap|ip_vti|ip6_vti|ip6gre|ip6tnl|sit|tunl)0@.*):"' runas testuser systemd-run --wait --user --unit=test-hostname \ -p PrivateUsers=yes -p ProtectHostname=yes \ hostnamectl hostname foo \ && { echo 'unexpected success'; exit 1; } runas testuser systemd-run --wait --user --unit=test-clock \ -p PrivateUsers=yes -p ProtectClock=yes \ timedatectl set-time "2012-10-30 18:17:16" \ && { echo 'unexpected success'; exit 1; } runas testuser systemd-run --wait --user --unit=test-kernel-tunable \ -p PrivateUsers=yes -p ProtectKernelTunables=yes \ sh -c "echo 0 > /proc/sys/user/max_user_namespaces" \ && { echo 'unexpected success'; exit 1; } runas testuser systemd-run --wait --user --unit=test-kernel-mod \ -p PrivateUsers=yes -p ProtectKernelModules=yes \ sh -c "modprobe -r overlay && modprobe overlay" \ && { echo 'unexpected success'; exit 1; } if sysctl kernel.dmesg_restrict=0; then runas testuser systemd-run --wait --user --unit=test-kernel-log \ -p PrivateUsers=yes -p ProtectKernelLogs=yes -p LogNamespace=yes \ dmesg \ && { echo 'unexpected success'; exit 1; } fi unsquashfs -no-xattrs -d /tmp/img /usr/share/minimal_0.raw runas testuser systemd-run --wait --user --unit=test-root-dir \ -p PrivateUsers=yes -p RootDirectory=/tmp/img \ grep MARKER=1 /etc/os-release mkdir /tmp/img_bind mount --bind /tmp/img /tmp/img_bind runas testuser systemd-run --wait --user --unit=test-root-dir-bind \ -p PrivateUsers=yes -p RootDirectory=/tmp/img_bind -p MountFlags=private \ grep MARKER=1 /etc/os-release umount /tmp/img_bind # Unprivileged overlayfs was added to Linux 5.11, so try to detect it first mkdir -p /tmp/a /tmp/b /tmp/c if unshare --mount --user --map-root-user mount -t overlay overlay /tmp/c -o lowerdir=/tmp/a:/tmp/b; then unsquashfs -no-xattrs -d /tmp/app2 /usr/share/app1.raw runas testuser systemd-run --wait --user --unit=test-extension-dir \ -p PrivateUsers=yes -p ExtensionDirectories=/tmp/app2 \ -p TemporaryFileSystem=/run -p RootDirectory=/tmp/img \ -p MountAPIVFS=yes \ grep PORTABLE_PREFIXES=app1 /usr/lib/extension-release.d/extension-release.app2 fi systemd-analyze log-level info echo OK >/testok exit 0