From a8400c8f1a61223e4905e2939f8d71be82831c8c Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Thu, 23 Apr 2026 13:44:59 +0200 Subject: [PATCH 1/5] test: wrap even more binaries when running with sanitizers Turns out that the util-linux dep on libsystemd caused more fun than I originally anticipated: $ lddtree /usr/bin/dfuzzer dfuzzer => /usr/bin/dfuzzer (interpreter => /lib64/ld-linux-x86-64.so.2) libgio-2.0.so.0 => /lib64/libgio-2.0.so.0 libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0 libz.so.1 => /lib64/libz.so.1 libmount.so.1 => /lib64/libmount.so.1 libblkid.so.1 => /lib64/libblkid.so.1 libsystemd.so.0 => /lib64/libsystemd.so.0 libm.so.6 => /lib64/libm.so.6 ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 libselinux.so.1 => /lib64/libselinux.so.1 libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 ... Also, the tpm2 utils now depend on libudev through libcurl -> libssh -> libfido2 dep chain: $ lddtree /usr/bin/tpm2_pcrread tpm2_pcrread => /usr/bin/tpm2_pcrread (interpreter => /lib64/ld-linux-x86-64.so.2) ... libcurl.so.4 => /lib64/libcurl.so.4 ... libssh.so.4 => /lib64/libssh.so.4 libfido2.so.1 => /lib64/libfido2.so.1 libcbor.so.0.13 => /lib64/libcbor.so.0.13 libudev.so.1 => /lib64/libudev.so.1 libgcc_s.so.1 => /lib64/libgcc_s.so.1 ... Follow-up for 8030e0b19ef7c0e823d84dd08ad38a2d88e0a230. --- mkosi/mkosi.sanitizers/mkosi.postinst | 9 +++++++++ test/units/TEST-07-PID1.user-namespace-path.sh | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mkosi/mkosi.sanitizers/mkosi.postinst b/mkosi/mkosi.sanitizers/mkosi.postinst index 88ba2c2bc0..988a604c63 100755 --- a/mkosi/mkosi.sanitizers/mkosi.postinst +++ b/mkosi/mkosi.sanitizers/mkosi.postinst @@ -56,6 +56,7 @@ wrap=( dbus-broker-launch dbus-daemon delv + dfuzzer dhcpd dig dnf @@ -70,6 +71,7 @@ wrap=( groups id integritysetup + iscsiadm iscsid keymgr knotc @@ -79,12 +81,15 @@ wrap=( login ls lsblk + lsns lsof lvm mdadm mkfs.btrfs + mkfs.ext4 mksquashfs mount + mountpoint multipath multipathd nvme @@ -98,8 +103,12 @@ wrap=( stat stress-ng su + swapoff + swapon tar tgtd + # The tpm2 tools (tpm2_readpublic, tpm2_pcrextend, ...) all are symlinks to tpm2 + tpm2 umount unix_chkpwd useradd diff --git a/test/units/TEST-07-PID1.user-namespace-path.sh b/test/units/TEST-07-PID1.user-namespace-path.sh index 437968e8c2..fda83a9566 100755 --- a/test/units/TEST-07-PID1.user-namespace-path.sh +++ b/test/units/TEST-07-PID1.user-namespace-path.sh @@ -6,15 +6,6 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -# When sanitizers are used, export LD_PRELOAD with the sanitizers path, -# lsns doesn't work otherwise. -if [ -f /usr/lib/systemd/systemd-asan-env ]; then - # shellcheck source=/dev/null - . /usr/lib/systemd/systemd-asan-env - export LD_PRELOAD - export ASAN_OPTIONS -fi - # Only reuse the user namespace systemd-run --unit=oldservice --property=Type=exec --property=PrivateUsers=true sleep 3600 OLD_PID=$(systemctl show oldservice -p MainPID | awk -F= '{print $2}') From e3aaf3d76eb0990ca015961703e905977df8faf7 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Fri, 24 Apr 2026 14:17:23 +0200 Subject: [PATCH 2/5] test: drop any memory limits from units when running with sanitizers As the memory usage under sanitizers is quite unpredictable. This is currently relevant mainly for Polkit, as it introduced memory limits for its polkitd.service unit in the latest version [0] which are very easy to trigger when running under sanitizers (as polkitd depends on libsystemd which brings ASan into polkitd's address space). [0] https://github.com/polkit-org/polkit/commit/7d9c06c58a957ee3f2a4383ade6f207b05207e3e --- mkosi/mkosi.sanitizers/mkosi.postinst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mkosi/mkosi.sanitizers/mkosi.postinst b/mkosi/mkosi.sanitizers/mkosi.postinst index 988a604c63..a59b5d0478 100755 --- a/mkosi/mkosi.sanitizers/mkosi.postinst +++ b/mkosi/mkosi.sanitizers/mkosi.postinst @@ -9,13 +9,17 @@ if [[ ! -f "$BUILDROOT/$LIBSYSTEMD" ]]; then exit 0 fi -# ASAN and syscall filters aren't compatible with each other. +# ASAN and syscall filters aren't compatible with each other. Also, drop any memory limits +# as these are quite unpredictable when running under sanitizers. find "$BUILDROOT"/usr "$BUILDROOT"/etc -name '*.service' -type f | while read -r unit; do - if grep -q -e MemoryDeny -e SystemCall "$unit" ; then + if grep -q -e MemoryDeny -e MemoryMax -e MemoryHigh -e MemorySwapMax -e SystemCall "$unit" ; then mkdir -p "$unit.d" cat > "$unit.d/sanitizer-compat.conf" < Date: Thu, 23 Apr 2026 15:11:01 +0200 Subject: [PATCH 3/5] test: temporarily ignore sanitizer warning about blocked ptrace() LLVM 22 introduced an additional check [0] for ptrace() syscall when invoking sanitizers [0] which currently produces a false-positive warning when running some of our units under sanitizers: [ 47.524680] systemd-timedated[740]: ==740==WARNING: ptrace appears to be blocked (is seccomp enabled?). LeakSanitizer may hang. [ 47.524680] systemd-timedated[740]: ==740==Child exited with signal 15. ... [ 1555.734223] systemd-oomd[93]: ==93==WARNING: ptrace appears to be blocked (is seccomp enabled?). LeakSanitizer may hang. [ 1555.734223] systemd-oomd[93]: ==93==Child exited with signal 15. ... It is a false positive because we disable the seccomp filters system-wide for our units in the sanitizer jobs. Now, from what I've seen so far this happens only in Type=notify(-reload) units that also utilize bus_event_loop_with_idle(). This, combined with the fact that the ptrace()-check child process from [0] checks only if the child process was killed by _any_ signal, means that if the systemd unit exits on its own after becoming idle and then something sends it SIGTERM (either via explicit `systemctl stop` or during system shutdown), this SIGTERM might hit the ptrace()-check child process from the sanitizer handler (as we also send the signal to all processes in the target cgroup), which the parent process then mistakenly evaluates as a blocked ptrace() syscall, even though the check process wasn't killed by SIGSYS. I filed this as [1] to the LLVM project, but let's also temporarily ignore the warning in the sanitizer report processing, as it currently causes annoying test fails. [0] https://github.com/llvm/llvm-project/commit/a708b4bf21d7c2298224cdacf7d424abc3c8fed4 [1] https://github.com/llvm/llvm-project/issues/193714 --- test/integration-tests/integration-test-wrapper.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/integration-tests/integration-test-wrapper.py b/test/integration-tests/integration-test-wrapper.py index 93e1e0d91b..69b4333fee 100755 --- a/test/integration-tests/integration-test-wrapper.py +++ b/test/integration-tests/integration-test-wrapper.py @@ -142,7 +142,19 @@ def process_sanitizer_report(args: argparse.Namespace, journal_file: Path) -> bo fatal_end = re.compile(r'==[0-9]+==HINT:\s+\w+Sanitizer') # 'Standard' errors: - standard_begin = re.compile(r'([0-9]+: runtime error|==[0-9]+==.+?\w+Sanitizer)') + # + # TODO: there's currently a bug in LLVM 22 due to which certain systemd + # units can throw the following warning: + # [ 3366.747202] systemd-oomd[93]: ==93==WARNING: ptrace appears to be blocked (is seccomp enabled?). + # LeakSanitizer may hang. + # [ 3366.747202] systemd-oomd[93]: ==93==Child exited with signal 15. + # + # which is then picked up by the following regex and causes the test to + # fail. Let's, temporarily, exclude this warning from the regex to mitigate + # this. + # + # See: https://github.com/llvm/llvm-project/issues/193714 + standard_begin = re.compile(r'([0-9]+: runtime error|==[0-9]+==(?!WARNING: ptrace).+?\w+Sanitizer)') standard_end = re.compile(r'SUMMARY:\s+(\w+)Sanitizer') # extract COMM From 035ba3ea571bad6772cf3731f6b5379ccb08267f Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Sat, 25 Apr 2026 16:37:34 +0200 Subject: [PATCH 4/5] test: slightly reduce the performance/memory overhead for wrapped binaries Let's drop the quarantine that ASan uses for use-after-free detection, as it's pointless in wrapped binaries and can consume up to 256 MiB of memory (with the default configuration). Also, don't keep any stack traces for allocations & deallocations, which should (slightly) help with both memory & performance overhead. --- mkosi/mkosi.sanitizers/mkosi.postinst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mkosi/mkosi.sanitizers/mkosi.postinst b/mkosi/mkosi.sanitizers/mkosi.postinst index a59b5d0478..42bbd41063 100755 --- a/mkosi/mkosi.sanitizers/mkosi.postinst +++ b/mkosi/mkosi.sanitizers/mkosi.postinst @@ -140,8 +140,11 @@ for bin in "${wrap[@]}"; do # Preload the ASan runtime DSO, otherwise ASan will complain export LD_PRELOAD="$ASAN_RT_PATH" # Disable LSan to speed things up, since we don't care about leak reports -# from 'external' binaries -export ASAN_OPTIONS=detect_leaks=$enable_lsan +# from 'external' binaries. In addition, disable quarantine (for use-after-free +# detection) and malloc stack frame collection as we don't care about these in +# 'external' binaries either, and they just unnecessarily hog up memory & cpu +# cycles. +export ASAN_OPTIONS=detect_leaks=$enable_lsan:quarantine_size_mb=0:malloc_context_size=0 # Set argv[0] to the original binary name without the ".orig" suffix exec -a "\$0" -- "${target}.orig" "\$@" EOF From ef3c07352b5dfe04afefdf66f4693986562ddc2b Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Sat, 25 Apr 2026 23:39:47 +0200 Subject: [PATCH 5/5] test: don't strip directives from test units The original find was matching even our test units, which caused issues when the check was extended with Memory*= directives, as we stripped them off from test units for TEST-55-OOMD where we certainly need them. Since the stripping was meant primarily for "production-grade" units, let's limit it to units under /etc/systemd/system/ and /usr/lib/systemd/system/. --- mkosi/mkosi.sanitizers/mkosi.postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkosi/mkosi.sanitizers/mkosi.postinst b/mkosi/mkosi.sanitizers/mkosi.postinst index 42bbd41063..f420a31b63 100755 --- a/mkosi/mkosi.sanitizers/mkosi.postinst +++ b/mkosi/mkosi.sanitizers/mkosi.postinst @@ -11,7 +11,7 @@ fi # ASAN and syscall filters aren't compatible with each other. Also, drop any memory limits # as these are quite unpredictable when running under sanitizers. -find "$BUILDROOT"/usr "$BUILDROOT"/etc -name '*.service' -type f | while read -r unit; do +find "$BUILDROOT"/{etc,usr/lib}/systemd/system/ -name '*.service' -type f | while read -r unit; do if grep -q -e MemoryDeny -e MemoryMax -e MemoryHigh -e MemorySwapMax -e SystemCall "$unit" ; then mkdir -p "$unit.d" cat > "$unit.d/sanitizer-compat.conf" <