From a0da62f2cb7f593cb8ba570bd9f12bd777399ace Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Thu, 9 Oct 2025 23:08:19 +0200 Subject: [PATCH] test: build the crashing test binary outside of the test So we don't have to pull in gcc and other stuff into it. Also, make the test itself a bit more robust and debug-able. (cherry picked from commit 937f609b41b9e27eba69c5ddbab4df2232e5a37b) --- src/test/meson.build | 11 ++++ src/test/test-coredump-stacktrace.c | 29 +++++++++ test/units/TEST-87-AUX-UTILS-VM.coredump.sh | 72 +++++++++++++++------ 3 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 src/test/test-coredump-stacktrace.c diff --git a/src/test/meson.build b/src/test/meson.build index da04b82d476..cfd15d118b4 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -276,6 +276,17 @@ executables += [ 'sources' : files('test-compress.c'), 'link_with' : [libshared], }, + test_template + { + 'sources' : files('test-coredump-stacktrace.c'), + 'type' : 'manual', + # This test intentionally crashes with SIGSEGV by dereferencing a NULL pointer + # to generate a coredump with a predictable stack trace. To prevent sanitizers + # from catching the error first let's disable them explicitly, and also always + # build with minimal optimizations to make the stack trace predictable no matter + # what we build the rest of systemd with + 'override_options' : ['b_sanitize=none', 'strip=false', 'debug=true'], + 'c_args' : ['-fno-sanitize=all', '-fno-optimize-sibling-calls', '-O1'], + }, test_template + { 'sources' : files('test-cryptolib.c'), 'dependencies' : libopenssl, diff --git a/src/test/test-coredump-stacktrace.c b/src/test/test-coredump-stacktrace.c new file mode 100644 index 00000000000..334a155a9c1 --- /dev/null +++ b/src/test/test-coredump-stacktrace.c @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* This is a test program that intentionally segfaults so we can generate a + * predictable-ish stack trace in tests. */ + +#include + +__attribute__((noinline)) +static void baz(int *x) { + *x = rand(); +} + +__attribute__((noinline)) +static void bar(void) { + int * volatile x = NULL; + + baz(x); +} + +__attribute__((noinline)) +static void foo(void) { + bar(); +} + +int main(void) { + foo(); + + return 0; +} diff --git a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh index 7384784b21e..354498a5ff6 100755 --- a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh +++ b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh @@ -8,15 +8,13 @@ set -o pipefail # Make sure the binary name fits into 15 characters CORE_TEST_BIN="/tmp/test-dump" -CORE_STACKTRACE_TEST_BIN="/tmp/test-stacktrace-dump" -MAKE_STACKTRACE_DUMP="/tmp/make-stacktrace-dump" CORE_TEST_UNPRIV_BIN="/tmp/test-usr-dump" MAKE_DUMP_SCRIPT="/tmp/make-dump" # Unset $PAGER so we don't have to use --no-pager everywhere export PAGER= at_exit() { - rm -fv -- "$CORE_TEST_BIN" "$CORE_TEST_UNPRIV_BIN" "$MAKE_DUMP_SCRIPT" "$MAKE_STACKTRACE_DUMP" + rm -fv -- "$CORE_TEST_BIN" "$CORE_TEST_UNPRIV_BIN" "$MAKE_DUMP_SCRIPT" } (! systemd-detect-virt -cq) @@ -251,30 +249,66 @@ systemd-run -t --property CoredumpFilter=default ls /tmp (! coredumpctl debug --debugger=/bin/true --debugger-arguments='"') # Test for EnterNamespace= feature -if pkgconf --atleast-version 0.192 libdw ; then - # dwfl_set_sysroot() is supported only in libdw-0.192 or newer. - cat >"$MAKE_STACKTRACE_DUMP" <"$MAKE_STACKTRACE_DUMP" <<\EOF +#!/usr/bin/bash -eux + +TARGET="/tmp/${1:?}" +EC=0 + +# "Unhide" debuginfo in the namespace (see the comment below) +test -d /usr/lib/debug/ && umount /usr/lib/debug/ + +mount -t tmpfs tmpfs /tmp/ +cp /usr/lib/systemd/tests/unit-tests/manual/test-coredump-stacktrace "$TARGET" + +$TARGET || EC=$? +if [[ $EC -ne 139 ]]; then + echo >&2 "$TARGET didn't crash, this shouldn't happen" + exit 1 +fi + +exit 0 EOF -$CORE_STACKTRACE_TEST_BIN -END chmod +x "$MAKE_STACKTRACE_DUMP" + # Since the test-coredump-stacktrace binary is built together with rest of the systemd its debug symbols + # might be part of debuginfo packages (if supported & built), and libdw will then use them to symbolize + # the stacktrace even if it doesn't have access to the original crashing binary. Let's make the test + # simpler and just "hide" the debuginfo data, so libdw is forced to access the target namespace to get + # the necessary symbols + test -d /usr/lib/debug/ && mount -t tmpfs tmpfs /usr/lib/debug/ + mkdir -p /run/systemd/coredump.conf.d/ printf '[Coredump]\nEnterNamespace=no' >/run/systemd/coredump.conf.d/99-enter-namespace.conf - unshare --pid --fork --mount-proc --mount --uts --ipc --net bash -c "$MAKE_STACKTRACE_DUMP" || : - timeout 30 bash -c "until coredumpctl -1 info $CORE_STACKTRACE_TEST_BIN | grep -zvqE 'baz.*bar.*foo'; do sleep .2; done" + unshare --pid --fork --mount-proc --mount --uts --ipc --net "$MAKE_STACKTRACE_DUMP" "test-stacktrace-not-symbolized" + timeout 30 bash -c "until coredumpctl list -q --no-legend /tmp/test-stacktrace-not-symbolized; do sleep .2; done" + coredumpctl info /tmp/test-stacktrace-not-symbolized | tee /tmp/not-symbolized.log + (! grep -E "#[0-9]+ .* main " /tmp/not-symbolized.log) + (! grep -E "#[0-9]+ .* foo " /tmp/not-symbolized.log) + (! grep -E "#[0-9]+ .* bar " /tmp/not-symbolized.log) + (! grep -E "#[0-9]+ .* baz " /tmp/not-symbolized.log) printf '[Coredump]\nEnterNamespace=yes' >/run/systemd/coredump.conf.d/99-enter-namespace.conf - unshare --pid --fork --mount-proc --mount --uts --ipc --net bash -c "$MAKE_STACKTRACE_DUMP" || : - timeout 30 bash -c "until coredumpctl -1 info $CORE_STACKTRACE_TEST_BIN | grep -zqE 'baz.*bar.*foo'; do sleep .2; done" + unshare --pid --fork --mount-proc --mount --uts --ipc --net "$MAKE_STACKTRACE_DUMP" "test-stacktrace-symbolized" + timeout 30 bash -c "until coredumpctl list -q --no-legend /tmp/test-stacktrace-symbolized; do sleep .2; done" + coredumpctl info /tmp/test-stacktrace-symbolized | tee /tmp/symbolized.log + grep -E "#[0-9]+ .* main " /tmp/symbolized.log + grep -E "#[0-9]+ .* foo " /tmp/symbolized.log + grep -E "#[0-9]+ .* bar " /tmp/symbolized.log + grep -E "#[0-9]+ .* baz " /tmp/symbolized.log + + test -d /usr/lib/debug/ && umount /usr/lib/debug/ + rm -f "$MAKE_STACKTRACE_DUMP" /run/systemd/coredump.conf.d/99-enter-namespace.conf /tmp/{not-,}symbolized.log else echo "libdw doesn't not support setting sysroot, skipping EnterNamespace= test" fi -- 2.47.3