 |
systemd-tests-257.5-alt2.x86_64 |
unsafe-tmp-usage-in-scripts |
fail |
The test discovered scripts with errors which may be used by a user for damaging important system files. For example if a script uses in its work a temp file which is created in /tmp directory, then every user can create symlinks with the same name (pattern) in this directory in order to destroy or rewrite some system or another user's files. Scripts _must_ _use_ mktemp/tempfile or must use $TMPDIR. mktemp/tempfile is safest. $TMPDIR is safer than /tmp/ because libpam-tmpdir creates a subdirectory of /tmp that is only accessible by that user, and then sets TMPDIR and other variables to that. Hence, it doesn't matter nearly as much if you create a non-random filename, because nobody but you can access it. Found error in /usr/lib/systemd/tests/testdata/units/TEST-87-AUX-UTILS-VM.modules-load.sh: $ grep /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-87-AUX-UTILS-VM.modules-load.sh "$MODULES_LOAD_BIN" # Explicit config file modprobe dummy printf "dummy" >"$CONFIG_FILE" "$MODULES_LOAD_BIN" "$CONFIG_FILE" |& tee /tmp/out.log grep "Inserted module .*dummy" /tmp/out.log # Implicit config file modprobe dummy printf "dummy" >"$CONFIG_FILE" "$MODULES_LOAD_BIN" |& tee /tmp/out.log grep "Inserted module .*dummy" /tmp/out.log # Valid & invalid data mixed together modprobe dummy cat >"$CONFIG_FILE" </tmp/core.redirected test -s /tmp/core.redirected coredumpctl dump -o /tmp/core.output "${CORE_TEST_BIN##*/}" test -s /tmp/core.output rm -f /tmp/core.{output,redirected} # Unprivileged stuff # Related issue: https://github.com/systemd/systemd/issues/26912 UNPRIV_CMD=(systemd-run --user --wait --pipe -M "testuser@.host" --) # Trigger a couple of coredumps as an unprivileged user -- "${UNPRIV_CMD[@]}" coredumpctl info "$CORE_TEST_UNPRIV_BIN" "${UNPRIV_CMD[@]}" coredumpctl info "${CORE_TEST_UNPRIV_BIN##*/}" (! "${UNPRIV_CMD[@]}" coredumpctl info --all "$CORE_TEST_BIN") (! "${UNPRIV_CMD[@]}" coredumpctl info --all "${CORE_TEST_BIN##*/}") # We should have a couple of externally stored coredumps "${UNPRIV_CMD[@]}" coredumpctl --field=COREDUMP_FILENAME | tee /tmp/coredumpctl.out grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out rm -f /tmp/coredumpctl.out "${UNPRIV_CMD[@]}" coredumpctl debug --debugger=/bin/true "$CORE_TEST_UNPRIV_BIN" "${UNPRIV_CMD[@]}" coredumpctl debug --debugger=/bin/true --debugger-arguments="-this --does --not 'do anything' -a -t --all" "${CORE_TEST_UNPRIV_BIN##*/}" "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_UNPRIV_BIN" >/tmp/core.redirected test -s /tmp/core.redirected "${UNPRIV_CMD[@]}" coredumpctl dump -o /tmp/core.output "${CORE_TEST_UNPRIV_BIN##*/}" test -s /tmp/core.output rm -f /tmp/core.{output,redirected} (! "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_BIN" >/dev/null) # --backtrace mode # Pass one of the existing journal coredump records to systemd-coredump and # use our PID as the source to make matching the coredump later easier Found error in /usr/lib/systemd/tests/testdata/units/TEST-87-AUX-UTILS-VM.bootctl.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-87-AUX-UTILS-VM.bootctl.sh return 0 ) testcase_bootctl_image() { IMAGE_DIR="$(mktemp --directory /tmp/test-bootctl.XXXXXXXXXX)" trap cleanup_image RETURN truncate -s 256m "${IMAGE_DIR}/image" cat >"${IMAGE_DIR}/partscript" </dev/null; then echo "mkfs.btrfs not found, skipping." return 0 fi IMAGE_DIR="$(mktemp --directory /tmp/test-bootctl.XXXXXXXXXX)" trap cleanup_raid RETURN truncate -s 256m "${IMAGE_DIR}/image1" truncate -s 256m "${IMAGE_DIR}/image2" -- SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.SetRebootToFirmware '{"state":true}' --graceful=io.systemd.BootControl.RebootToFirmwareNotSupported SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.SetRebootToFirmware '{"state":false}' --graceful=io.systemd.BootControl.RebootToFirmwareNotSupported } testcase_bootctl_secure_boot_auto_enroll() { cat >/tmp/openssl.conf </tmp/nextroot-lower/lower # Copy os-release away, so that we can manipulate it and check that it is updated in the propagate # directory across soft reboots. Try to cover corner cases by truncating it. mkdir -p /tmp/nextroot-lower/etc grep ID /etc/os-release >/tmp/nextroot-lower/etc/os-release echo MARKER=1 >>/tmp/nextroot-lower/etc/os-release cmp /etc/os-release /run/systemd/propagate/.os-release-stage/os-release (! grep -q MARKER=1 /etc/os-release) mount -t overlay nextroot /run/nextroot -o lowerdir=/tmp/nextroot-lower:/,ro # Bind our current root into the target so that we later can return to it mount --bind / /run/nextroot/original-root # Restart the unit that is not supposed to survive -- systemd-run --collect --service-type=exec -p DefaultDependencies=no -p IgnoreOnIsolate=yes -p SetCredential=gone:hoge --unit=TEST-82-SOFTREBOOT-nosurvive.service sleep infinity # Ensure that the unit doesn't get deactivated by dependencies on the source file. Given it's a verity # image that is already open, even if the tmpfs with the image goes away, the file will be pinned by the # kernel and will keep working. cp /usr/share/minimal_0.* /tmp/ # Configure these transient units to survive the soft reboot - they will not conflict with shutdown.target # and it will be ignored on the isolate that happens in the next boot. The first will use argv[0][0] = # '@', and the second will use SurviveFinalKillSignal=yes. Both should survive. # By writing to stdout, which is connected to the journal, we also ensure logging doesn't break across -- --property SetCredential=preserve:yay \ "$survive_argv" # shellcheck disable=SC2016 systemd-run --service-type=exec --unit=TEST-82-SOFTREBOOT-survive.service \ --property TemporaryFileSystem="/run /tmp /var" \ --property RootImage=/tmp/minimal_0.raw \ --property SurviveFinalKillSignal=yes \ --property IgnoreOnIsolate=yes \ --property DefaultDependencies=no \ --property After=basic.target \ --property "Conflicts=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ Found error in /usr/lib/systemd/tests/testdata/units/TEST-81-GENERATORS.system-update-generator.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-81-GENERATORS.system-update-generator.sh # shellcheck source=test/units/generator-utils.sh . "$(dirname "$0")/generator-utils.sh" GENERATOR_BIN="/usr/lib/systemd/system-generators/systemd-system-update-generator" OUT_DIR="$(mktemp -d /tmp/system-update-generator-generator.XXX)" at_exit() { rm -frv "${OUT_DIR:?}" /system-update } -- link_endswith "$OUT_DIR/early/default.target" "/lib/systemd/system/system-update.target" : "system-update-generator: kernel cmdline warnings" # We should warn if the default target is overridden on the kernel cmdline # by a runlevel or systemd.unit=, but still generate the symlink SYSTEMD_PROC_CMDLINE="systemd.unit=foo.bar 3" run_and_list "$GENERATOR_BIN" "$OUT_DIR" |& tee /tmp/system-update-generator.log link_endswith "$OUT_DIR/early/default.target" "/lib/systemd/system/system-update.target" grep -qE "Offline system update overridden .* systemd.unit=" /tmp/system-update-generator.log grep -qE "Offline system update overridden .* runlevel" /tmp/system-update-generator.log Found error in /usr/lib/systemd/tests/testdata/units/TEST-81-GENERATORS.getty-generator.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-81-GENERATORS.getty-generator.sh # shellcheck source=test/units/generator-utils.sh . "$(dirname "$0")/generator-utils.sh" GENERATOR_BIN="/usr/lib/systemd/system-generators/systemd-getty-generator" OUT_DIR="$(mktemp -d /tmp/getty-generator.XXX)" at_exit() { rm -frv "${OUT_DIR:?}" } -- done # Sneak in one "not-a-tty" console touch /dev/notatty99 # Temporarily replace /sys/class/tty/console/active with our list of dummy # consoles so getty-generator can process them echo -ne "${DUMMY_ACTIVE_CONSOLES[@]}" /dev/notatty99 >/tmp/dummy-active-consoles mount -v --bind /tmp/dummy-active-consoles /sys/class/tty/console/active : "getty-generator: no arguments" # Sneak in an invalid value for $SYSTEMD_GETTY_AUTO to test things out PID1_ENVIRON="SYSTEMD_GETTY_AUTO=foo" run_and_list "$GENERATOR_BIN" "$OUT_DIR" for console in "${DUMMY_ACTIVE_CONSOLES[@]}"; do Found error in /usr/lib/systemd/tests/testdata/units/TEST-80-NOTIFYACCESS.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-80-NOTIFYACCESS.sh set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh mkfifo /tmp/syncfifo1 /tmp/syncfifo2 sync_in() { read -r x < /tmp/syncfifo1 test "$x" = "$1" } sync_out() { echo "$1" > /tmp/syncfifo2 } export SYSTEMD_LOG_LEVEL=debug # Test NotifyAccess= override through sd_notify() -- assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "none" systemctl stop notify.service assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "all" rm /tmp/syncfifo1 /tmp/syncfifo2 # Explicitly test busctl's BUSERROR= reporting and systemctl status should show it (! systemd-run --wait --unit="TEST-80-BUSERROR.service" -p NotifyAccess=main busctl introspect org.freedesktop.systemd1 /bogus/001) assert_eq "$(systemctl show TEST-80-BUSERROR.service -P StatusBusError)" "org.freedesktop.DBus.Error.UnknownObject" assert_in "D-Bus: org.freedesktop.DBus.Error.UnknownObject" "$(systemctl status TEST-80-BUSERROR.service)" # Now test basic fdstore behaviour MYSCRIPT="/tmp/myscript$RANDOM.sh" cat >> "$MYSCRIPT" <<'EOF' #!/usr/bin/env bash set -eux set -o pipefail test "$FDSTORE" -eq 7 N="/tmp/$RANDOM" echo $RANDOM > "$N" systemd-notify --fd=4 --fdname=quux --pid=parent 4< "$N" rm "$N" systemd-notify --ready exec sleep infinity -- MYUNIT="myunit$RANDOM.service" systemd-run -u "$MYUNIT" -p Type=notify -p FileDescriptorStoreMax=7 "$MYSCRIPT" test "$(systemd-analyze fdstore "$MYUNIT" | wc -l)" -eq 2 systemd-analyze fdstore "$MYUNIT" --json=short systemd-analyze fdstore "$MYUNIT" --json=short | grep -P -q '\[{"fdname":"quux","type":.*,"devno":\[.*\],"inode":.*,"rdevno":null,"path":"/tmp/.*","flags":"ro"}\]' systemctl stop "$MYUNIT" rm "$MYSCRIPT" systemd-analyze log-level debug Found error in /usr/lib/systemd/tests/testdata/units/TEST-76-SYSCTL.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-76-SYSCTL.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh export SYSTEMD_LOG_LEVEL=debug echo "foo.bar=42" >/tmp/foo.conf assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf assert_rc 1 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf echo "-foo.foo=42" >/tmp/foo.conf assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf if ! systemd-detect-virt --quiet --container; then ip link add hoge type dummy udevadm wait /sys/class/net/hoge cat >/tmp/foo.conf </proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp echo 0 >/proc/sys/net/ipv4/conf/hoge/bootp_relay echo 0 >/proc/sys/net/ipv4/conf/hoge/disable_policy assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge /tmp/foo.conf assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1" assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1" assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0" fi Found error in /usr/lib/systemd/tests/testdata/units/TEST-75-RESOLVED.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-75-RESOLVED.sh systemctl reload systemd-resolved.service resolvectl status resolvectl dns dns0 | grep -qF "1.1.1.1" # For some reason piping this last command to grep fails with: # 'resolvectl[1378]: Failed to print table: Broken pipe' # so use an intermediate file in /tmp/ resolvectl >/tmp/output grep -qF "DNS Servers: 8.8.8.8" /tmp/output # Check if resolved exits cleanly. restart_resolved } Found error in /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.socket.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.socket.sh systemctl daemon-reload systemctl start per-source-limit.socket systemctl status per-source-limit.socket # So these two should take up the first two connection slots socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn1 & J1="$!" socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn2 & J2="$!" waitfor() { local file="${1:?}" -- echo >&2 "Timeout while waiting for the expected output" return 1 } # Wait until the word "waldo" shows in the output files waitfor /tmp/foo.conn1 waitfor /tmp/foo.conn2 # The next connection should fail, because the limit is hit socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn3 & J3="$!" # But this one should work, because done under a different UID setpriv --reuid=1 socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn4 & J4="$!" waitfor /tmp/foo.conn4 # The third job should fail quickly, wait for it wait "$J3" # The other jobs will hang forever, since we run "sleep infinity" on the server side. Let's kill the jobs now. kill "$J1" kill "$J2" kill "$J4" # The 3rd connection should not have seen "waldo", since it should have been refused too early (! grep -q "waldo" /tmp/foo.conn3 ) Found error in /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.sbsign.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.sbsign.sh if [[ ! -d /usr/lib/systemd/boot/efi ]]; then echo "systemd-boot is not installed, skipping." exit 0 fi cat >/tmp/openssl.conf </dev/null; then echo "sbverify not found, skipping." exit 0 fi SD_BOOT="$(find /usr/lib/systemd/boot/efi/ -name "systemd-boot*.efi" | head -n1)" (! sbverify --cert /tmp/sb.crt "$SD_BOOT") /usr/lib/systemd/systemd-sbsign sign --certificate /tmp/sb.crt --private-key /tmp/sb.key --output /tmp/sdboot "$SD_BOOT" sbverify --cert /tmp/sb.crt /tmp/sdboot # Make sure appending signatures to an existing certificate table works as well. /usr/lib/systemd/systemd-sbsign sign --certificate /tmp/sb.crt --private-key /tmp/sb.key --output /tmp/sdboot /tmp/sdboot sbverify --cert /tmp/sb.crt /tmp/sdboot } run_testcases Found error in /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.keyutil.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-74-AUX-UTILS.keyutil.sh if ! command -v /usr/lib/systemd/systemd-keyutil >/dev/null; then echo "systemd-keyutil not found, skipping." exit 0 fi cat >/tmp/openssl.conf </tmp/borked set +e SYSTEMD_MEASURE_LOG_USERSPACE=/tmp/borked "$SD_PCRLOCK" cel --no-pager --json=pretty ret=$? set -e # If it crashes the exit code will be 149 test $ret -eq 1 -- PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=query # Repeat immediately (this call will have to reuse the nvindex, rather than create it) "$SD_PCRLOCK" make-policy --pcr="$PCRS" "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force img="/tmp/pcrlock.img" truncate -s 20M "$img" echo -n hoho >/tmp/pcrlockpwd chmod 0600 /tmp/pcrlockpwd cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$img" /tmp/pcrlockpwd systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --tpm2-public-key= --wipe-slot=tpm2 "$img" systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless systemd-cryptsetup detach pcrlock # Ensure systemd-pcrlock not crashing on empty variant directory mkdir -p /var/lib/pcrlock.d/123-empty.pcrlock.d -- openssl rsa -pubout -in "$img".private.pem -out "$img".public.pem systemd-cryptenroll --unlock-tpm2-device=auto --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --tpm2-public-key="$img".public.pem --wipe-slot=tpm2 "$img" "$SD_MEASURE" sign --current --bank=sha256 --private-key="$img".private.pem --public-key="$img".public.pem --phase=: | tee "$img".pcrsign SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup attach pcrlock "$img" - "tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,tpm2-signature=$img.pcrsign,headless" systemd-cryptsetup detach pcrlock systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --tpm2-public-key= --wipe-slot=tpm2 "$img" rm "$img".public.pem "$img".private.pem "$img".pcrsign # Now use the root fs support, i.e. make the tool write a copy of the pcrlock # file as service credential to some temporary dir and remove the local copy, so that # it has to use the credential version. mkdir /tmp/fakexbootldr SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force mv /var/lib/systemd/pcrlock.json /var/lib/systemd/pcrlock.json.gone ls -al /tmp/fakexbootldr/loader/credentials CREDENTIAL_FILE="$(echo /tmp/fakexbootldr/loader/credentials/pcrlock.*.cred)" test -f "$CREDENTIAL_FILE" # Strip dir and .cred suffix from file name. CREDENTIAL_NAME=${CREDENTIAL_FILE#/tmp/fakexbootldr/loader/credentials/} CREDENTIAL_NAME=${CREDENTIAL_NAME%.cred} systemd-creds decrypt --name="$CREDENTIAL_NAME" "$CREDENTIAL_FILE" ln -s "$CREDENTIAL_FILE" /tmp/fakexbootldr/loader/credentials/"$CREDENTIAL_NAME" test -f /tmp/fakexbootldr/loader/credentials/"$CREDENTIAL_NAME" SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY=/tmp/fakexbootldr/loader/credentials systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,headless systemd-cryptsetup detach pcrlock mv /var/lib/systemd/pcrlock.json.gone /var/lib/systemd/pcrlock.json SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" remove-policy "$SD_PCRLOCK" unlock-firmware-config "$SD_PCRLOCK" unlock-gpt "$SD_PCRLOCK" unlock-machine-id "$SD_PCRLOCK" unlock-file-system -- varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.RemovePolicy '{}' varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.MakePolicy '{}' varlinkctl call --collect --json=pretty /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.ReadEventLog '{}' rm "$img" /tmp/pcrlockpwd # For issue #35746 for _ in {0..10}; do run0 /usr/lib/systemd/systemd-pcrlock done Found error in /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.measure.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.measure.sh if [[ ! -x "${SD_MEASURE:?}" ]]; then echo "$SD_MEASURE not found, skipping the test" exit 0 fi IMAGE="$(mktemp /tmp/systemd-measure-XXX.image)" echo HALLO >/tmp/tpmdata1 echo foobar >/tmp/tpmdata2 cat >/tmp/result </tmp/result.json </tmp/result </tmp/result.json </dev/null; then MEASURE_BANKS+=("--bank=sha1") fi # Sign current PCR state with it "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: | tee "/tmp/pcrsign.sig" dd if=/dev/urandom of=/tmp/pcrtestdata bs=1024 count=64 systemd-creds encrypt /tmp/pcrtestdata /tmp/pcrtestdata.encrypted --with-key=host+tpm2-with-public-key --tpm2-public-key="/tmp/pcrsign-public.pem" systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" | cmp - /tmp/pcrtestdata # Invalidate PCR, decrypting should fail now tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 (! systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" >/dev/null) # Sign new PCR state, decrypting should work now. "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: >"/tmp/pcrsign.sig2" systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig2" | cmp - /tmp/pcrtestdata # Now, do the same, but with a cryptsetup binding truncate -s 20M "$IMAGE" cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$IMAGE" /tmp/passphrase # Ensure that an unrelated signature, when not requested, is not used touch /run/systemd/tpm2-pcr-signature.json systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto --tpm2-public-key="/tmp/pcrsign-public.pem" "$IMAGE" # Reset and use the signature now rm -f /run/systemd/tpm2-pcr-signature.json systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto --tpm2-public-key="/tmp/pcrsign-public.pem" --tpm2-signature="/tmp/pcrsign.sig2" "$IMAGE" # Check if we can activate that (without the token module stuff) SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup detach test-volume2 # Check if we can activate that (and a second time with the token module stuff enabled) SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 systemd-cryptsetup detach test-volume2 # After extending the PCR things should fail tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 (! SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1) (! SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1) # But once we sign the current PCRs, we should be able to unlock again "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: >"/tmp/pcrsign.sig3" SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1 systemd-cryptsetup detach test-volume2 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1 systemd-cryptsetup detach test-volume2 # Test --append mode and de-duplication. With the same parameters signing should not add a new entry "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: --append="/tmp/pcrsign.sig3" >"/tmp/pcrsign.sig4" cmp "/tmp/pcrsign.sig3" "/tmp/pcrsign.sig4" # Sign one more phase, this should "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=quux:waldo --append="/tmp/pcrsign.sig4" >"/tmp/pcrsign.sig5" (! cmp "/tmp/pcrsign.sig4" "/tmp/pcrsign.sig5") # Should still be good to unlock, given the old entry still exists SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 systemd-cryptsetup attach test-volume2 "$IMAGE" - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig5",headless=1 systemd-cryptsetup detach test-volume2 # Adding both signatures once more should not change anything, due to the deduplication "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: --append="/tmp/pcrsign.sig5" >"/tmp/pcrsign.sig6" "$SD_MEASURE" sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=quux:waldo --append="/tmp/pcrsign.sig6" >"/tmp/pcrsign.sig7" cmp "/tmp/pcrsign.sig5" "/tmp/pcrsign.sig7" rm -f "$IMAGE" Found error in /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.cryptsetup.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.cryptsetup.sh } trap at_exit EXIT # Prepare a fresh disk image IMAGE="$(mktemp /tmp/systemd-cryptsetup-XXX.IMAGE)" truncate -s 20M "$IMAGE" echo -n passphrase >/tmp/passphrase # Change file mode to avoid "/tmp/passphrase has 0644 mode that is too permissive" messages chmod 0600 /tmp/passphrase cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$IMAGE" /tmp/passphrase # Unlocking via keyfile systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto "$IMAGE" # Enroll unlock with default PCR policy PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto "$IMAGE" systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 systemd-cryptsetup detach test-volume -- systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 systemd-cryptsetup detach test-volume # Now the interesting part, enrolling using a hash value that doesn't match the current PCR value systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12 CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) EXPECTED_PCR_VALUE=$(cat /tmp/pcr.dat /tmp/pcr.dat | openssl dgst -sha256 -r | cut -d ' ' -f 1) PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="12:sha256=$EXPECTED_PCR_VALUE" "$IMAGE" (! systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1) tpm2_pcrextend "12:sha256=$CURRENT_PCR_VALUE" systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 systemd-cryptsetup detach test-volume # enroll TPM using device key instead of direct access, then verify unlock using TPM tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12 CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) tpm2_readpublic -c 0x81000001 -o /tmp/srk.pub systemd-analyze srk > /tmp/srk2.pub cmp /tmp/srk.pub /tmp/srk2.pub if [ -f /run/systemd/tpm2-srk-public-key.tpm2b_public ] ; then cmp /tmp/srk.pub /run/systemd/tpm2-srk-public-key.tpm2b_public fi # --tpm2-device-key= requires OpenSSL >= 3 with KDF-SS if openssl_supports_kdf SSKDF; then PASSWORD=passphrase systemd-cryptenroll --tpm2-device-key=/tmp/srk.pub --tpm2-pcrs="12:sha256=$CURRENT_PCR_VALUE" "$IMAGE" systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 systemd-cryptsetup detach test-volume fi rm -f /tmp/pcr.dat /tmp/srk.pub fi # Use default (0) seal key handle systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0 "$IMAGE" -- (! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x02000001 "$IMAGE") # HMAC/loaded session (! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x03000001 "$IMAGE") # Policy/saved session (! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x40000001 "$IMAGE") # Permanent # Use non-SRK persistent seal key handle (by creating/persisting new key) PRIMARY=/tmp/primary.ctx tpm2_createprimary -c "$PRIMARY" PERSISTENT_LINE=$(tpm2_evictcontrol -c "$PRIMARY" | grep persistent-handle) PERSISTENT_HANDLE="0x${PERSISTENT_LINE##*0x}" tpm2_flushcontext -t -- systemd-cryptsetup detach test-volume # --tpm2-device-key= requires OpenSSL >= 3 with KDF-SS if openssl_supports_kdf SSKDF; then # Make sure that --tpm2-device-key= also works with systemd-repart tpm2_readpublic -c 0x81000001 -o /tmp/srk.pub mkdir /tmp/dditest cat > /tmp/dditest/50-root.conf </tmp/cryptenroll.out systemd-cryptenroll "$@" |& tee /tmp/cryptenroll.out grep -qE "Wiped slot [[:digit:]]+" /tmp/cryptenroll.out )} # There is an external issue with libcryptsetup on ppc64 that hits 95% of Ubuntu ppc64 test runs, so skip it if [[ "$(uname -m)" == "ppc64le" ]]; then echo "Skipping systemd-cryptenroll tests on ppc64le, see https://github.com/systemd/systemd/issues/27716" exit 0 fi export SYSTEMD_LOG_LEVEL=debug IMAGE="$(mktemp /tmp/systemd-cryptenroll-XXX.image)" truncate -s 20M "$IMAGE" echo -n password >/tmp/password # Change file mode to avoid "/tmp/password has 0644 mode that is too permissive" messages chmod 0600 /tmp/password cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$IMAGE" /tmp/password # Enroll additional tokens, keys, and passwords to exercise the list and wipe stuff systemd-cryptenroll --unlock-key-file=/tmp/password --tpm2-device=auto "$IMAGE" NEWPASSWORD="" systemd-cryptenroll --unlock-key-file=/tmp/password --password "$IMAGE" NEWPASSWORD=foo systemd-cryptenroll --unlock-key-file=/tmp/password --password "$IMAGE" for _ in {0..9}; do systemd-cryptenroll --unlock-key-file=/tmp/password --recovery-key "$IMAGE" done PASSWORD="" NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true "$IMAGE" # Do some basic checks before we start wiping stuff systemd-cryptenroll "$IMAGE" systemd-cryptenroll "$IMAGE" | grep password -- (! systemd-cryptenroll "$IMAGE" | grep recovery) # We shouldn't be able to wipe all keyslots without enrolling a new key first (! systemd-cryptenroll "$IMAGE" --wipe=all) PASSWORD=foo NEWPASSWORD=foo cryptenroll_wipe_and_check "$IMAGE" --password --wipe=all # Check if the newly (and only) enrolled password works (! systemd-cryptenroll --unlock-key-file=/tmp/password --recovery-key "$IMAGE") (! PASSWORD="" systemd-cryptenroll --recovery-key "$IMAGE") PASSWORD=foo systemd-cryptenroll --recovery-key "$IMAGE" systemd-cryptenroll --fido2-with-client-pin=false "$IMAGE" systemd-cryptenroll --fido2-with-user-presence=false "$IMAGE" -- # Change PIN on TPM2 enrollment PIN=1234 NEWPIN=4321 systemd-cryptenroll --unlock-tpm2-device=auto --tpm2-device=auto --tpm2-with-pin=yes "$IMAGE" PIN=4321 systemd-cryptenroll --unlock-tpm2-device=auto --recovery-key "$IMAGE" (! systemd-cryptenroll --fido2-with-client-pin=false) (! systemd-cryptenroll --fido2-with-user-presence=f "$IMAGE" /tmp/foo) (! systemd-cryptenroll --fido2-with-client-pin=1234 "$IMAGE") (! systemd-cryptenroll --fido2-with-user-presence=1234 "$IMAGE") (! systemd-cryptenroll --fido2-with-user-verification=1234 "$IMAGE") (! systemd-cryptenroll --tpm2-with-pin=1234 "$IMAGE") (! systemd-cryptenroll --recovery-key --password "$IMAGE") (! systemd-cryptenroll --password --recovery-key "$IMAGE") (! systemd-cryptenroll --password --fido2-device=auto "$IMAGE") (! systemd-cryptenroll --password --pkcs11-token-uri=auto "$IMAGE") (! systemd-cryptenroll --password --tpm2-device=auto "$IMAGE") (! systemd-cryptenroll --unlock-fido2-device=auto --unlock-fido2-device=auto "$IMAGE") (! systemd-cryptenroll --unlock-fido2-device=auto --unlock-key-file=/tmp/unlock "$IMAGE") (! systemd-cryptenroll --fido2-credential-algorithm=es512 "$IMAGE") (! systemd-cryptenroll --tpm2-public-key-pcrs=key "$IMAGE") (! systemd-cryptenroll --tpm2-pcrs=key "$IMAGE") (! systemd-cryptenroll --tpm2-pcrs=44+8 "$IMAGE") (! systemd-cryptenroll --tpm2-pcrs=hello "$IMAGE") Found error in /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.creds.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-70-TPM2.creds.sh set -o pipefail export SYSTEMD_LOG_LEVEL=debug # Ensure that sandboxing doesn't stop creds from being accessible echo "test" > /tmp/testdata systemd-creds encrypt /tmp/testdata /tmp/testdata.encrypted --with-key=tpm2 # LoadCredentialEncrypted systemd-run -p PrivateDevices=yes -p LoadCredentialEncrypted=testdata.encrypted:/tmp/testdata.encrypted --pipe --wait systemd-creds cat testdata.encrypted | cmp - /tmp/testdata # SetCredentialEncrypted systemd-run -p PrivateDevices=yes -p SetCredentialEncrypted=testdata.encrypted:"$(cat /tmp/testdata.encrypted)" --pipe --wait systemd-creds cat testdata.encrypted | cmp - /tmp/testdata rm -f /tmp/testdata Found error in /usr/lib/systemd/tests/testdata/units/TEST-68-PROPAGATE-EXIT-STATUS.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-68-PROPAGATE-EXIT-STATUS.sh ExecStart=sh -c "exit 0" EOF # Script to check that when an OnSuccess= dependency fires, the correct # MONITOR* env variables are passed. cat >/tmp/check_on_success.sh <<"EOF" #!/bin/sh set -ex env | sort if [ "$MONITOR_SERVICE_RESULT" != "success" ]; then -- exit 1 fi exit 0 EOF chmod +x /tmp/check_on_success.sh cat >/run/systemd/system/testservice-success-exit-handler-68.service </run/systemd/system/testservice-success-exit-handler-68-template@.service </tmp/check_on_failure.sh <<"EOF" #!/bin/sh set -ex env | sort if [ "$MONITOR_SERVICE_RESULT" != "exit-code" ]; then -- exit 1 fi exit 0 EOF chmod +x /tmp/check_on_failure.sh cat >/run/systemd/system/testservice-failure-exit-handler-68.service </run/systemd/system/testservice-failure-exit-handler-68-template@.service </tmp/out1 chroot /tmp/root systemd-analyze cat-config systemd/system-preset >/tmp/out2 diff /tmp/out{1,2} fi # verify mkdir -p /tmp/img/usr/lib/systemd/system/ mkdir -p /tmp/img/opt/ touch /tmp/img/opt/script0.sh chmod +x /tmp/img/opt/script0.sh cat </tmp/img/usr/lib/systemd/system/testfile.service [Service] ExecStart = /opt/script0.sh EOF set +e # Default behaviour is to recurse through all dependencies when unit is loaded (! systemd-analyze verify --root=/tmp/img/ testfile.service) # As above, recurses through all dependencies when unit is loaded (! systemd-analyze verify --recursive-errors=yes --root=/tmp/img/ testfile.service) # Recurses through unit file and its direct dependencies when unit is loaded (! systemd-analyze verify --recursive-errors=one --root=/tmp/img/ testfile.service) set -e # zero exit status since dependencies are ignored when unit is loaded systemd-analyze verify --recursive-errors=no --root=/tmp/img/ testfile.service rm /tmp/img/usr/lib/systemd/system/testfile.service cat </tmp/testfile.service [Unit] foo = bar [Service] ExecStart = echo hello EOF cat </tmp/testfile2.service [Unit] Requires = testfile.service [Service] ExecStart = echo hello EOF # Zero exit status since no additional dependencies are recursively loaded when the unit file is loaded systemd-analyze verify --recursive-errors=no /tmp/testfile2.service set +e # Non-zero exit status since all associated dependencies are recursively loaded when the unit file is loaded (! systemd-analyze verify --recursive-errors=yes /tmp/testfile2.service) set -e rm /tmp/testfile.service rm /tmp/testfile2.service cat </tmp/sample.service [Unit] Description = A Sample Service [Service] ExecStart = echo hello Slice=support.slice EOF # Zero exit status since no additional dependencies are recursively loaded when the unit file is loaded systemd-analyze verify --recursive-errors=no /tmp/sample.service cat </tmp/testfile.service [Service] ExecStart = echo hello DeviceAllow=/dev/sda EOF # Prevent regression from #13380 and #20859 where we can't verify hidden files cp /tmp/testfile.service /tmp/.testfile.service systemd-analyze verify /tmp/.testfile.service rm /tmp/.testfile.service # Alias a unit file's name on disk (see #20061) cp /tmp/testfile.service /tmp/testsrvc (! systemd-analyze verify /tmp/testsrvc) systemd-analyze verify /tmp/testsrvc:alias.service # Zero exit status since the value used for comparison determine exposure to security threats is by default 100 systemd-analyze security --offline=true /tmp/testfile.service #The overall exposure level assigned to the unit is greater than the set threshold (! systemd-analyze security --threshold=90 --offline=true /tmp/testfile.service) # Ensure we print the list of ACLs, see https://github.com/systemd/systemd/issues/23185 systemd-analyze security --offline=true /tmp/testfile.service | grep -q -F "/dev/sda" # Make sure that running generators under systemd-analyze verify works. # Note: sd-analyze spawns generators in a sandbox which makes gcov unhapy, so temporarily override # $GCOV_PREFIX to make it skip generating any coverage reports GCOV_PREFIX=/tmp systemd-analyze verify --generators /tmp/testfile.service rm /tmp/testfile.service cat </tmp/img/usr/lib/systemd/system/testfile.service [Service] ExecStart = echo hello PrivateNetwork = yes PrivateDevices = yes PrivateUsers = yes EOF # The new overall exposure level assigned to the unit is less than the set thresholds # Verifies that the --offline= option works with --root= systemd-analyze security --threshold=90 --offline=true --root=/tmp/img/ testfile.service cat </tmp/foo@.service [Service] ExecStart=ls EOF cat </tmp/hoge@test.service [Service] ExecStart=ls EOF # issue #30357 -- systemd-analyze verify tmp/hoge@test.service (! systemd-analyze verify tmp/hoge@nonexist.service) (! systemd-analyze verify tmp/hoge@.service) popd pushd /usr systemd-analyze verify ../tmp/foo@bar.service systemd-analyze verify ../tmp/foo@.service systemd-analyze verify ../tmp/hoge@test.service (! systemd-analyze verify ../tmp/hoge@nonexist.service) (! systemd-analyze verify ../tmp/hoge@.service) popd systemd-analyze verify /tmp/foo@bar.service systemd-analyze verify /tmp/foo@.service systemd-analyze verify /tmp/hoge@test.service (! systemd-analyze verify /tmp/hoge@nonexist.service) (! systemd-analyze verify /tmp/hoge@.service) # test that all commands are verified. cat </tmp/multi-exec-start.service [Service] Type=oneshot ExecStart=true ExecStart=ls EOF systemd-analyze verify /tmp/multi-exec-start.service echo 'ExecStart=command-should-not-exist' >>/tmp/multi-exec-start.service (! systemd-analyze verify /tmp/multi-exec-start.service) # Prevent regression from #20233 where systemd-analyze will return nonzero exit codes on warnings # Unit file with warning "Unknown key name 'foo' in section 'Unit', ignoring" cat </tmp/testwarnings.service [Unit] Foo=Bar [Service] ExecStart=echo hello EOF # yes/no/one should all return nonzero exit status for warnings in unit file (! systemd-analyze verify --recursive-errors=yes /tmp/testwarnings.service) (! systemd-analyze verify --recursive-errors=no /tmp/testwarnings.service) (! systemd-analyze verify --recursive-errors=one /tmp/testwarnings.service) # zero exit status since no errors and only warnings systemd-analyze verify /tmp/testwarnings.service rm /tmp/testwarnings.service # Added an additional "INVALID_ID" id to the .json to verify that nothing breaks when input is malformed # The PrivateNetwork id description and weight was changed to verify that 'security' is actually reading in # values from the .json file when required. The default weight for "PrivateNetwork" is 2500, and the new weight # assigned to that id in the .json file is 6000. This increased weight means that when the "PrivateNetwork" key is # set to 'yes' (as above in the case of testfile.service) in the content of the unit file, the overall exposure # level for the unit file should decrease to account for that increased weight. cat </tmp/testfile.json {"UserOrDynamicUser": {"description_bad": "Service runs as root user", "weight": 0, "range": 10 }, -- } EOF # Reads in custom security requirements from the parsed .json file and uses these for comparison systemd-analyze security --threshold=90 --offline=true \ --security-policy=/tmp/testfile.json \ --root=/tmp/img/ testfile.service # The strict profile adds a lot of sanboxing options systemd-analyze security --threshold=25 --offline=true \ --security-policy=/tmp/testfile.json \ --profile=strict \ --root=/tmp/img/ testfile.service # The trusted profile doesn't add any sanboxing options (! systemd-analyze security --threshold=25 --offline=true \ --security-policy=/tmp/testfile.json \ --profile=/usr/lib/systemd/portable/profile/trusted/service.conf \ --root=/tmp/img/ testfile.service) (! systemd-analyze security --threshold=50 --offline=true \ --security-policy=/tmp/testfile.json \ --root=/tmp/img/ testfile.service) rm /tmp/img/usr/lib/systemd/system/testfile.service if systemd-analyze --version | grep -q -F "+ELFUTILS"; then systemd-analyze inspect-elf --json=short /lib/systemd/systemd | grep -q -F '"elfType":"executable"' fi Found error in /usr/lib/systemd/tests/testdata/units/TEST-63-PATH.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-63-PATH.sh systemctl log-level debug # Test that a path unit continuously triggering a service that fails condition checks eventually fails with # the trigger-limit-hit error. rm -f /tmp/nonexistent systemctl start test63.path touch /tmp/test63 # Make sure systemd has sufficient time to hit the trigger limit for test63.path. # shellcheck disable=SC2016 timeout 30 bash -c 'until test "$(systemctl show test63.path -P ActiveState)" = failed; do sleep .2; done' test "$(systemctl show test63.service -P ActiveState)" = inactive test "$(systemctl show test63.service -P Result)" = success test "$(systemctl show test63.path -P Result)" = trigger-limit-hit # Test that starting the service manually doesn't affect the path unit. rm -f /tmp/test63 systemctl reset-failed systemctl start test63.path systemctl start test63.service test "$(systemctl show test63.service -P ActiveState)" = inactive test "$(systemctl show test63.service -P Result)" = success test "$(systemctl show test63.path -P ActiveState)" = active test "$(systemctl show test63.path -P Result)" = success # Test that glob matching works too, with $TRIGGER_PATH systemctl start test63-glob.path touch /tmp/test63-glob-foo timeout 60 bash -c 'until systemctl -q is-active test63-glob.service; do sleep .2; done' test "$(systemctl show test63-glob.service -P ActiveState)" = active test "$(systemctl show test63-glob.service -P Result)" = success test "$(busctl --json=short get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/test63_2dglob_2eservice org.freedesktop.systemd1.Unit ActivationDetails)" = '{"type":"a(ss)","data":[["trigger_unit","test63-glob.path"],["trigger_path","/tmp/test63-glob-foo"]]}' systemctl stop test63-glob.path test63-glob.service test "$(busctl --json=short get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/test63_2dglob_2eservice org.freedesktop.systemd1.Unit ActivationDetails)" = '{"type":"a(ss)","data":[]}' # tests for issue https://github.com/systemd/systemd/issues/24577#issuecomment-1522628906 rm -f /tmp/hoge systemctl start test63-issue-24577.path systemctl status -n 0 test63-issue-24577.path systemctl status -n 0 test63-issue-24577.service || : systemctl list-jobs output=$(systemctl list-jobs --no-legend) assert_not_in "test63-issue-24577.service" "$output" assert_not_in "test63-issue-24577-dep.service" "$output" touch /tmp/hoge systemctl status -n 0 test63-issue-24577.path systemctl status -n 0 test63-issue-24577.service || : systemctl list-jobs output=$(systemctl list-jobs --no-legend) assert_in "test63-issue-24577.service" "$output" -- systemctl list-jobs output=$(systemctl list-jobs --no-legend) assert_in "test63-issue-24577.service" "$output" assert_in "test63-issue-24577-dep.service" "$output" rm -f /tmp/hoge systemctl stop test63-issue-24577.service systemctl status -n 0 test63-issue-24577.path systemctl status -n 0 test63-issue-24577.service || : systemctl list-jobs output=$(systemctl list-jobs --no-legend) -- assert_in "test63-issue-24577-dep.service" "$output" # Test for race condition fixed by https://github.com/systemd/systemd/pull/30768 # Here's the schedule of events that we to happen during this test: # (This test) (The service) # .path unit monitors /tmp/copyme for changes # Take lock on /tmp/noexeit ↓ # Write to /tmp/copyme ↓ # Wait for deactivating Started # ↓ Copies /tmp/copyme to /tmp/copied # ↓ Tells manager it's shutting down # Ensure service did the copy Tries to lock /tmp/noexit and blocks # Write to /tmp/copyme ↓ # # Now at this point the test can diverge. If we regress, this second write is # missed and we'll see: # ... (second write) ... (blocked) # Drop lock on /tmp/noexit ↓ # Wait for service to do copy Unblocks and exits # ↓ (dead) # ↓ # (timeout) # Test fails # # Otherwise, we'll see: # ... (second write) ... (blocked) # Drop lock on /tmp/noexit ↓ and .path unit queues a new start job # Wait for service to do copy Unblocks and exits # ↓ Starts again b/c of queued job # ↓ Copies again # Test Passes systemctl start test63-pr-30768.path exec {lock}<>/tmp/noexit flock -e $lock echo test1 > /tmp/copyme # shellcheck disable=SC2016 timeout 30 bash -c 'until test "$(systemctl show test63-pr-30768.service -P ActiveState)" = deactivating; do sleep .2; done' diff /tmp/copyme /tmp/copied echo test2 > /tmp/copyme exec {lock}<&- timeout 30 bash -c 'until diff /tmp/copyme /tmp/copied >/dev/null; do sleep .2; done' systemctl log-level info touch /testok Found error in /usr/lib/systemd/tests/testdata/units/TEST-55-OOMD.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-55-OOMD.sh systemctl daemon-reload } testcase_duration_analyze() { # Verify memory pressure duration is valid if >= 1 second cat </tmp/TEST-55-OOMD-valid-duration.service [Service] ExecStart=echo hello ManagedOOMMemoryPressureDurationSec=1s EOF # Verify memory pressure duration is invalid if < 1 second cat </tmp/TEST-55-OOMD-invalid-duration.service [Service] ExecStart=echo hello ManagedOOMMemoryPressureDurationSec=0 EOF systemd-analyze --recursive-errors=no verify /tmp/TEST-55-OOMD-valid-duration.service (! systemd-analyze --recursive-errors=no verify /tmp/TEST-55-OOMD-invalid-duration.service) rm -f /tmp/TEST-55-OOMD-valid-duration.service rm -f /tmp/TEST-55-OOMD-invalid-duration.service } testcase_duration_override() { # Verify memory pressure duration can be overridden to non-zero values mkdir -p /run/systemd/system/TEST-55-OOMD-testmunch.service.d/ Found error in /usr/lib/systemd/tests/testdata/units/TEST-54-CREDS.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-54-CREDS.sh # Sanity checks # # Create a dummy "full" disk (similar to /dev/full) to check out-of-space # scenarios mkdir /tmp/full mount -t tmpfs -o size=1,nr_inodes=1 tmpfs /tmp/full # verb: setup # Run this first, otherwise any encrypted credentials wouldn't be decryptable # as we regenerate the host key rm -fv /var/lib/systemd/credential.secret -- echo foo >"$CRED_DIR/insecure" echo foo | systemd-creds --name="encrypted" encrypt - "$ENC_CRED_DIR/encrypted" echo foo | systemd-creds encrypt - "$ENC_CRED_DIR/encrypted-unnamed" chmod -R 0400 "$CRED_DIR" "$ENC_CRED_DIR" chmod -R 0444 "$CRED_DIR/insecure" mkdir /tmp/empty/ systemd-creds --system systemd-creds --no-pager --help systemd-creds --version systemd-creds has-tpm2 || : -- systemd-creds list --system ENCRYPTED_CREDENTIALS_DIRECTORY="$ENC_CRED_DIR" CREDENTIALS_DIRECTORY="$CRED_DIR" systemd-creds list --no-legend ENCRYPTED_CREDENTIALS_DIRECTORY="$ENC_CRED_DIR" CREDENTIALS_DIRECTORY="$CRED_DIR" systemd-creds list --json=pretty | jq ENCRYPTED_CREDENTIALS_DIRECTORY="$ENC_CRED_DIR" CREDENTIALS_DIRECTORY="$CRED_DIR" systemd-creds list --json=short | jq ENCRYPTED_CREDENTIALS_DIRECTORY="$ENC_CRED_DIR" CREDENTIALS_DIRECTORY="$CRED_DIR" systemd-creds list --json=off ENCRYPTED_CREDENTIALS_DIRECTORY="/tmp/empty/" CREDENTIALS_DIRECTORY="/tmp/empty/" systemd-creds list # verb: cat for cred in secure-or-weak insecure encrypted encrypted-unnamed; do ENCRYPTED_CREDENTIALS_DIRECTORY="$ENC_CRED_DIR" CREDENTIALS_DIRECTORY="$CRED_DIR" systemd-creds cat "$cred" done -- run_with_cred_compare "mycred:68656c6c6f0a776f726c64" "hello\nworld" --transcode=unhex cat mycred run_with_cred_compare 'mycred:{ "foo" : "bar", "baz" : [ 3, 4 ] }' '{"foo":"bar","baz":[3,4]}\n' --json=short cat mycred systemd-run -p SetCredential='mycred:{ "foo" : "bar", "baz" : [ 3, 4 ] }' --wait --pipe -- systemd-creds --json=pretty cat mycred | jq # verb: encrypt/decrypt echo "According to all known laws of aviation..." >/tmp/cred.orig systemd-creds --with-key=host encrypt /tmp/cred.orig /tmp/cred.enc systemd-creds decrypt /tmp/cred.enc /tmp/cred.dec diff /tmp/cred.orig /tmp/cred.dec rm -f /tmp/cred.{enc,dec} # --pretty cred_name="fo'''o''bar" cred_option="$(systemd-creds --pretty --name="$cred_name" encrypt /tmp/cred.orig -)" mkdir -p /run/systemd/system cat >/run/systemd/system/test-54-pretty-cred.service </tmp/ts54-concat (cat /etc/passwd /etc/shadow && echo -n wuff) | cmp /tmp/ts54-concat rm /tmp/ts54-concat # Test that SetCredential= acts as fallback for LoadCredential= echo piff >/tmp/ts54-fallback [ "$(systemd-run -p LoadCredential=paff:/tmp/ts54-fallback -p SetCredential=paff:poff --pipe --wait systemd-creds cat paff)" = "piff" ] rm /tmp/ts54-fallback [ "$(systemd-run -p LoadCredential=paff:/tmp/ts54-fallback -p SetCredential=paff:poff --pipe --wait systemd-creds cat paff)" = "poff" ] if systemd-detect-virt -q -c ; then expected_credential=mynspawncredential expected_value=strangevalue elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then -- # Verify that creating a user via sysusers via the kernel cmdline worked grep -q ^credtestuser: /etc/passwd # Verify that writing a file via tmpfiles worked [ "$(cat /tmp/sourcedfromcredential)" = "tmpfilessecret" ] [ "$(cat /etc/motd.d/50-provision.conf)" = "hello" ] [ "$(cat /etc/issue.d/50-provision.conf)" = "welcome" ] # Verify that adding a unit and drop-in via credentials worked systemctl start my-service test -f /tmp/unit-cred test -f /tmp/unit-dropin test -f /tmp/unit-named-dropin else echo "qemu_fw_cfg support missing in kernel. Sniff!" expected_credential="" expected_value="" fi -- --unit=test-54-immutable-rm.service \ --wait \ rm '${CREDENTIALS_DIRECTORY}/passwd') # Check directory-based loading mkdir -p /tmp/ts54-creds/sub echo -n a >/tmp/ts54-creds/foo echo -n b >/tmp/ts54-creds/bar echo -n c >/tmp/ts54-creds/baz echo -n d >/tmp/ts54-creds/sub/qux systemd-run -p LoadCredential=cred:/tmp/ts54-creds \ -p DynamicUser=1 \ --unit=test-54-dir.service \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/cred_foo' \ '${CREDENTIALS_DIRECTORY}/cred_bar' \ '${CREDENTIALS_DIRECTORY}/cred_baz' \ '${CREDENTIALS_DIRECTORY}/cred_sub_qux' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n abcd) rm /tmp/ts54-concat rm -rf /tmp/ts54-creds # Check that globs work as expected mkdir -p /run/credstore echo -n a >/run/credstore/test.creds.first # Make sure that when multiple credentials of the same name are found, the first one is used (/etc/credstore -- -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/test.creds.first' \ '${CREDENTIALS_DIRECTORY}/test.creds.second' \ '${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n abc) # Check that ImportCredentialEx= works without renaming. systemd-run -p "ImportCredentialEx=test.creds.*" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/test.creds.first' \ '${CREDENTIALS_DIRECTORY}/test.creds.second' \ '${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n abc) # Check that renaming with globs works as expected. systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' \ '${CREDENTIALS_DIRECTORY}/renamed.creds.second' \ '${CREDENTIALS_DIRECTORY}/renamed.creds.third' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n abc) # Check that renaming without globs works as expected. systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n a) # Test that multiple renames are processed in the correct order. systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ -p "ImportCredentialEx=test.creds.second:renamed.creds.first" \ --unit=test-54-ImportCredential.service \ -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/renamed.creds.first' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n a) # Test that a credential can be imported multiple times with different names. systemd-run -p "ImportCredentialEx=test.creds.first" \ -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \ -p "ImportCredentialEx=test.creds.first:renamed.creds.second" \ -- -p DynamicUser=1 \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/test.creds.first' \ '${CREDENTIALS_DIRECTORY}/renamed.creds.first' \ '${CREDENTIALS_DIRECTORY}/renamed.creds.second' >/tmp/ts54-concat cmp /tmp/ts54-concat <(echo -n aaa) # Now test encrypted credentials (only supported when built with OpenSSL though) if systemctl --version | grep -q -- +OPENSSL ; then echo -n $RANDOM >/tmp/test-54-plaintext systemd-creds encrypt --name=test-54 /tmp/test-54-plaintext /tmp/test-54-ciphertext systemd-creds decrypt --name=test-54 /tmp/test-54-ciphertext | cmp /tmp/test-54-plaintext systemd-run -p LoadCredentialEncrypted=test-54:/tmp/test-54-ciphertext \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext echo -n $RANDOM >/tmp/test-54-plaintext systemd-creds encrypt --name=test-54 /tmp/test-54-plaintext /tmp/test-54-ciphertext systemd-creds decrypt --name=test-54 /tmp/test-54-ciphertext | cmp /tmp/test-54-plaintext systemd-run -p SetCredentialEncrypted=test-54:"$(cat /tmp/test-54-ciphertext)" \ --wait \ --pipe \ cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext rm /tmp/test-54-plaintext /tmp/test-54-ciphertext fi # https://github.com/systemd/systemd/issues/27275 systemd-run -p DynamicUser=yes -p 'LoadCredential=os:/etc/os-release' \ -p 'ExecStartPre=true' \ -- --service-type=oneshot --wait --pipe \ true | cmp /etc/os-release # https://github.com/systemd/systemd/pull/24734#issuecomment-1925440546 # Also ExecStartPre= should be able to update creds dd if=/dev/urandom of=/tmp/cred-huge bs=600K count=1 chmod 777 /tmp/cred-huge systemd-run -p ProtectSystem=full \ -p 'LoadCredential=huge:/tmp/cred-huge' \ -p 'ExecStartPre=true' \ -p 'ExecStartPre=bash -c "echo fresh >/tmp/cred-huge"' \ --unit=test-54-huge-cred.service \ --wait --pipe \ systemd-creds cat huge | cmp - <(echo "fresh") rm /tmp/cred-huge echo stable >/tmp/cred-stable systemd-run -p 'LoadCredential=stable:/tmp/cred-stable' \ -p 'ExecStartPost=systemd-creds cat stable' \ --unit=test-54-stable.service \ --service-type=oneshot --wait --pipe \ bash -c "echo bogus >/tmp/cred-stable" | cmp - <(echo "stable") assert_eq "$(cat /tmp/cred-stable)" "bogus" rm /tmp/cred-stable if ! systemd-detect-virt -q -c ; then # Validate that the credential we inserted via the initrd logic arrived test "$(systemd-creds cat --system myinitrdcred)" = "guatemala" -- systemctl -P Wants show getty.target | grep -q container-getty@idontexist.service fi # Decrypt/encrypt via varlink echo '{"data":"Zm9vYmFyCg=="}' > /tmp/vlcredsdata varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "$(cat /tmp/vlcredsdata)" | \ varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt > /tmp/vlcredsdata2 cmp /tmp/vlcredsdata /tmp/vlcredsdata2 rm /tmp/vlcredsdata /tmp/vlcredsdata2 clean_usertest() { rm -f /tmp/usertest.data /tmp/usertest.data } trap clean_usertest EXIT dd if=/dev/urandom of=/tmp/usertest.data bs=4096 count=1 systemd-creds encrypt --user /tmp/usertest.data /tmp/usertest.cred systemd-creds decrypt --user /tmp/usertest.cred - | cmp /tmp/usertest.data # Decryption must fail if it's not done in user context (! systemd-creds decrypt /tmp/usertest.cred - ) # Decryption must also fail if a different user is used (! systemd-creds decrypt --user --uid=65534 /tmp/usertest.cred - ) # Try the reverse systemd-creds encrypt --user --uid=65534 /tmp/usertest.data /tmp/usertest.cred (! systemd-creds decrypt --user /tmp/usertest.cred - ) systemd-creds decrypt --user --uid=65534 /tmp/usertest.cred - | cmp /tmp/usertest.data systemd-creds encrypt --user /tmp/usertest.data /tmp/usertest.creds --name=mytest # Make sure we actually can decode this in user context systemctl start user@0.service XDG_RUNTIME_DIR=/run/user/0 systemd-run --pipe --user --unit=waldi.service -p LoadCredentialEncrypted=mytest:/tmp/usertest.creds cat /run/user/0/credentials/waldi.service/mytest | cmp /tmp/usertest.data systemd-analyze log-level info touch /testok Found error in /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.mountfsd.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.mountfsd.sh fi at_exit() { set +e umount -R /tmp/unpriv/mount rmdir /tmp/unpriv rm -f /tmp/test-50-unpriv-privkey.key /tmp/test-50-unpriv-cert.crt /run/verity.d/test-50-unpriv-cert.crt rm -f /var/tmp/unpriv.raw /tmp/unpriv.raw.mtree /tmp/unpriv2.raw.mtree rm -f /tmp/unpriv.out /tmp/unpriv.out2 /tmp/unpriv.out3 } trap at_exit EXIT systemctl start systemd-mountfsd.socket systemd-nsresourced.socket openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" \ -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ -keyout /tmp/test-50-unpriv-privkey.key -out /tmp/test-50-unpriv-cert.crt systemd-dissect --mkdir --mount "$MINIMAL_IMAGE.raw" /tmp/unpriv/mount SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ systemd-repart -P \ -s /tmp/unpriv/mount \ --certificate=/tmp/test-50-unpriv-cert.crt \ --private-key=/tmp/test-50-unpriv-privkey.key \ /var/tmp/unpriv.raw systemd-dissect --rmdir --umount /tmp/unpriv/mount systemd-dissect --image-policy='root=unprotected:=absent+unused' /var/tmp/unpriv.raw systemd-dissect --image-policy='root=unprotected:=absent+unused' --mtree /var/tmp/unpriv.raw >/tmp/unpriv.raw.mtree # Run unpriv, should fail due to lack of privs (! runas testuser systemd-dissect /var/tmp/unpriv.raw) (! runas testuser systemd-dissect --mtree /var/tmp/unpriv.raw) if (SYSTEMD_LOG_TARGET=console varlinkctl call \ /run/systemd/userdb/io.systemd.NamespaceResource \ io.systemd.NamespaceResource.AllocateUserRange \ '{"name":"test-supported","size":65536,"userNamespaceFileDescriptor":0}' 2>&1 || true) | -- echo "User namespace interface not supported, skipping mountfsd/nsresourced tests" exit 0 fi # Install key in keychain cp /tmp/test-50-unpriv-cert.crt /run/verity.d # Now run unpriv again, should be OK now. runas testuser systemd-dissect /var/tmp/unpriv.raw runas testuser systemd-dissect --mtree /var/tmp/unpriv.raw >/tmp/unpriv2.raw.mtree # Check that unpriv and priv run yielded same results cmp /tmp/unpriv.raw.mtree /tmp/unpriv2.raw.mtree # Make sure nspawn works unpriv, too (for now do not nest) if ! systemd-detect-virt -c; then systemd-nspawn --pipe -i /var/tmp/unpriv.raw --read-only echo thisisatest > /tmp/unpriv.out echo thisisatest | cmp /tmp/unpriv.out - # The unpriv user has no rights to lock the image or write to it. Let's # turn off both for this test, so that we don't have to copy the image # around. systemd-run -M testuser@ --user --pipe \ -p Environment=SYSTEMD_NSPAWN_LOCK=0 \ -p Delegate=1 \ -p DelegateSubgroup=supervisor \ -p Environment=SYSTEMD_LOG_LEVEL=debug \ --wait -- \ systemd-nspawn --keep-unit --register=no -i /var/tmp/unpriv.raw --read-only --pipe echo thisisatest >/tmp/unpriv.out2 echo thisisatest | cmp /tmp/unpriv.out2 - fi systemd-run -M testuser@ --user --pipe -p RootImage=/var/tmp/unpriv.raw -p PrivateUsers=1 --wait echo thisisatest >/tmp/unpriv.out3 echo thisisatest | cmp /tmp/unpriv.out3 - Found error in /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.dissect.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.dissect.sh RemainAfterExit=yes MountAPIVFS=yes PrivateTmp=yes ExecStart=sh -c ' \\ systemd-notify --ready; \\ while [ ! -f /tmp/img/usr/lib/os-release ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\ sleep 0.1; \\ done; \\ mount; \\ mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid"; \\ ' EOF systemctl start testservice-50d.service # Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount) mkdir -p /tmp/wrong/foo mksquashfs /tmp/wrong/foo /tmp/wrong.raw systemctl mount-image --mkdir testservice-50d.service /tmp/wrong.raw /tmp/img test "$(systemctl show -P SubState testservice-50d.service)" = "running" systemctl mount-image --mkdir testservice-50d.service "$MINIMAL_IMAGE.raw" /tmp/img root:nosuid # shellcheck disable=SC2016 timeout 30s bash -xec 'while [[ $(systemctl show -P SubState testservice-50d.service) == running ]]; do sleep .2; done' systemctl is-active testservice-50d.service # ExtensionImages will set up an overlay systemd-run -P \ --property ExtensionImages=/tmp/app0.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /opt/script0.sh | grep -q -F "extension-release.app0" systemd-run -P \ --property ExtensionImages=/tmp/app0.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /opt/script0.sh | grep -q -F "extension-release.app0" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /opt/script1.sh | grep -q -F "extension-release.app2" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" systemd-run -P \ --property ExtensionImages=/tmp/app-nodistro.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" systemd-run -P \ --property ExtensionImages=/etc/service-scoped-test.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/conf0.raw" \ veritysetup status "$(cat /tmp/app0.roothash)-verity" | grep -q "$(cat /tmp/app0.roothash)" systemd-run -P \ --property ExtensionImages="/tmp/app0.raw /tmp/conf0.raw" \ veritysetup status "$(cat /tmp/conf0.roothash)-verity" | grep -q "$(cat /tmp/conf0.roothash)" # Check that two identical verity images at different paths do not fail with -ELOOP from OverlayFS mkdir -p /tmp/loop cp /tmp/app0.raw /tmp/loop/app0.raw veritysetup format /tmp/loop/app0.raw /tmp/loop/app0.verity --root-hash-file /tmp/loop/app0.roothash cp /tmp/loop/app0.raw /tmp/loop/app0_copy.raw cp /tmp/loop/app0.verity /tmp/loop/app0_copy.verity cp /tmp/loop/app0.roothash /tmp/loop/app0_copy.roothash systemd-run -P \ --property ExtensionImages=/tmp/loop/app0.raw \ --property ExtensionImages=/tmp/loop/app0_copy.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ "${BIND_LOG_SOCKETS[@]}" \ cat /opt/script0.sh | grep -q -F "extension-release.app0" rm -rf /tmp/loop/ # Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw mkdir -p /tmp/symlink-test/ cp /tmp/app-nodistro.raw /tmp/symlink-test/app-nodistro-v1.raw ln -fs /tmp/symlink-test/app-nodistro-v1.raw /tmp/symlink-test/app-nodistro.raw systemd-run -P \ --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" # Symlink check again but for confext mkdir -p /etc/symlink-test/ -- --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" # And again mixing sysext and confext systemd-run -P \ --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" systemd-run -P \ --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ --property RootImage="$MINIMAL_IMAGE.raw" \ cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" cat >/run/systemd/system/testservice-50e.service </tmp/discover.json grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")" # Wait until the symlinks we want to test are established udevadm trigger -w "$LOOP" -- (! /etc/testscript) systemd-confext status systemd-confext unmerge rm -rf /run/confexts/ unsquashfs -no-xattrs -d /tmp/img "$MINIMAL_IMAGE.raw" systemd-run --unit=test-root-ephemeral \ -p RootDirectory=/tmp/img \ -p RootEphemeral=yes \ -p Type=exec \ bash -c "touch /abc && sleep infinity" test -n "$(ls -A /var/lib/systemd/ephemeral-trees)" systemctl stop test-root-ephemeral # shellcheck disable=SC2016 timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done' test ! -f /tmp/img/abc systemd-dissect --mtree /tmp/img >/dev/null systemd-dissect --list /tmp/img >/dev/null read -r SHA256SUM1 _ < <(systemd-dissect --copy-from /tmp/img etc/os-release | sha256sum) test "$SHA256SUM1" != "" echo abc > abc systemd-dissect --copy-to /tmp/img abc /abc test -f /tmp/img/abc # Test for dissect tool support with systemd-sysext mkdir -p /run/extensions/ testkit/usr/lib/extension-release.d/ echo "ID=_any" >testkit/usr/lib/extension-release.d/extension-release.testkit echo "ARCHITECTURE=_any" >>testkit/usr/lib/extension-release.d/extension-release.testkit -- systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" cat /run/host/os-release | cmp "$OS_RELEASE" # Test that systemd-sysext reloads the daemon. mkdir -p /var/lib/extensions/ ln -s /tmp/app-reload.raw /var/lib/extensions/app-reload.raw systemd-sysext merge --no-reload # the service should not be running (! systemctl --quiet is-active foo.service) systemd-sysext unmerge --no-reload systemd-sysext merge Found error in /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.DDI.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-50-DISSECT.DDI.sh # SPDX-License-Identifier: LGPL-2.1-or-later set -eux set -o pipefail # Check that the /sbin/mount.ddi helper works dir="/tmp/mounthelper.$RANDOM" mount -t ddi "$MINIMAL_IMAGE.gpt" "$dir" -o ro,X-mount.mkdir,discard umount -R "$dir" # Test systemd-repart --make-ddi=: if [[ -z "${OPENSSL_CONFIG:?}" ]] || ! command -v mksquashfs &>/dev/null; then -- exit 0 fi openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" \ -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ -keyout /tmp/test-50-privkey.key -out /tmp/test-50-cert.crt mkdir -p /tmp/test-50-confext/etc/extension-release.d/ echo "foobar50" >/tmp/test-50-confext/etc/waldo { grep -e '^\(ID\|VERSION_ID\)=' /etc/os-release echo IMAGE_ID=waldo echo IMAGE_VERSION=7 } >/tmp/test-50-confext/etc/extension-release.d/extension-release.waldo mkdir -p /run/confexts SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ systemd-repart -C \ -s /tmp/test-50-confext \ --certificate=/tmp/test-50-cert.crt \ --private-key=/tmp/test-50-privkey.key \ /run/confexts/waldo.confext.raw rm -rf /tmp/test-50-confext mkdir -p /run/verity.d cp /tmp/test-50-cert.crt /run/verity.d/ systemd-dissect --mtree /run/confexts/waldo.confext.raw systemd-confext refresh test "$(/tmp/test-50-sysext/usr/lib/extension-release.d/extension-release.waldo mkdir -p /run/extensions SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ systemd-repart -S \ -s /tmp/test-50-sysext \ --certificate=/tmp/test-50-cert.crt \ --private-key=/tmp/test-50-privkey.key \ /run/extensions/waldo.sysext.raw systemd-dissect --mtree /run/extensions/waldo.sysext.raw systemd-sysext refresh test -f /usr/waldo rm /run/verity.d/test-50-cert.crt /run/extensions/waldo.sysext.raw /tmp/test-50-cert.crt /tmp/test-50-privkey.key systemd-sysext refresh test ! -f /usr/waldo Found error in /usr/lib/systemd/tests/testdata/units/TEST-46-HOMED.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-46-HOMED.sh # filesystems, let's drop these fields before comparing the outputs to # avoid unexpected fails. To see the full outputs of both homectl & # userdbctl (for debugging purposes) drop the fields just before the # comparison. local USERNAME="${1:?}" homectl inspect "$USERNAME" | tee /tmp/a userdbctl user "$USERNAME" | tee /tmp/b # diff uses the grep BREs for pattern matching diff -I '^\s*Disk \(Size\|Free\|Floor\|Ceiling\|Usage\):' /tmp/{a,b} rm /tmp/{a,b} homectl inspect --json=pretty "$USERNAME" } wait_for_state() { -- diff "/var/cache/systemd/home/blob-user/$1" "$2" diff "/var/cache/systemd/home/blob-user/$1" "/home/blob-user/.identity-blob/$1" } mkdir /tmp/blob1 /tmp/blob2 echo data1 blob1 >/tmp/blob1/test1 echo data1 blob2 >/tmp/blob2/test1 echo data2 blob1 >/tmp/blob1/test2 echo data2 blob2 >/tmp/blob2/test2 echo invalid filename >/tmp/blob1/файл echo data3 >/tmp/external-test3 echo avatardata >/tmp/external-avatar ln -s /tmp/external-avatar /tmp/external-avatar-lnk dd if=/dev/urandom of=/tmp/external-barely-fits bs=1M count=64 dd if=/dev/urandom of=/tmp/external-toobig bs=1M count=65 # create w/ prepopulated blob dir NEWPASSWORD=EMJuc3zQaMibJo homectl create blob-user \ --disk-size=min --luks-discard=yes \ --luks-pbkdf-type=pbkdf2 --luks-pbkdf-time-cost=1ms \ --rate-limit-interval=1s --rate-limit-burst=1000 \ --uid=12345 \ --blob=/tmp/blob1 inspect blob-user PASSWORD=EMJuc3zQaMibJo homectl activate blob-user inspect blob-user test -d /var/cache/systemd/home/blob-user stat -c "%u %#a" /var/cache/systemd/home/blob-user | grep "^0 0755" test -d /home/blob-user/.identity-blob stat -c "%u %#a" /home/blob-user/.identity-blob | grep "^12345 0700" checkblob test1 /tmp/blob1/test1 (! checkblob test1 /tmp/blob2/test1 ) checkblob test2 /tmp/blob1/test2 (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) (! checkblob test3 /tmp/external-test3 ) (! checkblob avatar /tmp/external-avatar ) # append files to existing blob, both well-known and other PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b test3=/tmp/external-test3 --avatar=/tmp/external-avatar inspect blob-user checkblob test1 /tmp/blob1/test1 (! checkblob test1 /tmp/blob2/test1 ) checkblob test2 /tmp/blob1/test2 (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) checkblob test3 /tmp/external-test3 checkblob avatar /tmp/external-avatar # delete files from existing blob, both well-known and other PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b test3= --avatar= inspect blob-user checkblob test1 /tmp/blob1/test1 (! checkblob test1 /tmp/blob2/test1 ) checkblob test2 /tmp/blob1/test2 (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) (! checkblob test3 /tmp/external-test3 ) (! checkblob avatar /tmp/external-avatar ) # swap entire blob directory PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b /tmp/blob2 inspect blob-user (! checkblob test1 /tmp/blob1/test1 ) checkblob test1 /tmp/blob2/test1 (! checkblob test2 /tmp/blob1/test2 ) checkblob test2 /tmp/blob2/test2 (! checkblob фаил /tmp/blob1/фаил ) (! checkblob test3 /tmp/external-test3 ) (! checkblob avatar /tmp/external-avatar ) # create and delete files while swapping blob directory. Also symlinks. PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b /tmp/blob1 -b test2= -b test3=/tmp/external-test3 --avatar=/tmp/external-avatar-lnk inspect blob-user checkblob test1 /tmp/blob1/test1 (! checkblob test1 /tmp/blob2/test1 ) (! checkblob test2 /tmp/blob1/test2 ) (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) checkblob test3 /tmp/external-test3 checkblob avatar /tmp/external-avatar # target of the link # clear the blob directory PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b /tmp/blob2 -b test3=/tmp/external-test3 --blob= inspect blob-user (! checkblob test1 /tmp/blob1/test1 ) (! checkblob test1 /tmp/blob2/test1 ) (! checkblob test2 /tmp/blob1/test2 ) (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) (! checkblob test3 /tmp/external-test3 ) (! checkblob avatar /tmp/external-avatar ) # file that's exactly 64M still fits # FIXME: Figure out why this fails on ext4. if [[ "$FSTYPE" != "ext2/ext3" ]]; then PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ -b barely-fits=/tmp/external-barely-fits (! checkblob test1 /tmp/blob1/test1 ) (! checkblob test1 /tmp/blob2/test1 ) (! checkblob test2 /tmp/blob1/test2 ) (! checkblob test2 /tmp/blob2/test2 ) (! checkblob фаил /tmp/blob1/фаил ) (! checkblob test3 /tmp/external-test3 ) (! checkblob avatar /tmp/external-avatar ) checkblob barely-fits /tmp/external-barely-fits fi # error out if the file is too big (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b huge=/tmp/external-toobig ) # error out if filenames are invalid (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b .hidden=/tmp/external-test3 ) (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b "with spaces=/tmp/external-test3" ) (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b with=equals=/tmp/external-test3 ) (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b файл=/tmp/external-test3 ) (! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b special@chars=/tmp/external-test3 ) # Make sure offline updates to blobs get propagated in homectl deactivate blob-user inspect blob-user homectl update blob-user --offline -b barely-fits= -b propagated=/tmp/external-test3 inspect blob-user PASSWORD=EMJuc3zQaMibJo homectl activate blob-user inspect blob-user (! checkblob barely-fits /tmp/external-barely-fits ) checkblob propagated /tmp/external-test3 homectl deactivate blob-user wait_for_state blob-user inactive homectl remove blob-user -- varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"uid":2000000,"service":"io.systemd.Multiplexer"}' (! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"","service":"io.systemd.Multiplexer"}') (! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"🐱","service":"io.systemd.Multiplexer"}') (! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"i-do-not-exist","service":"io.systemd.Multiplexer"}') userdbctl ssh-authorized-keys dropinuser | tee /tmp/authorized-keys grep "ssh-ed25519" /tmp/authorized-keys grep "ecdsa-sha2-nistp256" /tmp/authorized-keys echo "my-top-secret-key 🐱" >/tmp/my-top-secret-key userdbctl ssh-authorized-keys dropinuser --chain /bin/cat /tmp/my-top-secret-key | tee /tmp/authorized-keys grep "ssh-ed25519" /tmp/authorized-keys grep "ecdsa-sha2-nistp256" /tmp/authorized-keys grep "my-top-secret-key 🐱" /tmp/authorized-keys (! userdbctl ssh-authorized-keys 🐱) (! userdbctl ssh-authorized-keys dropin-user --chain) (! userdbctl ssh-authorized-keys dropin-user --chain '') (! SYSTEMD_LOG_LEVEL=debug userdbctl ssh-authorized-keys dropin-user --chain /bin/false) -- if command -v ssh &>/dev/null && command -v sshd &>/dev/null && ! [[ -v ASAN_OPTIONS ]]; then at_exit() { set +e systemctl is-active -q mysshserver.socket && systemctl stop mysshserver.socket rm -f /tmp/homed.id_ecdsa /run/systemd/system/mysshserver{@.service,.socket} systemctl daemon-reload homectl remove homedsshtest for dir in /etc /usr/lib; do if [[ -f "$dir/pam.d/sshd.bak" ]]; then mv "$dir/pam.d/sshd.bak" "$dir/pam.d/sshd" -- } trap at_exit EXIT # Test that SSH logins work with delayed unlocking ssh-keygen -N '' -C '' -t ecdsa -f /tmp/homed.id_ecdsa NEWPASSWORD=hunter4711 homectl create \ --disk-size=min \ --luks-discard=yes \ --luks-pbkdf-type=pbkdf2 \ --luks-pbkdf-time-cost=1ms \ --rate-limit-interval=1s \ --rate-limit-burst=1000 \ --enforce-password-policy=no \ --ssh-authorized-keys=@/tmp/homed.id_ecdsa.pub \ --stop-delay=0 \ homedsshtest homectl inspect homedsshtest mkdir -p /etc/ssh -- systemctl daemon-reload systemctl start mysshserver.socket userdbctl user -j homedsshtest ssh -t -t -4 -p 4711 -i /tmp/homed.id_ecdsa \ -o "SetEnv PASSWORD=hunter4711" -o "StrictHostKeyChecking no" \ homedsshtest@localhost echo zzz | tr -d '\r' | tee /tmp/homedsshtest.out grep -E "^zzz$" /tmp/homedsshtest.out rm /tmp/homedsshtest.out ssh -t -t -4 -p 4711 -i /tmp/homed.id_ecdsa \ -o "SetEnv PASSWORD=hunter4711" -o "StrictHostKeyChecking no" \ homedsshtest@localhost env wait_for_state homedsshtest inactive fi Found error in /usr/lib/systemd/tests/testdata/units/TEST-44-LOG-NAMESPACE.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-44-LOG-NAMESPACE.sh journalctl --namespace=foobar --sync journalctl --namespace=foobaz --sync ls -l /var/log/journal/ journalctl --list-namespaces journalctl -o cat --namespace=foobar >/tmp/hello-world journalctl -o cat >/tmp/no-hello-world journalctl --list-namespaces | grep foobar journalctl --list-namespaces | grep foobaz journalctl --list-namespaces -o json | jq . [[ "$(journalctl --root=/tmp --list-namespaces --quiet)" == "" ]] grep "^hello world$" /tmp/hello-world (! grep "^hello world$" /tmp/no-hello-world) systemd-analyze log-level info touch /testok Found error in /usr/lib/systemd/tests/testdata/units/TEST-29-PORTABLE.directory.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-29-PORTABLE.directory.sh # If we're running under sanitizers, we need to use a less restrictive # profile, otherwise LSan syscall would get blocked by seccomp ARGS+=(--profile=trusted) fi unsquashfs -dest /tmp/minimal_0 /usr/share/minimal_0.raw unsquashfs -dest /tmp/minimal_1 /usr/share/minimal_1.raw portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/minimal_0 minimal-app0 systemctl is-active minimal-app0.service systemctl is-active minimal-app0-foo.service systemctl is-active minimal-app0-bar.service && exit 1 portablectl "${ARGS[@]}" reattach --now --enable --runtime /tmp/minimal_1 minimal-app0 systemctl is-active minimal-app0.service systemctl is-active minimal-app0-bar.service systemctl is-active minimal-app0-foo.service && exit 1 portablectl list | grep -q -F "minimal_1" busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' portablectl detach --now --enable --runtime /tmp/minimal_1 minimal-app0 portablectl list | grep -q -F "No images." busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1 mkdir /tmp/rootdir /tmp/app0 /tmp/app1 /tmp/overlay /tmp/os-release-fix /tmp/os-release-fix/etc mount /tmp/app0.raw /tmp/app0 mount /tmp/app1.raw /tmp/app1 mount /usr/share/minimal_0.raw /tmp/rootdir # Fix up os-release to drop the valid PORTABLE_SERVICES field (because we are # bypassing the sysext logic in portabled here it will otherwise not see the # extensions additional valid prefix) grep -v "^PORTABLE_PREFIXES=" /tmp/rootdir/etc/os-release >/tmp/os-release-fix/etc/os-release mount -t overlay overlay -o lowerdir=/tmp/os-release-fix:/tmp/app1:/tmp/rootdir /tmp/overlay grep . /tmp/overlay/usr/lib/extension-release.d/* grep . /tmp/overlay/etc/os-release portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/overlay app1 systemctl is-active app1.service portablectl detach --now --runtime overlay app1 -- [Unit] Description=App 1 EOF systemctl daemon-reload portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1 systemctl is-active app1.service portablectl detach --now --runtime overlay app1 umount /tmp/overlay portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 systemctl is-active app0.service systemctl is-active app1.service portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/rootdir/usr/lib/os-release portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/extension-release.d/extension-release.app0 portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/extension-release.d/extension-release.app2 portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/systemd/system/app1.service portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/systemd/system/app0.service grep -q -F "LogExtraFields=PORTABLE=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_ROOT=rootdir" /run/systemd/system.attached/app0.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf -- grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app1.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app1.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app1.service.d/20-portable.conf portablectl detach --clean --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 # Ensure --clean remove state and other directories belonging to the portable image being detached test ! -d /var/lib/app0 test ! -d /run/app0 # Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned) portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 test -d /run/portables/app0 test -d /run/portables/app1 test -d /run/portables/rootdir test -f /run/systemd/system.attached/app0.service test -f /run/systemd/system.attached/app1.service test -L /run/systemd/system.attached/app0.service.d/10-profile.conf test -L /run/systemd/system.attached/app1.service.d/10-profile.conf portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 # Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce. # Provides coverage for https://github.com/systemd/systemd/issues/23481 portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0 portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0 # attach and detach again to check if all drop-in configs are removed even if the main unit files are removed portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0 portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0 # The wrong file should be ignored, given the right one has the xattr set trap 'rm -rf /var/cache/wrongext' EXIT mkdir -p /var/cache/wrongext/usr/lib/extension-release.d /var/cache/wrongext/usr/lib/systemd/system/ echo "[Service]" > /var/cache/wrongext/usr/lib/systemd/system/app0.service touch /var/cache/wrongext/usr/lib/extension-release.d/extension-release.wrongext_somethingwrong.txt cp /tmp/rootdir/usr/lib/os-release /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0 setfattr -n user.extension-release.strict -v "false" /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0 portablectl "${ARGS[@]}" attach --runtime --extension /var/cache/wrongext /tmp/rootdir app0 status="$(portablectl is-attached --extension wrongext rootdir)" [[ "${status}" == "attached-runtime" ]] portablectl detach --runtime --extension /var/cache/wrongext /tmp/rootdir app0 umount /tmp/rootdir umount /tmp/app0 umount /tmp/app1 Found error in /usr/lib/systemd/tests/testdata/units/TEST-24-CRYPTSETUP.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-24-CRYPTSETUP.sh at_exit() { set +e mountpoint -q /proc/cmdline && umount /proc/cmdline rm -f /etc/crypttab [[ -e /tmp/crypttab.bak ]] && cp -fv /tmp/crypttab.bak /etc/crypttab [[ -n "${STORE_LOOP:-}" ]] && losetup -d "$STORE_LOOP" [[ -n "${WORKDIR:-}" ]] && rm -rf "$WORKDIR" systemctl daemon-reload } -- cp "$IMAGE_DETACHED_HEADER" "$TMPFS_DETACHED_HEADER/header" udevadm settle --timeout=60 # Prepare our test crypttab [[ -e /etc/crypttab ]] && cp -fv /etc/crypttab /tmp/crypttab.bak cat >/etc/crypttab </tmp/cmdline.tmp mount --bind /tmp/cmdline.tmp /proc/cmdline # Run the systemd-cryptsetup-generator once explicitly, to collect coverage, # as during daemon-reload we run generators in a sandbox mkdir -p /tmp/systemd-cryptsetup-generator.out /usr/lib/systemd/system-generators/systemd-cryptsetup-generator /tmp/systemd-cryptsetup-generator.out/ systemctl daemon-reload systemctl list-unit-files "systemd-cryptsetup@*" cryptsetup_start_and_check empty_key test -e "$IMAGE_EMPTY_KEYFILE_ERASE" Found error in /usr/lib/systemd/tests/testdata/units/TEST-23-UNIT-FILE.ExtraFileDescriptors.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-23-UNIT-FILE.ExtraFileDescriptors.sh . "$(dirname "$0")"/util.sh at_exit() { set +e rm -rf /tmp/test-extra-fd/ } trap at_exit EXIT mkdir /tmp/test-extra-fd echo "Hello" > /tmp/test-extra-fd/1.txt echo "Extra" > /tmp/test-extra-fd/2.txt systemd-analyze log-level debug # Open files and assign FD to variables exec {TEST_FD1}/tmp/forking1.sh </tmp/forking2.sh </tmp/notify1.sh </tmp/TEST-23-UNIT-FILE.counter if [ "$counter" -eq 5 ] ; then systemctl kill --kill-whom=main -sUSR1 TEST-23-UNIT-FILE.service fi Found error in /usr/lib/systemd/tests/testdata/units/TEST-22-TMPFILES.03.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-22-TMPFILES.03.sh # # Basic tests for types creating/writing files set -eux set -o pipefail rm -fr /tmp/{f,F,w} mkdir /tmp/{f,F,w} touch /tmp/file-owned-by-root # # 'f' # systemd-tmpfiles --dry-run --create - </tmp/F/truncated echo "This should be truncated" >/tmp/F/truncated-with-content systemd-tmpfiles --create - </tmp/F/rw-fs/foo (! systemd-tmpfiles --create -) </tmp/F/rw-fs/foo (! systemd-tmpfiles --create -) < fails. (! systemd-tmpfiles --create -) < /tmp/C/3/f1 systemd-tmpfiles --create - </tmp/test19-exit-cgroup.sh < sleep sleep infinity & -- (sleep 1; \$1) & # process tree: systemd -> bash -> sleep sleep infinity EOF chmod +x /tmp/test19-exit-cgroup.sh # service should be stopped cleanly systemd-run --wait \ --unit=one \ --property="Type=notify" \ --property="ExitType=cgroup" \ /tmp/test19-exit-cgroup.sh 'systemctl stop one' # same thing with a truthy exec condition systemd-run --wait \ --unit=two \ --property="Type=notify" \ --property="ExitType=cgroup" \ --property="ExecCondition=true" \ /tmp/test19-exit-cgroup.sh 'systemctl stop two' # false exec condition: systemd-run should exit immediately with status code: 1 (! systemd-run --wait \ --unit=three \ --property="Type=notify" \ --property="ExitType=cgroup" \ --property="ExecCondition=false" \ /tmp/test19-exit-cgroup.sh) # service should exit uncleanly (main process exits with SIGKILL) (! systemd-run --wait \ --unit=four \ --property="Type=notify" \ --property="ExitType=cgroup" \ /tmp/test19-exit-cgroup.sh 'systemctl kill --signal 9 four') # Multiple level process tree, parent process exits quickly cat >/tmp/test19-exit-cgroup-parentless.sh < sleep sleep infinity & -- systemd-notify --ready # Run the stop/kill command after this bash process exits (sleep 1; \$1) & EOF chmod +x /tmp/test19-exit-cgroup-parentless.sh # service should be stopped cleanly systemd-run --wait \ --unit=five \ --property="Type=notify" \ --property="ExitType=cgroup" \ /tmp/test19-exit-cgroup-parentless.sh 'systemctl stop five' # service should still exit cleanly despite SIGKILL (the main process already exited cleanly) systemd-run --wait \ --unit=six \ --property="Type=notify" \ --property="ExitType=cgroup" \ /tmp/test19-exit-cgroup-parentless.sh 'systemctl kill --signal 9 six' systemd-analyze log-level info Found error in /usr/lib/systemd/tests/testdata/units/TEST-17-UDEV.SYSTEMD_WANTS-escape.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-17-UDEV.SYSTEMD_WANTS-escape.sh IFNAME=test-netif-foo at_exit() { set +e rm -f /tmp/output-i /tmp/output-I rm -rf /run/udev/rules.d/ udevadm control --reload rm -f /run/systemd/system/test@.service -- mkdir -p /run/systemd/system/ cat >/run/systemd/system/test@.service </tmp/output-i; echo "I=/%I" >/tmp/output-I' RemainAfterExit=yes EOF systemctl daemon-reload -- udevadm wait --timeout 30 --settle "/sys/class/net/${IFNAME}" assert_eq "$(udevadm info --query=property --property SYSTEMD_WANTS --value "/sys/class/net/${IFNAME}")" "test@${ESCAPED}.service" # The value shown by systemctl is doubly escaped and quoted. assert_eq "$(systemctl show -p Wants --value "${ESCAPED}.device")" "\"test@${SHELL_ESCAPED}.service\"" timeout 30 bash -c 'until [[ -s /tmp/output-i ]] && [[ -s /tmp/output-I ]]; do sleep .5; done' assert_eq "$(cat /tmp/output-i)" "i=${ESCAPED}" assert_eq "$(cat /tmp/output-I)" "I=${SYSPATH}" exit 0 Found error in /usr/lib/systemd/tests/testdata/units/TEST-15-DROPIN.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-15-DROPIN.sh testcase_symlink_dropin_directory() { # For issue #21920. echo "Testing symlink drop-in directory..." create_services test15-a rmdir /{etc,run,usr/lib}/systemd/system/test15-a.service.d mkdir -p /tmp/TEST-15-DROPIN-test15-a-dropin-directory ln -s /tmp/TEST-15-DROPIN-test15-a-dropin-directory /etc/systemd/system/test15-a.service.d cat >/tmp/TEST-15-DROPIN-test15-a-dropin-directory/override.conf </tmp/cred.path systemd-nspawn --directory="$root" \ --load-credential=cred.path:/tmp/cred.path \ --set-credential="cred.set:hello world" \ bash -xec '[[ "$(/tmp/bind systemd-nspawn --register=no \ --directory="$root" \ --bind=/tmp/bind \ bash -c 'test -e /tmp/bind' rm -fr "$root" /tmp/bind } testcase_norbind() { # https://github.com/systemd/systemd/issues/13170 local root root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.norbind-path.XXX)" mkdir -p /tmp/binddir/subdir echo -n "outer" >/tmp/binddir/subdir/file mount -t tmpfs tmpfs /tmp/binddir/subdir echo -n "inner" >/tmp/binddir/subdir/file create_dummy_container "$root" systemd-nspawn --register=no \ --directory="$root" \ --bind=/tmp/binddir:/mnt:norbind \ bash -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; exit 1; fi' umount /tmp/binddir/subdir rm -fr "$root" /tmp/binddir/ } rootidmap_cleanup() { local dir="${1:?}" -- local root cmd permissions local owner=1000 root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.rootidmap-path.XXX)" # Create ext4 image, as ext4 supports idmapped-mounts. mkdir -p /tmp/rootidmap/bind dd if=/dev/zero of=/tmp/rootidmap/ext4.img bs=4k count=2048 mkfs.ext4 /tmp/rootidmap/ext4.img mount /tmp/rootidmap/ext4.img /tmp/rootidmap/bind trap "rootidmap_cleanup /tmp/rootidmap/" RETURN touch /tmp/rootidmap/bind/file chown -R "$owner:$owner" /tmp/rootidmap/bind create_dummy_container "$root" cmd='PERMISSIONS=$(stat -c "%u:%g" /mnt/file); if [[ $PERMISSIONS != "0:0" ]]; then echo "*** wrong permissions: $PERMISSIONS"; return 1; fi; touch /mnt/other_file' if ! SYSTEMD_LOG_TARGET=console \ systemd-nspawn --register=no \ --directory="$root" \ --bind=/tmp/rootidmap/bind:/mnt:rootidmap \ bash -c "$cmd" |& tee nspawn.out; then if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out; then echo "idmapped mounts are not supported, skipping the test..." return 0 fi return 1 fi permissions=$(stat -c "%u:%g" /tmp/rootidmap/bind/other_file) if [[ $permissions != "$owner:$owner" ]]; then echo "*** wrong permissions: $permissions" [[ "$IS_USERNS_SUPPORTED" == "yes" ]] && return 1 fi } -- local root cmd permissions local owner=1000 root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.owneridmap-path.XXX)" # Create ext4 image, as ext4 supports idmapped-mounts. mkdir -p /tmp/owneridmap/bind dd if=/dev/zero of=/tmp/owneridmap/ext4.img bs=4k count=2048 mkfs.ext4 /tmp/owneridmap/ext4.img mount /tmp/owneridmap/ext4.img /tmp/owneridmap/bind trap "owneridmap_cleanup /tmp/owneridmap/" RETURN touch /tmp/owneridmap/bind/file chown -R "$owner:$owner" /tmp/owneridmap/bind # Allow users to read and execute / in order to execute binaries chmod o+rx "$root" create_dummy_container "$root" -- if ! SYSTEMD_LOG_TARGET=console \ systemd-nspawn --register=no \ --directory="$root" \ -U \ --user=testuser \ --bind=/tmp/owneridmap/bind:/home/testuser:owneridmap \ ${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \ /usr/bin/bash -c "$cmd" |& tee nspawn.out; then if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out; then echo "idmapped mounts are not supported, skipping the test..." return 0 fi return 1 fi permissions=$(stat -c "%u:%g" /tmp/owneridmap/bind/other_file) if [[ $permissions != "$owner:$owner" ]]; then echo "*** wrong permissions: $permissions" [[ "$IS_USERNS_SUPPORTED" == "yes" ]] && return 1 fi } -- create_dummy_container "$root" entrypoint="$root/entrypoint.sh" cat >"$entrypoint" <<\EOF #!/usr/bin/bash -ex . /tmp/os-release [[ -n "${ID:-}" && "$ID" != "$container_host_id" ]] && exit 1 [[ -n "${VERSION_ID:-}" && "$VERSION_ID" != "$container_host_version_id" ]] && exit 1 [[ -n "${BUILD_ID:-}" && "$BUILD_ID" != "$container_host_build_id" ]] && exit 1 [[ -n "${VARIANT_ID:-}" && "$VARIANT_ID" != "$container_host_variant_id" ]] && exit 1 -- echo MARKER=1 >>/etc/os-release fi systemd-nspawn --register=no \ --directory="$root" \ --bind="$os_release_source:/tmp/os-release" \ "${entrypoint##"$root"}" if grep -q MARKER /etc/os-release; then ln -svrf /usr/lib/os-release /etc/os-release fi -- rm -fr "$root" } testcase_machinectl_bind() { local service_path service_name root container_name ec local cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep .5; done; exit 1;' root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.machinectl-bind.XXX)" create_dummy_container "$root" container_name="$(basename "$root")" -- ExecStart=systemd-nspawn --directory="$root" --notify-ready=no /usr/bin/bash -xec "$cmd" EOF systemctl daemon-reload systemctl start "$service_name" touch /tmp/marker machinectl bind --mkdir "$container_name" /tmp/marker timeout 10 bash -c "while [[ '\$(systemctl show -P SubState $service_name)' == running ]]; do sleep .2; done" ec="$(systemctl show -P ExecMainStatus "$service_name")" systemctl stop "$service_name" -- mkdir -p /run/systemd/nspawn/ rm -f "/etc/systemd/nspawn/$container_name.nspawn" cat >"/run/systemd/nspawn/$container_name.nspawn" <"/var/lib/machines/$NSPAWN_FRAGMENT" </tmp/fragment.nspawn </tmp/expected varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List "{\"pid\":$pid}" | diff /tmp/expected - varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List "{\"name\":\"long-running\", \"pid\":$pid}" | diff /tmp/expected - (! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List "{\"name\":\"non-existent\", \"pid\":$pid}") (! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":""}') (! varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"ah@??.hmm"}') # test io.systemd.Machine.Kill -- varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "tty"}' varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "login"}' varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "shell"}' rm -f /tmp/none-existent-file varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Open '{"name": ".host", "mode": "shell", "user": "root", "path": "/bin/sh", "args": ["/bin/sh", "-c", "echo $FOO > /tmp/none-existent-file"], "environment": ["FOO=BAR"]}' timeout 30 bash -c "until test -e /tmp/none-existent-file; do sleep .5; done" grep -q "BAR" /tmp/none-existent-file # test io.systemd.MachineImage.List varlinkctl --more call /run/systemd/machine/io.systemd.MachineImage io.systemd.MachineImage.List '{}' | grep 'long-running' varlinkctl --more call /run/systemd/machine/io.systemd.MachineImage io.systemd.MachineImage.List '{}' | grep '.host' varlinkctl call /run/systemd/machine/io.systemd.MachineImage io.systemd.MachineImage.List '{"name":"long-running"}' Found error in /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.private-pids.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.private-pids.sh # 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 } -- 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 </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 </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 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" -- # be at least 1 unmasked procfs mount in ANY directory. Otherwise, if /proc/ is masked (e.g. /proc/scsi is # over-mounted with tmpfs), then mounting a new /proc/ will fail. # # Thus, to guarantee PrivatePIDs=yes tests for unprivileged users pass, we mount a new procfs on a temporary # directory with no masking. This will guarantee an unprivileged user can mount a new /proc/ successfully. 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 we will mask /proc/ by mounting tmpfs over /proc/scsi. This will guarantee that mounting /proc/ will fail # for unprivileged users when using PrivatePIDs=yes. Now units should fail as PrivatePIDs=yes has no graceful # fallback. # Found error in /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.main-PID-change.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.main-PID-change.sh # Update it back to our own PID, this should also work systemd-notify --uid=1000 MAINPID="$MAINPID" test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" cat >/tmp/test-mainpid.sh <<\EOF #!/usr/bin/env bash set -eux set -o pipefail -- sleep infinity & disown echo $MAINPID >/run/mainpidsh/pid EOF chmod +x /tmp/test-mainpid.sh systemd-run --unit=test-mainpidsh.service \ -p StandardOutput=tty \ -p StandardError=tty \ -p Type=forking \ -p RuntimeDirectory=mainpidsh \ -p PIDFile=/run/mainpidsh/pid \ /tmp/test-mainpid.sh test "$(systemctl show -P MainPID test-mainpidsh.service)" -eq "$(cat /run/mainpidsh/pid)" cat >/tmp/test-mainpid2.sh <<\EOF #!/usr/bin/env bash set -eux set -o pipefail -- disown echo $MAINPID >/run/mainpidsh2/pid chown 1001:1001 /run/mainpidsh2/pid EOF chmod +x /tmp/test-mainpid2.sh systemd-run --unit=test-mainpidsh2.service \ -p StandardOutput=tty \ -p StandardError=tty \ -p Type=forking \ -p RuntimeDirectory=mainpidsh2 \ -p PIDFile=/run/mainpidsh2/pid \ /tmp/test-mainpid2.sh test "$(systemctl show -P MainPID test-mainpidsh2.service)" -eq "$(cat /run/mainpidsh2/pid)" cat >/dev/shm/test-mainpid3.sh </tmp/output [[ $(wc -l /dev/null # -b always behaves like -b0 journalctl -q -b-1 -b0 | head -1 >/tmp/expected journalctl -q -b-1 -b | head -1 >/tmp/output diff /tmp/expected /tmp/output # ... even when another option follows (both of these should fail due to -m) { journalctl -ball -b0 -m 2>&1 || :; } | head -1 >/tmp/expected { journalctl -ball -b -m 2>&1 || :; } | head -1 >/tmp/output diff /tmp/expected /tmp/output # https://github.com/systemd/systemd/issues/13708 ID=$(systemd-id128 new) systemd-cat -t "$ID" bash -c 'echo parent; (echo child) & wait' & PID=$! wait $PID journalctl --sync # We can drop this grep when https://github.com/systemd/systemd/issues/13937 # has a fix. journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/tmp/output [[ $(wc -l /tmp/expected systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usually fail";echo;env echo -n "and be truncated";echo;' journalctl --sync journalctl -b -o cat -t "$ID" >/tmp/output diff /tmp/expected /tmp/output [[ $(journalctl -b -o cat -t "$ID" --output-fields=_TRANSPORT | grep -Pc "^stdout$") -eq 3 ]] [[ $(journalctl -b -o cat -t "$ID" --output-fields=_LINE_BREAK | grep -Pc "^pid-change$") -eq 3 ]] [[ $(journalctl -b -o cat -t "$ID" --output-fields=_PID | sort -u | grep -c "^.*$") -eq 3 ]] [[ $(journalctl -b -o cat -t "$ID" --output-fields=MESSAGE | grep -Pc "^(This will|usually fail|and be truncated)$") -eq 3 ]] -- systemctl start forever-print-hola sleep 3 systemctl restart systemd-journald sleep 3 systemctl stop forever-print-hola [[ ! -f "/tmp/i-lose-my-logs" ]] # https://github.com/systemd/systemd/issues/4408 rm -f /tmp/i-lose-my-logs systemctl start forever-print-hola sleep 3 systemctl kill --signal=SIGKILL systemd-journald sleep 3 [[ ! -f "/tmp/i-lose-my-logs" ]] systemctl stop forever-print-hola set +o pipefail # https://github.com/systemd/systemd/issues/15528 journalctl --follow --file=/var/log/journal/*/* | head -n1 | grep . # https://github.com/systemd/systemd/issues/24565 journalctl --follow --merge | head -n1 | grep . set -o pipefail # https://github.com/systemd/systemd/issues/26746 rm -f /tmp/issue-26746-log /tmp/issue-26746-cursor ID="$(systemd-id128 new)" journalctl -t "$ID" --follow --cursor-file=/tmp/issue-26746-cursor | tee /tmp/issue-26746-log & systemd-cat -t "$ID" /bin/sh -c 'echo hogehoge' # shellcheck disable=SC2016 timeout 10 bash -c 'until [[ -f /tmp/issue-26746-log && "$(cat /tmp/issue-26746-log)" =~ hogehoge ]]; do sleep .5; done' pkill -TERM journalctl timeout 10 bash -c 'until test -f /tmp/issue-26746-cursor; do sleep .5; done' CURSOR_FROM_FILE="$(cat /tmp/issue-26746-cursor)" CURSOR_FROM_JOURNAL="$(journalctl -t "$ID" --output=export MESSAGE=hogehoge | sed -n -e '/__CURSOR=/ { s/__CURSOR=//; p }')" test "$CURSOR_FROM_FILE" = "$CURSOR_FROM_JOURNAL" # Check that the seqnum field at least superficially works systemd-cat echo "ya" -- while read -r file; do filename="${file##*/}" unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}" done < <(find /usr/lib/systemd/tests/testdata/test-journals/no-rtc -name "*.zst") journalctl --directory="$JOURNAL_DIR" --list-boots --output=json >/tmp/lb1 diff -u /tmp/lb1 - <<'EOF' [{"index":-3,"boot_id":"5ea5fc4f82a14186b5332a788ef9435e","first_entry":1666569600994371,"last_entry":1666584266223608},{"index":-2,"boot_id":"bea6864f21ad4c9594c04a99d89948b0","first_entry":1666569601005945,"last_entry":1666584347230411},{"index":-1,"boot_id":"4c708e1fd0744336be16f3931aa861fb","first_entry":1666569601017222,"last_entry":1666584354649355},{"index":0,"boot_id":"35e8501129134edd9df5267c49f744a4","first_entry":1666569601009823,"last_entry":1666584438086856}] EOF rm -rf "$JOURNAL_DIR" /tmp/lb1 # Check that using --after-cursor/--cursor-file= together with journal filters doesn't # skip over entries matched by the filter # See: https://github.com/systemd/systemd/issues/30288 UNIT_NAME="test-cursor-$RANDOM.service" Found error in /usr/lib/systemd/tests/testdata/units/TEST-04-JOURNAL.journal-remote.sh: $ grep -A5 -B5 /tmp/ /usr/lib/systemd/tests/testdata/units/TEST-04-JOURNAL.journal-remote.sh # Generate a self-signed certificate for systemd-journal-remote # # Note: older OpenSSL requires a config file with some extra options, unfortunately # Note2: /run here is used on purpose, since the systemd-journal-remote service uses PrivateTmp=yes mkdir -p /run/systemd/journal-remote-tls cat >/tmp/openssl.conf <"$LOG_FILE" awk '!/^(data: \{.+\}|)$/ { exit 1; }' "$LOG_FILE" # Same thing as journalctl --output=export mkdir /tmp/remote-journal curl -LSfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries >"$LOG_FILE" /usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none "$LOG_FILE" journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" rm -rf /tmp/remote-journal/* # Let's do the same thing again, but let systemd-journal-remote spawn curl itself /usr/lib/systemd/systemd-journal-remote --url=http://localhost:19531/entries \ --output=/tmp/remote-journal/system.journal \ --split-mode=none journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" rm -rf /tmp/remote-journal # /machine curl -LSfs http://localhost:19531/machine >"$LOG_FILE" jq . "$LOG_FILE" -- fi # Generate a self-signed certificate for systemd-journal-gatewayd # # Note: older OpenSSL requires a config file with some extra options, unfortunately cat >/tmp/openssl.conf < /tmp/syncfifo1 } export SYSTEMD_LOG_LEVEL=debug echo "toplevel PID: $BASHPID" |