diff --git a/man/journald.conf.xml b/man/journald.conf.xml index 902bb9964c..5eb4aa82cf 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -257,7 +257,7 @@ and use the smaller of the two values. 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 SystemKeepFree= or RuntimeKeepFree= are violated when diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 4ec966abb6..d11f328918 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -93,8 +93,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 @@ -105,7 +109,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, @@ -1283,14 +1287,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]; diff --git a/src/home/homework-mount.c b/src/home/homework-mount.c index cf42a0b94d..de71b7f0ea 100644 --- a/src/home/homework-mount.c +++ b/src/home/homework-mount.c @@ -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) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 12d56413db..fd89b7761f 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -3836,7 +3836,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): diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh index 34cb941f93..8b91e188cc 100755 --- a/test/units/testsuite-73.sh +++ b/test/units/testsuite-73.sh @@ -238,6 +238,10 @@ test_vc_keymap() { for i in $(localectl list-keymaps); do # 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) diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh new file mode 100755 index 0000000000..6a89cbf208 --- /dev/null +++ b/test/units/testsuite-74.coredump.sh @@ -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/$(/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='"')