2023-03-21 23:19:41 +01:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# Make sure the binary name fits into 15 characters
CORE_TEST_BIN = "/tmp/test-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 "
}
trap at_exit EXIT
if systemd-detect-virt -cq; then
echo "Running in a container, skipping the systemd-coredump test..."
exit 0
fi
2023-05-24 10:31:41 +09:00
# To make all coredump entries stored in system.journal.
journalctl --rotate
2023-03-21 23:19:41 +01:00
# Check that we're the ones to receive coredumps
sysctl kernel.core_pattern | grep systemd-coredump
# Prepare "fake" binaries for coredumps, so we can properly exercise
# the matching stuff too
cp -vf /bin/sleep " ${ CORE_TEST_BIN : ? } "
cp -vf /bin/sleep " ${ CORE_TEST_UNPRIV_BIN : ? } "
# Simple script that spawns given "fake" binary and then kills it with
# given signal
cat >" ${ MAKE_DUMP_SCRIPT : ? } " <<\E OF
#!/bin/bash -ex
bin = " ${ 1 : ? } "
sig = " ${ 2 : ? } "
ulimit -c unlimited
" $bin " infinity &
pid = $!
2023-06-02 13:24:32 +02:00
# Sync with the "fake" binary, so we kill it once it's fully forked off,
# otherwise we might kill it during fork and kernel would then report
# "wrong" binary name (i.e. $MAKE_DUMP_SCRIPT instead of $CORE_TEST_BIN).
# In this case, wait until the "fake" binary (sleep in this case) enters
# the "interruptible sleep" state, at which point it should be ready
# to be sacrificed.
for _ in { 0..9} ; do
read -ra self_stat <" /proc/ $pid /stat "
[ [ " ${ self_stat [2] } " = = S ] ] && break
sleep .5
done
2023-03-21 23:19:41 +01:00
kill -s " $sig " " $pid "
# This should always fail
! wait " $pid "
EOF
chmod +x " $MAKE_DUMP_SCRIPT "
# Privileged stuff
[ [ " $( id -u) " -eq 0 ] ]
# Trigger a couple of coredumps
" $MAKE_DUMP_SCRIPT " " $CORE_TEST_BIN " "SIGTRAP"
" $MAKE_DUMP_SCRIPT " " $CORE_TEST_BIN " "SIGABRT"
# In the tests we store the coredumps in journals, so let's generate a couple
# with Storage=external as well
mkdir -p /run/systemd/coredump.conf.d/
printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.conf
" $MAKE_DUMP_SCRIPT " " $CORE_TEST_BIN " "SIGTRAP"
" $MAKE_DUMP_SCRIPT " " $CORE_TEST_BIN " "SIGABRT"
rm -fv /run/systemd/coredump.conf.d/99-external.conf
# Wait a bit for the coredumps to get processed
2023-03-25 12:02:15 +01:00
timeout 30 bash -c " while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done "
2023-03-21 23:19:41 +01:00
2023-09-19 17:09:58 -04:00
# Make sure we can forward crashes back to containers
CONTAINER = "testsuite-74-container"
mkdir -p " /var/lib/machines/ $CONTAINER "
mkdir -p " /run/systemd/system/systemd-nspawn@ $CONTAINER .service.d "
# Bind-mounting /etc into the container kinda defeats the purpose of --volatile=,
# but we need the ASan-related overrides scattered across /etc
cat > " /run/systemd/system/systemd-nspawn@ $CONTAINER .service.d/override.conf " << EOF
[ Service]
ExecStart =
ExecStart = systemd-nspawn --quiet --link-journal= try-guest --keep-unit --machine= %i --boot \
--volatile= yes --directory= / --bind-ro= /etc --inaccessible= /etc/machine-id
EOF
systemctl daemon-reload
machinectl start " $CONTAINER "
timeout 60 bash -xec " until systemd-run -M ' $CONTAINER ' -q --wait --pipe true; do sleep .5; done "
[ [ " $( systemd-run -M " $CONTAINER " -q --wait --pipe coredumpctl list -q --no-legend /usr/bin/sleep | wc -l) " -eq 0 ] ]
machinectl copy-to " $CONTAINER " " $MAKE_DUMP_SCRIPT "
systemd-run -M " $CONTAINER " -q --wait --pipe " $MAKE_DUMP_SCRIPT " "/usr/bin/sleep" "SIGABRT"
systemd-run -M " $CONTAINER " -q --wait --pipe " $MAKE_DUMP_SCRIPT " "/usr/bin/sleep" "SIGTRAP"
# Wait a bit for the coredumps to get processed
timeout 30 bash -c " while [[ \$(systemd-run -M $CONTAINER -q --wait --pipe coredumpctl list -q --no-legend /usr/bin/sleep | wc -l) -lt 2 ]]; do sleep 1; done "
2023-03-21 23:19:41 +01:00
coredumpctl
SYSTEMD_LOG_LEVEL = debug coredumpctl
coredumpctl --help
coredumpctl --version
coredumpctl --no-pager --no-legend
coredumpctl --all
coredumpctl -1
coredumpctl -n 1
coredumpctl --reverse
coredumpctl -F COREDUMP_EXE
coredumpctl --json= short | jq
coredumpctl --json= pretty | jq
coredumpctl --json= off
coredumpctl --root= /
coredumpctl --directory= /var/log/journal
2023-09-19 17:09:58 -04:00
coredumpctl --file= " /var/log/journal/ $( </etc/machine-id) " /*.journal
2023-03-21 23:19:41 +01:00
coredumpctl --since= @0
coredumpctl --since= yesterday --until= tomorrow
# We should have a couple of externally stored coredumps
coredumpctl --field= COREDUMP_FILENAME | tee /tmp/coredumpctl.out
grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out
rm -f /tmp/coredumpctl.out
coredumpctl info
coredumpctl info " $CORE_TEST_BIN "
coredumpctl info /foo /bar/ /baz " $CORE_TEST_BIN "
coredumpctl info " ${ CORE_TEST_BIN ##*/ } "
coredumpctl info foo bar baz " ${ CORE_TEST_BIN ##*/ } "
coredumpctl info COREDUMP_EXE = " $CORE_TEST_BIN "
coredumpctl info COREDUMP_EXE = aaaaa COREDUMP_EXE = COREDUMP_EXE = " $CORE_TEST_BIN "
coredumpctl debug --debugger= /bin/true " $CORE_TEST_BIN "
SYSTEMD_DEBUGGER = /bin/true coredumpctl debug " $CORE_TEST_BIN "
coredumpctl debug --debugger= /bin/true --debugger-arguments= "-this --does --not 'do anything' -a -t --all" " ${ CORE_TEST_BIN ##*/ } "
coredumpctl dump " $CORE_TEST_BIN " >/tmp/core.redirected
test -s /tmp/core.redirected
coredumpctl dump -o /tmp/core.output " ${ CORE_TEST_BIN ##*/ } "
test -s /tmp/core.output
rm -f /tmp/core.{ output,redirected}
# Unprivileged stuff
# Related issue: https://github.com/systemd/systemd/issues/26912
UNPRIV_CMD = ( systemd-run --user --wait --pipe -M "testuser@.host" --)
# Trigger a couple of coredumps as an unprivileged user
" ${ UNPRIV_CMD [@] } " " $MAKE_DUMP_SCRIPT " " $CORE_TEST_UNPRIV_BIN " "SIGTRAP"
" ${ UNPRIV_CMD [@] } " " $MAKE_DUMP_SCRIPT " " $CORE_TEST_UNPRIV_BIN " "SIGABRT"
# In the tests we store the coredumps in journals, so let's generate a couple
# with Storage=external as well
mkdir -p /run/systemd/coredump.conf.d/
printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.conf
" ${ UNPRIV_CMD [@] } " " $MAKE_DUMP_SCRIPT " " $CORE_TEST_UNPRIV_BIN " "SIGTRAP"
" ${ UNPRIV_CMD [@] } " " $MAKE_DUMP_SCRIPT " " $CORE_TEST_UNPRIV_BIN " "SIGABRT"
rm -fv /run/systemd/coredump.conf.d/99-external.conf
# Wait a bit for the coredumps to get processed
2023-03-25 12:02:15 +01:00
timeout 30 bash -c " while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_UNPRIV_BIN | wc -l) -lt 4 ]]; do sleep 1; done "
2023-03-21 23:19:41 +01:00
# root should see coredumps from both binaries
coredumpctl info " $CORE_TEST_UNPRIV_BIN "
coredumpctl info " ${ CORE_TEST_UNPRIV_BIN ##*/ } "
# The test user should see only their own coredumps
" ${ UNPRIV_CMD [@] } " coredumpctl
" ${ UNPRIV_CMD [@] } " coredumpctl info " $CORE_TEST_UNPRIV_BIN "
" ${ UNPRIV_CMD [@] } " coredumpctl info " ${ CORE_TEST_UNPRIV_BIN ##*/ } "
( ! " ${ UNPRIV_CMD [@] } " coredumpctl info --all " $CORE_TEST_BIN " )
( ! " ${ UNPRIV_CMD [@] } " coredumpctl info --all " ${ CORE_TEST_BIN ##*/ } " )
# We should have a couple of externally stored coredumps
" ${ UNPRIV_CMD [@] } " coredumpctl --field= COREDUMP_FILENAME | tee /tmp/coredumpctl.out
grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out
rm -f /tmp/coredumpctl.out
" ${ UNPRIV_CMD [@] } " coredumpctl debug --debugger= /bin/true " $CORE_TEST_UNPRIV_BIN "
" ${ UNPRIV_CMD [@] } " coredumpctl debug --debugger= /bin/true --debugger-arguments= "-this --does --not 'do anything' -a -t --all" " ${ CORE_TEST_UNPRIV_BIN ##*/ } "
" ${ UNPRIV_CMD [@] } " coredumpctl dump " $CORE_TEST_UNPRIV_BIN " >/tmp/core.redirected
test -s /tmp/core.redirected
" ${ UNPRIV_CMD [@] } " coredumpctl dump -o /tmp/core.output " ${ CORE_TEST_UNPRIV_BIN ##*/ } "
test -s /tmp/core.output
rm -f /tmp/core.{ output,redirected}
( ! " ${ UNPRIV_CMD [@] } " coredumpctl dump " $CORE_TEST_BIN " >/dev/null)
# --backtrace mode
# Pass one of the existing journal coredump records to systemd-coredump and
# use our PID as the source to make matching the coredump later easier
# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT HOSTNAME
journalctl -b -n 1 --output= export --output-fields= MESSAGE,COREDUMP COREDUMP_EXE = "/usr/bin/test-dump" |
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509994 12345 mymachine
# Wait a bit for the coredump to get processed
2023-03-25 12:02:15 +01:00
timeout 30 bash -c " while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done "
2023-03-21 23:19:41 +01:00
coredumpctl info " $$ "
coredumpctl info COREDUMP_HOSTNAME = "mymachine"
2023-04-26 14:32:04 +01:00
# This used to cause a stack overflow
systemd-run -t --property CoredumpFilter = all ls /tmp
systemd-run -t --property CoredumpFilter = default ls /tmp
2023-03-21 23:19:41 +01:00
( ! coredumpctl --hello-world)
( ! coredumpctl -n 0)
( ! coredumpctl -n -1)
( ! coredumpctl --file= /dev/null)
( ! coredumpctl --since= 0)
( ! coredumpctl --until= '' )
( ! coredumpctl --since= today --until= yesterday)
( ! coredumpctl --directory= / --root= /)
( ! coredumpctl --json= foo)
( ! coredumpctl -F foo -F bar)
( ! coredumpctl list 0)
( ! coredumpctl list -- -1)
( ! coredumpctl list '' )
( ! coredumpctl info /../.~= )
( ! coredumpctl info '' )
( ! coredumpctl dump --output= /dev/full " $CORE_TEST_BIN " )
( ! coredumpctl dump --output= /dev/null --output= /dev/null " $CORE_TEST_BIN " )
( ! coredumpctl debug --debugger= /bin/false)
( ! coredumpctl debug --debugger= /bin/true --debugger-arguments= '"' )