mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
The whole point of using 'command -v' is that it's a very portable way to check if an executable exists. It doesn't print an error.
225 lines
6.0 KiB
Bash
Executable File
225 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
set -eux
|
|
set -o pipefail
|
|
|
|
# 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
|
|
|
|
if [[ ! -v ASAN_OPTIONS && ! -v UBSAN_OPTIONS && "${TEST_RUN_DFUZZER:-0}" == "0" ]]; then
|
|
echo "no sanitizer is enabled, skipping. (Hint: set TEST_RUN_DFUZZER=1 to run test forcibly)."
|
|
exit 77
|
|
fi
|
|
|
|
add_suppression() {
|
|
local interface="${1:?}"
|
|
local suppression="${2:?}"
|
|
|
|
sed -i "\%\[$interface\]%a$suppression" /etc/dfuzzer.conf
|
|
}
|
|
|
|
systemctl log-level info
|
|
|
|
# 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.
|
|
MANAGER_METHOD_FILTER=(
|
|
StartUnit
|
|
StartUnitWithFlags
|
|
StartUnitReplace
|
|
StopUnit
|
|
RestartUnit
|
|
TryRestartUnit
|
|
ReloadOrRestartUnit
|
|
ReloadOrTryRestartUnit
|
|
KillUnit
|
|
QueueSignalUnit
|
|
FreezeUnit
|
|
AttachProcessesToUnit
|
|
RemoveSubgroupFromUnit
|
|
AbandonScope
|
|
CancelJob
|
|
Exit
|
|
Reboot
|
|
SoftReboot
|
|
PowerOff
|
|
Halt
|
|
KExec
|
|
SwitchRoot
|
|
EnqueueMarkedJobs
|
|
)
|
|
UNIT_METHOD_FILTER=(
|
|
Start
|
|
Stop
|
|
Restart
|
|
TryRestart
|
|
ReloadOrRestart
|
|
ReloadOrTryRestart
|
|
Kill
|
|
QueueSignal
|
|
Freeze
|
|
)
|
|
SCOPE_METHOD_FILTER=(
|
|
Abandon
|
|
)
|
|
JOB_METHOD_FILTER=(
|
|
Cancel
|
|
)
|
|
LOGIN_METHOD_FILTER=(
|
|
FlushDevices # This triggers all devices and makes the system super heavy
|
|
PowerOff
|
|
PowerOffWithFlags
|
|
Reboot
|
|
RebootWithFlags
|
|
Halt
|
|
HaltWithFlags
|
|
Suspend
|
|
SuspendWithFlags
|
|
Hibernate
|
|
HibernateWithFlags
|
|
HybridSleep
|
|
HybridSleepWithFlags
|
|
SuspendThenHibernate
|
|
SuspendThenHibernateWithFlags
|
|
ScheduleShutdown
|
|
)
|
|
for method in "${MANAGER_METHOD_FILTER[@]}"; do
|
|
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Manager:$method"
|
|
done
|
|
for method in "${UNIT_METHOD_FILTER[@]}"; do
|
|
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Unit:$method"
|
|
done
|
|
for method in "${SCOPE_METHOD_FILTER[@]}"; do
|
|
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Scope:$method"
|
|
done
|
|
for method in "${JOB_METHOD_FILTER[@]}"; do
|
|
add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Job:$method"
|
|
done
|
|
for method in "${LOGIN_METHOD_FILTER[@]}"; do
|
|
add_suppression "org.freedesktop.login1" "org.freedesktop.login1.Manager:$method"
|
|
done
|
|
|
|
cat /etc/dfuzzer.conf
|
|
|
|
# TODO
|
|
# * check for possibly newly introduced buses?
|
|
NAME_LIST=(
|
|
home
|
|
hostname
|
|
import
|
|
locale
|
|
login
|
|
machine
|
|
portable
|
|
resolve
|
|
timedate
|
|
)
|
|
|
|
# Some services require specific conditions:
|
|
# - systemd-oomd requires PSI
|
|
# - systemd-timesyncd can't run in a container
|
|
# - systemd-networkd can run in a container if it has CAP_NET_ADMIN capability
|
|
if tail -n +1 /proc/pressure/{cpu,io,memory}; then
|
|
NAME_LIST+=( oom )
|
|
fi
|
|
|
|
if ! systemd-detect-virt --container; then
|
|
NAME_LIST+=( timesync )
|
|
fi
|
|
|
|
if ip link add dummy-fuzz type dummy; then
|
|
# if a dummy interface is created, then let's also setup it for resolved
|
|
ip link set dummy-fuzz up
|
|
ip address add 192.0.2.1/24 dev dummy-fuzz
|
|
|
|
# When we can create a dummy interface, we definitely have CAP_NET_ADMIN
|
|
NAME_LIST+=( network )
|
|
|
|
# Create unit files for another dummy interface for networkd
|
|
mkdir -p /run/systemd/network
|
|
cat >/run/systemd/network/10-dummy-fuzz2.netdev <<EOF
|
|
[NetDev]
|
|
Kind=dummy
|
|
Name=dummy-fuzz2
|
|
EOF
|
|
cat >/run/systemd/network/10-dummy-fuzz2.network <<EOF
|
|
[Match]
|
|
Name=dummy-fuzz2
|
|
[Network]
|
|
Address=192.0.2.2/24
|
|
EOF
|
|
fi
|
|
|
|
# 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
|
|
|
|
# Disable debugging logs from systemd-homed, systemd-nsresourced, and systemd-userdbd.
|
|
# Otherwise, journal is filled with the debugging logs by them.
|
|
systemctl service-log-level systemd-homed.service info
|
|
for service in systemd-nsresourced.service systemd-userdbd.service; do
|
|
mkdir -p "/run/systemd/system/${service}.d"
|
|
cat >"/run/systemd/system/${service}.d/10-disable-debug.conf" <<EOF
|
|
[Service]
|
|
Environment=SYSTEMD_LOG_LEVEL=info
|
|
EOF
|
|
systemctl daemon-reload
|
|
systemctl restart "$service"
|
|
done
|
|
|
|
test_systemd() {
|
|
systemd-run "$@" --pipe --wait \
|
|
-- dfuzzer -b "$PAYLOAD_MAX" -n org.freedesktop.systemd1
|
|
|
|
# Let's reload the systemd user daemon to test (de)serialization as well
|
|
systemctl "$@" daemon-reload
|
|
# FIXME: explicitly trigger reexecute until systemd/systemd#27204 is resolved
|
|
systemctl "$@" daemon-reexec
|
|
}
|
|
|
|
# Let's first test the session bus before the system one, as it may be in a
|
|
# spurious state after fuzzing the system bus or login bus.
|
|
echo "Bus: org.freedesktop.systemd1 (session)"
|
|
test_systemd --machine 'testuser@.host' --user
|
|
|
|
# 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
|
|
|
|
# Next, test the system service buses, as the services may be in a spurious
|
|
# state after fuzzing the system service manager bus.
|
|
for name in "${NAME_LIST[@]}"; do
|
|
bus="org.freedesktop.${name}1"
|
|
service="systemd-${name}d.service"
|
|
|
|
echo "Bus: $bus"
|
|
|
|
# Unmask and enable the service.
|
|
systemctl unmask "$service"
|
|
systemctl enable "$service"
|
|
|
|
# enable debugging logs
|
|
systemctl service-log-level "$service" debug || :
|
|
|
|
systemd-run --pipe --wait \
|
|
-- dfuzzer -b "$PAYLOAD_MAX" -n "$bus"
|
|
|
|
# disable debugging logs
|
|
systemctl service-log-level "$service" info || :
|
|
done
|
|
|
|
umount /var/lib/machines
|
|
|
|
# Finally, test the system bus.
|
|
echo "Bus: org.freedesktop.systemd1 (system)"
|
|
test_systemd
|
|
|
|
touch /testok
|