From 25338c37915521876c84bca196de50d73c3c17ea Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Mon, 13 Dec 2021 20:50:28 +0100 Subject: [PATCH] test: fuzz our dbus interfaces with dfuzzer (cherry picked from commit 354b3364aa63620a0f732bb8a6fe9332a4f550e4) Related: #2087652 --- test/TEST-21-DFUZZER/Makefile | 1 + test/TEST-21-DFUZZER/test.sh | 24 +++++++++ test/test-functions | 1 + test/units/testsuite-21.service | 10 ++++ test/units/testsuite-21.sh | 94 +++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 120000 test/TEST-21-DFUZZER/Makefile create mode 100755 test/TEST-21-DFUZZER/test.sh create mode 100644 test/units/testsuite-21.service create mode 100755 test/units/testsuite-21.sh diff --git a/test/TEST-21-DFUZZER/Makefile b/test/TEST-21-DFUZZER/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-21-DFUZZER/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-21-DFUZZER/test.sh b/test/TEST-21-DFUZZER/test.sh new file mode 100755 index 0000000000..ecc04e368c --- /dev/null +++ b/test/TEST-21-DFUZZER/test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -e + +TEST_DESCRIPTION="Fuzz our D-Bus interfaces with dfuzzer" +TEST_NO_NSPAWN=1 +TEST_SUPPORTING_SERVICES_SHOULD_BE_MASKED=0 +QEMU_TIMEOUT="${QEMU_TIMEOUT:-1800}" + +# shellcheck source=test/test-functions +. "${TEST_BASE_DIR:?}/test-functions" + +command -v dfuzzer >/dev/null || exit 0 + +test_append_files() { + local workspace="${1:?}" + + image_install dfuzzer /etc/dfuzzer.conf + + # Enable all systemd-related services, including the D-Bus ones + "$SYSTEMCTL" --root="${workspace:?}" preset-all +} + +do_test "$@" diff --git a/test/test-functions b/test/test-functions index 44f465c914..079a7249e4 100644 --- a/test/test-functions +++ b/test/test-functions @@ -99,6 +99,7 @@ SYSTEMD_JOURNAL_REMOTE="${SYSTEMD_JOURNAL_REMOTE:-$(command -v "$BUILD_DIR/syste SYSTEMD="${SYSTEMD:-$(command -v "$BUILD_DIR/systemd" || command -v "$ROOTLIBDIR/systemd")}" SYSTEMD_NSPAWN="${SYSTEMD_NSPAWN:-$(command -v "$BUILD_DIR/systemd-nspawn" || command -v systemd-nspawn)}" JOURNALCTL="${JOURNALCTL:-$(command -v "$BUILD_DIR/journalctl" || command -v journalctl)}" +SYSTEMCTL="${SYSTEMCTL:-$(command -v "$BUILD_DIR/systemctl" || command -v systemctl)}" TESTFILE="${BASH_SOURCE[1]}" if [ -z "$TESTFILE" ]; then diff --git a/test/units/testsuite-21.service b/test/units/testsuite-21.service new file mode 100644 index 0000000000..a5f77d07b4 --- /dev/null +++ b/test/units/testsuite-21.service @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Fuzz our D-Bus interfaces with dfuzzer +After=dbus.service multi-user.target +Wants=dbus.service multi-user.target + +[Service] +ExecStartPre=rm -f /failed /skipped /testok +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +Type=oneshot diff --git a/test/units/testsuite-21.sh b/test/units/testsuite-21.sh new file mode 100755 index 0000000000..43b5fb6f22 --- /dev/null +++ b/test/units/testsuite-21.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# 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 + +at_exit() { + # "Safety net" - check for any coredumps which might have not caused dfuzzer + # to stop & return an error (we need to do this now before truncating the + # journal) + # TODO: check fo ASan/UBSan errors + local found_cd=0 + while read -r exe; do + coredumctl info "$exe" + found_cd=1 + done < <(coredumpctl -F COREDUMP_EXE | sort -u) + [[ $found_cd -eq 0 ]] || exit 1 + + # We have to call the end.service 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 + [[ $SHUTDOWN_AT_EXIT -ne 0 ]] && systemctl start --job-mode=flush end.service +} + +trap at_exit EXIT + +systemctl log-level info + +# 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.network1 + org.freedesktop.portable1 + org.freedesktop.resolve1 + org.freedesktop.systemd1 + org.freedesktop.timedate1 + org.freedesktop.timesync1 +) + +# systemd-oomd requires PSI +if tail -n +1 /proc/pressure/{cpu,io,memory}; then + BUS_LIST+=(org.freedesktop.oom1) +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 -v -b "$PAYLOAD_MAX" -n "$bus" + + # Let's reload the systemd daemon to test (de)serialization as well + systemctl daemon-reload +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 -v -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 +done + +echo OK >/testok + +exit 0