2021-12-13 22:50:28 +03:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
2024-04-05 19:38:18 +03:00
# check dfuzzer is present before testing
if ! command -v dfuzzer & >/dev/null; then
echo "dfuzzer is not installed, skipping" | tee --append /skipped
exit 77
fi
2021-12-13 22:50:28 +03:00
# Save the end.service state before we start fuzzing, as it might get changed
# on the fly by one of the fuzzers
systemctl list-jobs | grep -F 'end.service' && SHUTDOWN_AT_EXIT = 1 || SHUTDOWN_AT_EXIT = 0
2023-04-26 12:05:40 +03:00
# shellcheck disable=SC2317
2021-12-13 22:50:28 +03:00
at_exit( ) {
2022-06-21 11:13:48 +03:00
set +e
2022-06-21 11:20:12 +03:00
# We have to call the end.service/poweroff explicitly even if it's specified on
2021-12-13 22:50:28 +03:00
# the kernel cmdline via systemd.wants=end.service, since dfuzzer calls
# org.freedesktop.systemd1.Manager.ClearJobs() which drops the service
# from the queue
2022-06-21 11:20:12 +03:00
if [ [ $SHUTDOWN_AT_EXIT -ne 0 ] ] && ! systemctl poweroff; then
# PID1 is down let's try to save the journal
2022-06-26 22:00:43 +03:00
journalctl --sync # journal can be down as well so let's ignore exit codes here
2022-06-21 11:20:12 +03:00
systemctl -ff poweroff # sync() and reboot(RB_POWER_OFF)
fi
2021-12-13 22:50:28 +03:00
}
2023-12-29 01:15:42 +03:00
add_suppression( ) {
local interface = " ${ 1 : ? } "
local suppression = " ${ 2 : ? } "
sed -i " \%\[ $interface \]%a $suppression " /etc/dfuzzer.conf
}
2021-12-13 22:50:28 +03:00
trap at_exit EXIT
systemctl log-level info
2023-04-26 12:05:40 +03:00
# FIXME: systemd-run doesn't play well with daemon-reexec
# See: https://github.com/systemd/systemd/issues/27204
2023-12-29 01:15:42 +03:00
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Manager:Reexecute FIXME"
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Manager:SoftReboot destructive"
add_suppression "org.freedesktop.login1" "Sleep destructive"
2023-11-02 20:11:55 +03:00
2023-12-29 01:42:47 +03:00
# Skip calling start and stop methods on unit objects, as doing that is not only time consuming, but it also
# starts/stops units that interfere with the machine state. The actual code paths should be covered (to some
# degree) by the respective method counterparts on the manager object.
for method in Start Stop Restart ReloadOrRestart ReloadOrTryRestart Kill; do
add_suppression "org.freedesktop.systemd1" " org.freedesktop.systemd1.Unit: $method "
done
2023-12-29 01:15:42 +03:00
cat /etc/dfuzzer.conf
2023-04-26 12:05:40 +03:00
2021-12-13 22:50:28 +03:00
# TODO
# * check for possibly newly introduced buses?
BUS_LIST = (
org.freedesktop.home1
org.freedesktop.hostname1
org.freedesktop.import1
org.freedesktop.locale1
org.freedesktop.login1
org.freedesktop.machine1
org.freedesktop.portable1
org.freedesktop.resolve1
org.freedesktop.systemd1
org.freedesktop.timedate1
)
# systemd-oomd requires PSI
if tail -n +1 /proc/pressure/{ cpu,io,memory} ; then
2022-06-26 21:52:12 +03:00
BUS_LIST += (
org.freedesktop.oom1
)
fi
# Some services require specific conditions:
# - systemd-timesyncd can't run in a container
# - systemd-networkd can run in a container if it has CAP_NET_ADMIN capability
if ! systemd-detect-virt --container; then
BUS_LIST += (
org.freedesktop.network1
org.freedesktop.timesync1
)
elif busctl introspect org.freedesktop.network1 / & >/dev/null; then
BUS_LIST += (
org.freedesktop.network1
)
2021-12-13 22:50:28 +03:00
fi
SESSION_BUS_LIST = (
org.freedesktop.systemd1
)
# Maximum payload size generated by dfuzzer (in bytes) - default: 50K
PAYLOAD_MAX = 50000
# Tweak the maximum payload size if we're running under sanitizers, since
# with larger payloads we start hitting reply timeouts
if [ [ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ] ] ; then
PAYLOAD_MAX = 10000 # 10K
fi
# Overmount /var/lib/machines with a size-limited tmpfs, as fuzzing
# the org.freedesktop.machine1 stuff makes quite a mess
mount -t tmpfs -o size = 50M tmpfs /var/lib/machines
# Fuzz both the system and the session buses (where applicable)
for bus in " ${ BUS_LIST [@] } " ; do
echo " Bus: $bus (system) "
systemd-run --pipe --wait \
2022-06-21 11:04:03 +03:00
-- dfuzzer -b " $PAYLOAD_MAX " -n " $bus "
2021-12-13 22:50:28 +03:00
# Let's reload the systemd daemon to test (de)serialization as well
systemctl daemon-reload
2023-04-26 12:05:40 +03:00
# FIXME: explicitly trigger reexecute until systemd/systemd#27204 is resolved
systemctl daemon-reexec
2021-12-13 22:50:28 +03:00
done
umount /var/lib/machines
for bus in " ${ SESSION_BUS_LIST [@] } " ; do
echo " Bus: $bus (session) "
systemd-run --machine 'testuser@.host' --user --pipe --wait \
2022-06-21 11:04:03 +03:00
-- dfuzzer -b " $PAYLOAD_MAX " -n " $bus "
2021-12-13 22:50:28 +03:00
# Let's reload the systemd user daemon to test (de)serialization as well
systemctl --machine 'testuser@.host' --user daemon-reload
2023-04-26 12:05:40 +03:00
# FIXME: explicitly trigger reexecute until systemd/systemd#27204 is resolved
systemctl --machine 'testuser@.host' --user daemon-reexec
2021-12-13 22:50:28 +03:00
done
2023-07-12 16:49:55 +03:00
touch /testok