Skip to content
Merged
2 changes: 1 addition & 1 deletion man/journald.conf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
and use the smaller of the two values.</para>

<para>The first pair defaults to 10% and the second to 15% of
the size of the respective file system, but each value is
the size of the respective file system, but each of the calculated default values is
capped to 4G. If the file system is nearly full and either
<varname>SystemKeepFree=</varname> or
<varname>RuntimeKeepFree=</varname> are violated when
Expand Down
21 changes: 14 additions & 7 deletions src/coredump/coredump.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,12 @@ enum {
META_ARGV_SIGNAL, /* %s: number of signal causing dump */
META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch (we expand this to µs granularity) */
META_ARGV_RLIMIT, /* %c: core file size soft resource limit */
META_ARGV_HOSTNAME, /* %h: hostname */
_META_ARGV_REQUIRED,
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
_META_ARGV_MAX,
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */

/* The following indexes are cached for a couple of special fields we use (and
* thereby need to be retrieved quickly) for naming coredump files, and attaching
Expand All @@ -104,7 +108,7 @@ enum {
_META_MANDATORY_MAX,

/* The rest are similar to the previous ones except that we won't fail if one of
* them is missing. */
* them is missing in a message sent over the socket. */

META_EXE = _META_MANDATORY_MAX,
META_UNIT,
Expand Down Expand Up @@ -1282,14 +1286,17 @@ static int gather_pid_metadata_from_argv(
char *t;

/* We gather all metadata that were passed via argv[] into an array of iovecs that
* we'll forward to the socket unit */
* we'll forward to the socket unit.
*
* We require at least _META_ARGV_REQUIRED args, but will accept more.
* We know how to parse _META_ARGV_MAX args. The rest will be ignored. */

if (argc < _META_ARGV_MAX)
if (argc < _META_ARGV_REQUIRED)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not enough arguments passed by the kernel (%i, expected %i).",
argc, _META_ARGV_MAX);
"Not enough arguments passed by the kernel (%i, expected between %i and %i).",
argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);

for (int i = 0; i < _META_ARGV_MAX; i++) {
for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {

t = argv[i];

Expand Down
4 changes: 3 additions & 1 deletion src/home/homework-mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ int home_move_mount(const char *mount_suffix, const char *target) {
} else
d = HOME_RUNTIME_WORK_DIR;

(void) mkdir_p(target, 0700);
r = mkdir_p(target, 0700);
if (r < 0)
return log_error_errno(r, "Failed to create directory '%s': %m", target);

r = mount_nofollow_verbose(LOG_ERR, d, target, NULL, MS_BIND, NULL);
if (r < 0)
Expand Down
2 changes: 1 addition & 1 deletion test/test-network/systemd-networkd-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3772,7 +3772,7 @@ def test_qdisc_tbf(self):
output = check_output('tc qdisc show dev dummy98')
print(output)
self.assertRegex(output, 'qdisc tbf 35: root')
self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst (987500b|999200b) lat 70(.0)?ms')

@expectedFailureIfModuleIsNotAvailable('sch_teql')
def test_qdisc_teql(self):
Expand Down
4 changes: 4 additions & 0 deletions test/units/testsuite-73.sh
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ test_vc_keymap() {
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard

# set VC keymap

# Skip lv keymap and friends, otherwise the sanitizer detects heap-buffer-overflow in libxkbcommon.
[[ "$i" =~ ^lv ]] && continue

assert_rc 0 localectl set-keymap "$i"
output=$(localectl)

Expand Down
195 changes: 195 additions & 0 deletions test/units/testsuite-74.coredump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#!/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

# To make all coredump entries stored in system.journal.
journalctl --rotate

# 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:?}" <<\EOF
#!/bin/bash -ex

bin="${1:?}"
sig="${2:?}"

ulimit -c unlimited
"$bin" infinity &
pid=$!
# 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
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
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"

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
coredumpctl --file="/var/log/journal/$(</etc/machine-id)/system.journal"
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
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_UNPRIV_BIN | wc -l) -lt 4 ]]; do sleep 1; done"

# 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.
# Use our PID as the source to be able to create a PIDFD and to make matching 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 1679509900 12345
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 1679509901 12345 mymachine
# Wait a bit for the coredumps to get processed
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
coredumpctl info $$
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
coredumpctl info COREDUMP_HOSTNAME="mymachine"

# This used to cause a stack overflow
systemd-run -t --property CoredumpFilter=all ls /tmp
systemd-run -t --property CoredumpFilter=default ls /tmp

(! 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='"')
Loading