blob: 08ebfd91eb65996e10908dc46c53b7a8cfb7d384 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#!/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
# 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
# shellcheck disable=SC2317
at_exit() {
set +e
# We have to call the end.service/poweroff explicitly even if it's specified on
# the kernel cmdline via systemd.wants=end.service, since dfuzzer calls
# org.freedesktop.systemd1.Manager.ClearJobs() which drops the service
# from the queue
if [[ $SHUTDOWN_AT_EXIT -ne 0 ]] && ! systemctl poweroff; then
# PID1 is down let's try to save the journal
journalctl --sync # journal can be down as well so let's ignore exit codes here
systemctl -ff poweroff # sync() and reboot(RB_POWER_OFF)
fi
}
add_suppression() {
local interface="${1:?}"
local suppression="${2:?}"
sed -i "\%\[$interface\]%a$suppression" /etc/dfuzzer.conf
}
trap at_exit EXIT
systemctl log-level info
# FIXME: systemd-run doesn't play well with daemon-reexec
# See: https://github.com/systemd/systemd/issues/27204
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"
# 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
cat /etc/dfuzzer.conf
# 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
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
)
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 \
-- dfuzzer -b "$PAYLOAD_MAX" -n "$bus"
# Let's reload the systemd daemon to test (de)serialization as well
systemctl daemon-reload
# FIXME: explicitly trigger reexecute until systemd/systemd#27204 is resolved
systemctl daemon-reexec
done
umount /var/lib/machines
for bus in "${SESSION_BUS_LIST[@]}"; do
echo "Bus: $bus (session)"
systemd-run --machine 'testuser@.host' --user --pipe --wait \
-- dfuzzer -b "$PAYLOAD_MAX" -n "$bus"
# Let's reload the systemd user daemon to test (de)serialization as well
systemctl --machine 'testuser@.host' --user daemon-reload
# FIXME: explicitly trigger reexecute until systemd/systemd#27204 is resolved
systemctl --machine 'testuser@.host' --user daemon-reexec
done
touch /testok
|