Compare commits

..

No commits in common. "imports/c8s/systemd-239-62.el8" and "c8" have entirely different histories.

224 changed files with 22897 additions and 17 deletions

View File

@ -0,0 +1,24 @@
From 3a35fcaad4bb3831808280854eb84f68975279a1 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 19 Jul 2022 22:44:07 +0200
Subject: [PATCH] ci: bump the worker Ubuntu version to Jammy
rhel-only
Related: #2087152
---
.github/workflows/unit_tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 87b162fa71..f397e8ed6e 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -6,7 +6,7 @@ on: [pull_request]
jobs:
build:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:

View File

@ -0,0 +1,43 @@
From 434b4b64d17e16ed23f90c99c26dbd0e4ce6cd88 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 24 Nov 2021 15:58:50 +0100
Subject: [PATCH] test: make test-execute pass on Linux 5.15
Linux 5.15 broke kernel API:
https://github.com/torvalds/linux/commit/e70344c05995a190a56bbd1a23dc2218bcc8c924
Previously setting IOPRIO_CLASS_NONE for a process would then report
IOPRIO_CLASS_NONE back. But since 5.15 it reports IOPRIO_CLASS_BE
instead. Since IOPRIO_CLASS_NONE is an alias for a special setting of
IOPRIO_CLASS_BE this makes some sense, but it's also a kernel API
breakage that our testsuite trips up on.
(I made some minimal effort to inform the kernel people about this API
breakage during the 5.15 rc phase, but noone was interested.)
Either way let's hadle this gracefully in our test suite and accept
"best-effort" too when "none" was set.
(This is only triggable if the tests are run on 5.15 with full privs)
(cherry picked from commit d9b8771108cf2955efc3852b477391017d2c599a)
Related: #2087152
---
test/test-execute/exec-ioschedulingclass-none.service | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service
index b6af122a1e..8f917d345d 100644
--- a/test/test-execute/exec-ioschedulingclass-none.service
+++ b/test/test-execute/exec-ioschedulingclass-none.service
@@ -2,6 +2,7 @@
Description=Test for IOSchedulingClass=none
[Service]
-ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"'
+# Old kernels might report "none" here, new kernels "best-effort".
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none" -o "$${c%%:*}" = "best-effort"'
Type=oneshot
IOSchedulingClass=none

View File

@ -0,0 +1,25 @@
From 128d784dacb456f9ea675911e88d4b47925bda0d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 20 Jul 2022 10:24:36 +0200
Subject: [PATCH] ci: install iputils
Required by test-bpf.
rhel-only
Related: #2087152
---
.github/workflows/unit_tests.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
index c1311310fb..3859433720 100755
--- a/.github/workflows/unit_tests.sh
+++ b/.github/workflows/unit_tests.sh
@@ -11,6 +11,7 @@ ADDITIONAL_DEPS=(
dnsmasq
e2fsprogs
hostname
+ iputils
libasan
libubsan
nc

View File

@ -0,0 +1,63 @@
From 0feaf0be515c02a10ca12f726b4a8424262cf09c Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 19 Jul 2022 12:43:43 +0200
Subject: [PATCH] ci(Mergify): Add `ci-waived` logic
RHEL-only
Related: #2087152
---
.mergify.yml | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/.mergify.yml b/.mergify.yml
index 6fa400effd..3afd04f18e 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -4,6 +4,7 @@
pull_request_rules:
- name: Add `needs-ci` label on CI fail
conditions:
+ - label!=ci-waived
- or:
# Unit tests
- -check-success=build (stream8, GCC)
@@ -27,21 +28,24 @@ pull_request_rules:
- name: Remove `needs-ci` label on CI success
conditions:
- # Unit tests
- - check-success=build (stream8, GCC)
- - check-success=build (stream8, GCC_ASAN)
- # CentOS Stream CI
- - check-success=CentOS CI (CentOS Stream 8)
- # LGTM
- or:
- - "check-success=LGTM analysis: JavaScript"
- - "check-neutral=LGTM analysis: JavaScript"
- - or:
- - "check-success=LGTM analysis: Python"
- - "check-neutral=LGTM analysis: Python"
- - or:
- - "check-success=LGTM analysis: C/C++"
- - "check-neutral=LGTM analysis: C/C++"
+ - label=ci-waived
+ - and:
+ # Unit tests
+ - check-success=build (stream8, GCC)
+ - check-success=build (stream8, GCC_ASAN)
+ # CentOS Stream CI
+ - check-success=CentOS CI (CentOS Stream 8)
+ # LGTM
+ - or:
+ - "check-success=LGTM analysis: JavaScript"
+ - "check-neutral=LGTM analysis: JavaScript"
+ - or:
+ - "check-success=LGTM analysis: Python"
+ - "check-neutral=LGTM analysis: Python"
+ - or:
+ - "check-success=LGTM analysis: C/C++"
+ - "check-neutral=LGTM analysis: C/C++"
actions:
label:
remove:

View File

@ -0,0 +1,33 @@
From e48586dcfa66731a353ecc832e43fab75559e2cf Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 30 Oct 2019 16:37:42 +0100
Subject: [PATCH] sd-event: don't invalidate source type on disconnect
This fixes fd closing if fd ownership is requested.
(cherry picked from commit f59825595182d70b9ead238d1e885d0db99cc201)
Resolves: #2115396
---
src/libsystemd/sd-event/sd-event.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 0adfdd9e1a..09d4584bf9 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -1104,11 +1104,13 @@ static void source_disconnect(sd_event_source *s) {
event = s->event;
- s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID;
s->event = NULL;
LIST_REMOVE(sources, event->sources, s);
event->n_sources--;
+ /* Note that we don't invalidate the type here, since we still need it in order to close the fd or
+ * pidfd associated with this event source, which we'll do only on source_free(). */
+
if (!s->floating)
sd_event_unref(event);
}

View File

@ -0,0 +1,98 @@
From e6cd875a767ba23b218cdca395307ac6fb7fd882 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 30 May 2022 14:50:05 +0200
Subject: [PATCH] tests: make sure we delay running mount start jobs when
/p/s/mountinfo is rate limited
(cherry picked from commit 9e15be6c8d55abd800bf33f9776dd0e307ed37bc)
Related: #2095744
---
test/TEST-60-MOUNT-RATELIMIT/testsuite.sh | 53 +++++++++++++++++++++++
test/test-functions | 2 +-
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh b/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh
index 6211050faf..84fe9640e1 100755
--- a/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh
+++ b/test/TEST-60-MOUNT-RATELIMIT/testsuite.sh
@@ -2,6 +2,56 @@
set -eux
set -o pipefail
+test_issue_20329() {
+ local tmpdir unit
+ tmpdir="$(mktemp -d)"
+ unit=$(systemd-escape --suffix mount --path "$tmpdir")
+
+ # Set up test mount unit
+ cat > /run/systemd/system/"$unit" <<EOF
+[Mount]
+What=tmpfs
+Where=$tmpdir
+Type=tmpfs
+Options=defaults,nofail
+EOF
+
+ # Start the unit
+ systemctl daemon-reload
+ systemctl start "$unit"
+
+ [[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || {
+ echo >&2 "Test mount \"$unit\" unit isn't mounted"
+ return 1
+ }
+ mountpoint -q "$tmpdir"
+
+ trap 'systemctl stop $unit' RETURN
+
+ # Trigger the mount ratelimiting
+ cd "$(mktemp -d)"
+ mkdir foo
+ for ((i=0;i<50;++i)); do
+ mount --bind foo foo
+ umount foo
+ done
+
+ # Unmount the test mount and start it immediately again via systemd
+ umount "$tmpdir"
+ systemctl start "$unit"
+
+ # Make sure it is seen as mounted by systemd and it actually is mounted
+ [[ "$(systemctl show --property SubState --value "$unit")" = "mounted" ]] || {
+ echo >&2 "Test mount \"$unit\" unit isn't in \"mounted\" state"
+ return 1
+ }
+
+ mountpoint -q "$tmpdir" || {
+ echo >&2 "Test mount \"$unit\" is in \"mounted\" state, actually is not mounted"
+ return 1
+ }
+}
+
systemd-analyze log-level debug
systemd-analyze log-target journal
@@ -85,6 +135,9 @@ if systemctl list-units -t mount tmp-meow* | grep -q tmp-meow; then
exit 42
fi
+# test that handling of mount start jobs is delayed when /proc/self/mouninfo monitor is rate limited
+test_issue_20329
+
systemd-analyze log-level info
echo OK >/testok
diff --git a/test/test-functions b/test/test-functions
index 4d7832b1fb..ed8ab98173 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -23,7 +23,7 @@ fi
PATH_TO_INIT=$ROOTLIBDIR/systemd
-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"

View File

@ -0,0 +1,29 @@
From 0bf1df5c35c310c3efe49c7a3cb8c3be3e33492b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:05:37 +0100
Subject: [PATCH] core: drop references to 'StandardOutputFileToCreate'
This property never existed, let's drop any reference to it.
(cherry picked from commit 922ce049d1ed37ce77e3322711e29f256d9e5959)
Related: #2093479
---
src/core/dbus-execute.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 2e64f0baf4..05134851c5 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1809,8 +1809,8 @@ int bus_exec_context_set_transient_property(
} else if (STR_IN_SET(name,
"StandardInputFile",
- "StandardOutputFile", "StandardOutputFileToCreate", "StandardOutputFileToAppend",
- "StandardErrorFile", "StandardErrorFileToCreate", "StandardErrorFileToAppend")) {
+ "StandardOutputFile", "StandardOutputFileToAppend",
+ "StandardErrorFile", "StandardErrorFileToAppend")) {
const char *s;
r = sd_bus_message_read(message, "s", &s);

View File

@ -0,0 +1,29 @@
From 2ba82e6b7e9a7b138c985561dd7d26b9e4111fbe Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:06:19 +0100
Subject: [PATCH] dbus-execute: fix indentation
(cherry picked from commit dbe6c4b657aa5c58bfc049d869b94f00b41b7d95)
Related: #2093479
---
src/core/dbus-execute.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 05134851c5..fc433cc96f 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1858,9 +1858,9 @@ int bus_exec_context_set_transient_property(
c->std_error = EXEC_OUTPUT_FILE;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
} else {
- assert(streq(name, "StandardErrorFileToAppend"));
- c->std_error = EXEC_OUTPUT_FILE_APPEND;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
+ assert(streq(name, "StandardErrorFileToAppend"));
+ c->std_error = EXEC_OUTPUT_FILE_APPEND;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
}
}
}

View File

@ -0,0 +1,30 @@
From 4fbd505c5a15f2b6078dc43e5a1ff999993e8b23 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:07:06 +0100
Subject: [PATCH] dbus-execute: generate the correct transient unit setting
(cherry picked from commit 1704fba92f7b2c92238b0833943669045374daf9)
Related: #2093479
---
src/core/dbus-execute.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index fc433cc96f..00f4aeacef 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1856,11 +1856,11 @@ int bus_exec_context_set_transient_property(
if (streq(name, "StandardErrorFile")) {
c->std_error = EXEC_OUTPUT_FILE;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
} else {
assert(streq(name, "StandardErrorFileToAppend"));
c->std_error = EXEC_OUTPUT_FILE_APPEND;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s);
}
}
}

View File

@ -0,0 +1,33 @@
From b06347d1e85c98507ba386b24e6c7159edf4784f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:07:39 +0100
Subject: [PATCH] =?UTF-8?q?bus-unit-util:=20properly=20accept=20StandardOu?=
=?UTF-8?q?tput=3Dappend:=E2=80=A6=20settings?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit 8d33232ef1ad051b5ed00bd7b5fffb5a19bb83ae)
Resolves: #2093479
---
src/shared/bus-unit-util.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 9010448aaf..3910dfa812 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -894,9 +894,11 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
} else if ((n = startswith(eq, "file:"))) {
appended = strjoina(field, "File");
r = sd_bus_message_append(m, "(sv)", appended, "s", n);
+ } else if ((n = startswith(eq, "append:"))) {
+ appended = strjoina(field, "FileToAppend");
+ r = sd_bus_message_append(m, "(sv)", appended, "s", n);
} else
r = sd_bus_message_append(m, "(sv)", field, "s", eq);
-
if (r < 0)
return bus_log_create_error(r);

View File

@ -0,0 +1,68 @@
From d6ffd324cc933efec946a3ffbed6fccfe7077203 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:07:48 +0100
Subject: [PATCH] core: be more careful when inheriting stdout fds to stderr
We need to compare the fd name/file name if we inherit an fd from stdout
to stderr. Let's do that.
Fixes: #10875
(cherry picked from commit 41fc585a7a3b8ae857cad5fdad1bc70cdacfa8e5)
Related: #2093479
---
src/core/execute.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/core/execute.c b/src/core/execute.c
index 9cbb678ac4..b1d8dceb32 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -545,6 +545,30 @@ static int setup_input(
}
}
+static bool can_inherit_stderr_from_stdout(
+ const ExecContext *context,
+ ExecOutput o,
+ ExecOutput e) {
+
+ assert(context);
+
+ /* Returns true, if given the specified STDERR and STDOUT output we can directly dup() the stdout fd to the
+ * stderr fd */
+
+ if (e == EXEC_OUTPUT_INHERIT)
+ return true;
+ if (e != o)
+ return false;
+
+ if (e == EXEC_OUTPUT_NAMED_FD)
+ return streq_ptr(context->stdio_fdname[STDOUT_FILENO], context->stdio_fdname[STDERR_FILENO]);
+
+ if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND))
+ return streq_ptr(context->stdio_file[STDOUT_FILENO], context->stdio_file[STDERR_FILENO]);
+
+ return true;
+}
+
static int setup_output(
const Unit *unit,
const ExecContext *context,
@@ -603,7 +627,7 @@ static int setup_output(
return fileno;
/* Duplicate from stdout if possible */
- if ((e == o && e != EXEC_OUTPUT_NAMED_FD) || e == EXEC_OUTPUT_INHERIT)
+ if (can_inherit_stderr_from_stdout(context, o, e))
return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
o = e;
@@ -694,7 +718,6 @@ static int setup_output(
flags |= O_APPEND;
fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask);
-
if (fd < 0)
return fd;

View File

@ -0,0 +1,136 @@
From 2bbaa4b647c8a60a6c6a591f71313b0667447246 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 26 Nov 2018 21:09:07 +0100
Subject: [PATCH] =?UTF-8?q?test:=20add=20a=20test=20for=20StandardError=3D?=
=?UTF-8?q?file:=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This deserves a test of its, given how broken on so many levels this
previously was.
(cherry picked from commit 196b0a11f306b8041e35316feb05ed1f00380957)
Related: #2093479
---
test/TEST-27-STDOUTFILE/Makefile | 1 +
test/TEST-27-STDOUTFILE/test.sh | 52 ++++++++++++++++++++++++++++
test/TEST-27-STDOUTFILE/testsuite.sh | 40 +++++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 120000 test/TEST-27-STDOUTFILE/Makefile
create mode 100755 test/TEST-27-STDOUTFILE/test.sh
create mode 100755 test/TEST-27-STDOUTFILE/testsuite.sh
diff --git a/test/TEST-27-STDOUTFILE/Makefile b/test/TEST-27-STDOUTFILE/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-27-STDOUTFILE/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-27-STDOUTFILE/test.sh b/test/TEST-27-STDOUTFILE/test.sh
new file mode 100755
index 0000000000..724dbef231
--- /dev/null
+++ b/test/TEST-27-STDOUTFILE/test.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="test StandardOutput=file:"
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ inst_binary cmp
+
+ setup_basic_environment
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-27-STDOUTFILE/testsuite.sh b/test/TEST-27-STDOUTFILE/testsuite.sh
new file mode 100755
index 0000000000..75559e03e5
--- /dev/null
+++ b/test/TEST-27-STDOUTFILE/testsuite.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+systemd-analyze set-log-level debug
+systemd-analyze set-log-target console
+
+systemd-run --unit=one -p StandardOutput=file:/tmp/stdout -p StandardError=file:/tmp/stderr -p Type=exec sh -c 'echo x ; echo y >&2'
+cmp /tmp/stdout <<EOF
+x
+EOF
+cmp /tmp/stderr <<EOF
+y
+EOF
+
+systemd-run --unit=two -p StandardOutput=file:/tmp/stdout -p StandardError=file:/tmp/stderr -p Type=exec sh -c 'echo z ; echo a >&2'
+cmp /tmp/stdout <<EOF
+z
+EOF
+cmp /tmp/stderr <<EOF
+a
+EOF
+
+systemd-run --unit=three -p StandardOutput=append:/tmp/stdout -p StandardError=append:/tmp/stderr -p Type=exec sh -c 'echo b ; echo c >&2'
+cmp /tmp/stdout <<EOF
+z
+b
+EOF
+cmp /tmp/stderr <<EOF
+a
+c
+EOF
+
+systemd-analyze set-log-level info
+
+echo OK > /testok
+
+exit 0

View File

@ -0,0 +1,260 @@
From aa93c2acd6c9ed4eb0152be9002f59ecd9cc277e Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 24 Jun 2022 09:13:42 +0200
Subject: [PATCH] =?UTF-8?q?tree-wide:=20allow=20ASCII=20fallback=20for=20?=
=?UTF-8?q?=E2=86=92=20in=20logs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit e2341b6bc325932b3f9f10874956952cbdbd6361)
Resolves: #2093479
---
src/basic/mount-util.c | 5 +++--
src/core/dbus.c | 4 +++-
src/core/namespace.c | 7 +++++--
src/core/socket.c | 4 +++-
src/libsystemd/sd-bus/sd-bus.c | 4 +++-
src/login/logind-acl.c | 5 +++--
src/resolve/resolved-dns-query.c | 11 +++++++++--
src/shared/dns-domain.c | 9 ++++++---
src/tmpfiles/tmpfiles.c | 4 +++-
9 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 0c709001be..e7f9e514c2 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -18,6 +18,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
+#include "locale-util.h"
#include "mount-util.h"
#include "parse-util.h"
#include "path-util.h"
@@ -844,8 +845,8 @@ int mount_verbose(
log_debug("Bind-mounting %s on %s (%s \"%s\")...",
what, where, strnull(fl), strempty(o));
else if (f & MS_MOVE)
- log_debug("Moving mount %s → %s (%s \"%s\")...",
- what, where, strnull(fl), strempty(o));
+ log_debug("Moving mount %s %s %s (%s \"%s\")...",
+ what, special_glyph(ARROW), where, strnull(fl), strempty(o));
else
log_debug("Mounting %s on %s (%s \"%s\")...",
strna(type), where, strnull(fl), strempty(o));
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 584a8a1b01..66d838cdb4 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -31,6 +31,7 @@
#include "dbus.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "locale-util.h"
#include "log.h"
#include "missing.h"
#include "mkdir.h"
@@ -751,7 +752,8 @@ static int manager_dispatch_sync_bus_names(sd_event_source *es, void *userdata)
assert(s);
if (!streq_ptr(s->bus_name, name)) {
- log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
+ log_unit_warning(u, "Bus name has changed from %s %s %s, ignoring.",
+ s->bus_name, special_glyph(ARROW), name);
continue;
}
diff --git a/src/core/namespace.c b/src/core/namespace.c
index e4930db15c..3566795d46 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -15,6 +15,7 @@
#include "fd-util.h"
#include "fs-util.h"
#include "label.h"
+#include "locale-util.h"
#include "loop-util.h"
#include "loopback-setup.h"
#include "missing.h"
@@ -841,7 +842,8 @@ static int follow_symlink(
return -ELOOP;
}
- log_debug("Followed mount entry path symlink %s → %s.", mount_entry_path(m), target);
+ log_debug("Followed mount entry path symlink %s %s %s.",
+ mount_entry_path(m), special_glyph(ARROW), target);
free_and_replace(m->path_malloc, target);
m->has_prefix = true;
@@ -920,7 +922,8 @@ static int apply_mount(
if (r < 0)
return log_debug_errno(r, "Failed to follow symlinks on %s: %m", mount_entry_source(m));
- log_debug("Followed source symlinks %s → %s.", mount_entry_source(m), chased);
+ log_debug("Followed source symlinks %s %s %s.",
+ mount_entry_source(m), special_glyph(ARROW), chased);
free_and_replace(m->source_malloc, chased);
diff --git a/src/core/socket.c b/src/core/socket.c
index 6f9a0f7575..bdfeb43a70 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -25,6 +25,7 @@
#include "in-addr-util.h"
#include "io-util.h"
#include "label.h"
+#include "locale-util.h"
#include "log.h"
#include "missing.h"
#include "mkdir.h"
@@ -1355,7 +1356,8 @@ static int socket_symlink(Socket *s) {
}
if (r < 0)
- log_unit_warning_errno(UNIT(s), r, "Failed to create symlink %s → %s, ignoring: %m", p, *i);
+ log_unit_warning_errno(UNIT(s), r, "Failed to create symlink %s %s %s, ignoring: %m",
+ p, special_glyph(ARROW), *i);
}
return 0;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 803f3f50d6..21e54591f7 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -31,6 +31,7 @@
#include "cgroup-util.h"
#include "def.h"
#include "fd-util.h"
+#include "locale-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "macro.h"
@@ -518,7 +519,8 @@ void bus_set_state(sd_bus *bus, enum bus_state state) {
if (state == bus->state)
return;
- log_debug("Bus %s: changing state %s → %s", strna(bus->description), table[bus->state], table[state]);
+ log_debug("Bus %s: changing state %s %s %s", strna(bus->description),
+ table[bus->state], special_glyph(ARROW), table[state]);
bus->state = state;
}
diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c
index cafeb8822f..fe17eac0e6 100644
--- a/src/login/logind-acl.c
+++ b/src/login/logind-acl.c
@@ -9,6 +9,7 @@
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
+#include "locale-util.h"
#include "logind-acl.h"
#include "set.h"
#include "string-util.h"
@@ -260,8 +261,8 @@ int devnode_acl_all(struct udev *udev,
SET_FOREACH(n, nodes, i) {
int k;
- log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT"→"UID_FMT"%s%s)",
- n, seat, old_uid, new_uid,
+ log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT"%s"UID_FMT"%s%s)",
+ n, seat, old_uid, special_glyph(ARROW), new_uid,
del ? " del" : "", add ? " add" : "");
k = devnode_acl(n, flush, del, old_uid, add, new_uid);
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index c921fe841f..573e27d662 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -3,6 +3,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
#include "dns-type.h"
+#include "locale-util.h"
#include "hostname-util.h"
#include "local-addresses.h"
#include "resolved-dns-query.h"
@@ -942,7 +943,10 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
if (r < 0)
return r;
else if (r > 0)
- log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
+ log_debug("Following CNAME/DNAME %s %s %s.",
+ dns_question_first_name(q->question_idna),
+ special_glyph(ARROW),
+ dns_question_first_name(nq_idna));
k = dns_question_is_equal(q->question_idna, q->question_utf8);
if (k < 0)
@@ -956,7 +960,10 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
if (k < 0)
return k;
else if (k > 0)
- log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
+ log_debug("Following UTF8 CNAME/DNAME %s %s %s.",
+ dns_question_first_name(q->question_utf8),
+ special_glyph(ARROW),
+ dns_question_first_name(nq_utf8));
}
if (r == 0 && k == 0) /* No actual cname happened? */
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index de2fcca8b2..59799dec56 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -17,6 +17,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
+#include "locale-util.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "in-addr-util.h"
@@ -1260,7 +1261,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
- log_debug("idn2_lookup_u8: %s → %s", name, t);
+ log_debug("idn2_lookup_u8: %s %s %s", name, special_glyph(ARROW), t);
if (r == IDN2_OK) {
if (!startswith(name, "xn--")) {
_cleanup_free_ char *s = NULL;
@@ -1273,8 +1274,10 @@ int dns_name_apply_idna(const char *name, char **ret) {
}
if (!streq_ptr(name, s)) {
- log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
- name, t, s);
+ log_debug("idn2 roundtrip failed: \"%s\" %s \"%s\" %s \"%s\", ignoring.",
+ name, special_glyph(ARROW), t,
+ special_glyph(ARROW), s);
+ *ret = NULL;
return 0;
}
}
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 50fada99dd..b3c2aac746 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -36,6 +36,7 @@
#include "fs-util.h"
#include "glob-util.h"
#include "io-util.h"
+#include "locale-util.h"
#include "label.h"
#include "log.h"
#include "macro.h"
@@ -2143,7 +2144,8 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
* there's no immediate need for action by the user. However, in the interest of making things less confusing
* to the user, let's still inform the user that these snippets should really be updated. */
- log_notice("[%s:%u] Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.", fname, line, *path, n);
+ log_notice("[%s:%u] Line references path below legacy directory /var/run/, updating %s %s %s; please update the tmpfiles.d/ drop-in file accordingly.",
+ fname, line, *path, special_glyph(ARROW), n);
free(*path);
*path = n;

View File

@ -0,0 +1,129 @@
From f27568d24a29590b34fec3a96a5b3b5d290ba3d8 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 24 Jun 2022 09:59:44 +0200
Subject: [PATCH] =?UTF-8?q?tree-wide:=20allow=20ASCII=20fallback=20for=20?=
=?UTF-8?q?=E2=80=A6=20in=20logs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit 28e5e1e97f47067bce190ea6b3404907d63e4320)
Related: #2093479
---
src/core/manager.c | 5 +++--
src/shared/vlan-util.c | 3 ++-
src/sysusers/sysusers.c | 5 +++--
src/tmpfiles/tmpfiles.c | 6 +++---
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index 845c26f498..5873e5b6d7 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -49,6 +49,7 @@
#include "io-util.h"
#include "label.h"
#include "locale-setup.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
@@ -1404,7 +1405,7 @@ static void manager_coldplug(Manager *m) {
assert(m);
- log_debug("Invoking unit coldplug() handlers…");
+ log_debug("Invoking unit coldplug() handlers%s", special_glyph(ELLIPSIS));
/* Let's place the units back into their deserialized state */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
@@ -1426,7 +1427,7 @@ static void manager_catchup(Manager *m) {
assert(m);
- log_debug("Invoking unit catchup() handlers…");
+ log_debug("Invoking unit catchup() handlers%s", special_glyph(ELLIPSIS));
/* Let's catch up on any state changes that happened while we were reloading/reexecing */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
diff --git a/src/shared/vlan-util.c b/src/shared/vlan-util.c
index 400994a354..9301dacbe2 100644
--- a/src/shared/vlan-util.c
+++ b/src/shared/vlan-util.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "conf-parser.h"
+#include "locale-util.h"
#include "parse-util.h"
#include "string-util.h"
#include "vlan-util.h"
@@ -67,7 +68,7 @@ int config_parse_vlanid(
r = parse_vlanid(rvalue, id);
if (r == -ERANGE) {
- log_syntax(unit, LOG_ERR, filename, line, r, "VLAN identifier outside of valid range 0…4094, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "VLAN identifier outside of valid range 0%s4094, ignoring: %s", special_glyph(ELLIPSIS), rvalue);
return 0;
}
if (r < 0) {
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index a374ebaaf4..f547388151 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -12,6 +12,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "hashmap.h"
+#include "locale-util.h"
#include "pager.h"
#include "path-util.h"
#include "selinux-util.h"
@@ -1890,13 +1891,13 @@ static int read_config_files(char **args) {
STRV_FOREACH(f, files)
if (p && path_equal(*f, p)) {
- log_debug("Parsing arguments at position \"%s\"…", *f);
+ log_debug("Parsing arguments at position \"%s\"%s", *f, special_glyph(ELLIPSIS));
r = parse_arguments(args);
if (r < 0)
return r;
} else {
- log_debug("Reading config file \"%s\"…", *f);
+ log_debug("Reading config file \"%s\"%s", *f, special_glyph(ELLIPSIS));
/* Just warn, ignore result otherwise */
(void) read_config_file(*f, true);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index b3c2aac746..8da525120b 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -2654,7 +2654,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
assert(fn);
if (streq(fn, "-")) {
- log_debug("Reading config from stdin…");
+ log_debug("Reading config from stdin%s", special_glyph(ELLIPSIS));
fn = "<stdin>";
f = stdin;
} else {
@@ -2667,7 +2667,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
return log_error_errno(r, "Failed to open '%s': %m", fn);
}
- log_debug("Reading config file \"%s\"…", fn);
+ log_debug("Reading config file \"%s\"%s", fn, special_glyph(ELLIPSIS));
f = _f;
}
@@ -2765,7 +2765,7 @@ static int read_config_files(char **config_dirs, char **args, bool *invalid_conf
STRV_FOREACH(f, files)
if (p && path_equal(*f, p)) {
- log_debug("Parsing arguments at position \"%s\"…", *f);
+ log_debug("Parsing arguments at position \"%s\"%s", *f, special_glyph(ELLIPSIS));
r = parse_arguments(config_dirs, args, invalid_config);
if (r < 0)

View File

@ -0,0 +1,115 @@
From 207f51115c18c668982ef8bdb8a024fccaeb87f0 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Sat, 16 Jul 2022 09:49:12 +0200
Subject: [PATCH] core: allow to set default timeout for devices
Fixes: #19879
(cherry picked from commit a0fe19f9f791c05af236265954b1d73e8fcf5468)
Resolves: #1967245
---
src/core/dbus-manager.c | 1 +
src/core/device.c | 2 +-
src/core/main.c | 4 ++++
src/core/manager.c | 1 +
src/core/manager.h | 1 +
src/core/system.conf.in | 1 +
6 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 7488f22116..5b1ed3646e 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2509,6 +2509,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultDeviceTimeoutUSec", "t", bus_property_get_usec, offsetof(Manager, default_device_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
/* The following two items are obsolete alias */
diff --git a/src/core/device.c b/src/core/device.c
index cb8b66dfc5..71b7c1ef81 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -97,7 +97,7 @@ static void device_init(Unit *u) {
* indefinitely for plugged in devices, something which cannot
* happen for the other units since their operations time out
* anyway. */
- u->job_running_timeout = u->manager->default_timeout_start_usec;
+ u->job_running_timeout = u->manager->default_device_timeout_usec;
u->ignore_on_isolate = true;
diff --git a/src/core/main.c b/src/core/main.c
index 08a4df3c97..bfd4c531a7 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -109,6 +109,7 @@ static usec_t arg_default_restart_usec;
static usec_t arg_default_timeout_start_usec;
static usec_t arg_default_timeout_stop_usec;
static usec_t arg_default_timeout_abort_usec;
+static usec_t arg_default_device_timeout_usec;
static bool arg_default_timeout_abort_set;
static usec_t arg_default_start_limit_interval;
static unsigned arg_default_start_limit_burst;
@@ -687,6 +688,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStandardError", config_parse_output_restricted,0, &arg_default_std_error },
{ "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
{ "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
+ { "Manager", "DefaultDeviceTimeoutSec", config_parse_sec, 0, &arg_default_device_timeout_usec },
{ "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */
{ "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
@@ -754,6 +756,7 @@ static void set_manager_defaults(Manager *m) {
m->default_std_error = arg_default_std_error;
m->default_timeout_start_usec = arg_default_timeout_start_usec;
m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
+ m->default_device_timeout_usec = arg_default_device_timeout_usec;
m->default_restart_usec = arg_default_restart_usec;
m->default_start_limit_interval = arg_default_start_limit_interval;
m->default_start_limit_burst = arg_default_start_limit_burst;
@@ -2077,6 +2080,7 @@ static void reset_arguments(void) {
arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
arg_default_timeout_abort_set = false;
+ arg_default_device_timeout_usec = DEFAULT_TIMEOUT_USEC;
arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
arg_runtime_watchdog = 0;
diff --git a/src/core/manager.c b/src/core/manager.c
index 5873e5b6d7..f4611e6f8f 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -731,6 +731,7 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
m->default_tasks_max = UINT64_MAX;
m->default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
m->default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+ m->default_device_timeout_usec = DEFAULT_TIMEOUT_USEC,
m->default_restart_usec = DEFAULT_RESTART_USEC;
m->original_log_level = -1;
m->original_log_target = _LOG_TARGET_INVALID;
diff --git a/src/core/manager.h b/src/core/manager.h
index 7b572c8dfd..3f2cfc5e2e 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -285,6 +285,7 @@ struct Manager {
ExecOutput default_std_output, default_std_error;
usec_t default_restart_usec, default_timeout_start_usec, default_timeout_stop_usec;
+ usec_t default_device_timeout_usec;
usec_t default_start_limit_interval;
unsigned default_start_limit_burst;
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 84246c0e36..2f6852a89f 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -37,6 +37,7 @@
#DefaultStandardError=inherit
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
+#DefaultDeviceTimeoutSec=90s
#DefaultRestartSec=100ms
#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5

View File

@ -0,0 +1,34 @@
From ba81eba0feaf5c34f52141301e2b7ca93128fed0 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Sat, 16 Jul 2022 10:16:41 +0200
Subject: [PATCH] man: document DefaultDeviceTimeoutSec=
(cherry picked from commit 9e69bd4801588c12811c611a1c68b54cecbe1718)
Related: #1967245
---
man/systemd-system.conf.xml | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 988c4e7665..3670f34cb5 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -305,6 +305,17 @@
100ms.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>DefaultDeviceTimeoutSec=</varname></term>
+
+ <listitem><para>Configures the default timeout for waiting for devices. It can be changed per
+ device via the <varname>x-systemd.device-timeout=</varname> option in <filename>/etc/fstab</filename>
+ and <filename>/etc/crypttab</filename> (see
+ <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+ Defaults to 90s.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>DefaultStartLimitIntervalSec=</varname></term>
<term><varname>DefaultStartLimitBurst=</varname></term>

View File

@ -0,0 +1,255 @@
From f1a1ff976ed0787c79a0f57d773bc555ab756b8c Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Fri, 17 Dec 2021 19:39:29 +0100
Subject: [PATCH] Revert "core: Propagate condition failed state to triggering
units."
This reverts commit 12ab94a1e4961a39c32efb60b71866ab588d3ea2.
(cherry picked from commit 40f41f34d4af15d0147b5b2525f0b87ff62eae9a)
Related: #2114005
---
src/core/automount.c | 14 ++++----------
src/core/automount.h | 1 -
src/core/path.c | 16 +++++-----------
src/core/path.h | 1 -
src/core/socket.c | 28 +++++++++-------------------
src/core/socket.h | 1 -
src/core/timer.c | 12 +++---------
src/core/timer.h | 1 -
src/core/unit.c | 10 ----------
src/core/unit.h | 2 --
10 files changed, 21 insertions(+), 65 deletions(-)
diff --git a/src/core/automount.c b/src/core/automount.c
index bac3b2fab7..c1c513d4a5 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -776,11 +776,6 @@ static void automount_enter_running(Automount *a) {
goto fail;
}
- if (unit_has_failed_condition_or_assert(trigger)) {
- automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED);
- return;
- }
-
r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
if (r < 0) {
log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
@@ -1092,11 +1087,10 @@ static int automount_can_start(Unit *u) {
}
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
- [AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
- [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
- [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed",
+ [AUTOMOUNT_SUCCESS] = "success",
+ [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
+ [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
diff --git a/src/core/automount.h b/src/core/automount.h
index a7417d195c..21dd1c0774 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -10,7 +10,6 @@ typedef enum AutomountResult {
AUTOMOUNT_FAILURE_RESOURCES,
AUTOMOUNT_FAILURE_START_LIMIT_HIT,
AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
- AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED,
_AUTOMOUNT_RESULT_MAX,
_AUTOMOUNT_RESULT_INVALID = -1
} AutomountResult;
diff --git a/src/core/path.c b/src/core/path.c
index bf7e1bf3c2..c2facf0b16 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -453,7 +453,7 @@ static void path_enter_dead(Path *p, PathResult f) {
else
unit_log_failure(UNIT(p), path_result_to_string(p->result));
- path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED);
+ path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
}
static void path_enter_running(Path *p) {
@@ -711,11 +711,6 @@ static void path_trigger_notify(Unit *u, Unit *other) {
return;
}
- if (unit_has_failed_condition_or_assert(other)) {
- path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED);
- return;
- }
-
/* Don't propagate anything if there's still a job queued */
if (other->job)
return;
@@ -768,11 +763,10 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
static const char* const path_result_table[_PATH_RESULT_MAX] = {
- [PATH_SUCCESS] = "success",
- [PATH_FAILURE_RESOURCES] = "resources",
- [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
- [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
+ [PATH_SUCCESS] = "success",
+ [PATH_FAILURE_RESOURCES] = "resources",
+ [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
diff --git a/src/core/path.h b/src/core/path.h
index 0ad6bd12c6..8a69f06c13 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -46,7 +46,6 @@ typedef enum PathResult {
PATH_FAILURE_RESOURCES,
PATH_FAILURE_START_LIMIT_HIT,
PATH_FAILURE_UNIT_START_LIMIT_HIT,
- PATH_FAILURE_UNIT_CONDITION_FAILED,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -1
} PathResult;
diff --git a/src/core/socket.c b/src/core/socket.c
index bdfeb43a70..9d47ca2616 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2274,15 +2274,6 @@ static void socket_enter_running(Socket *s, int cfd) {
goto refuse;
}
- if (UNIT_ISSET(s->service) && cfd < 0) {
- Unit *service = UNIT_DEREF(s->service);
-
- if (unit_has_failed_condition_or_assert(service)) {
- socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED);
- return;
- }
- }
-
if (cfd < 0) {
bool pending = false;
Unit *other;
@@ -3298,16 +3289,15 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
- [SOCKET_SUCCESS] = "success",
- [SOCKET_FAILURE_RESOURCES] = "resources",
- [SOCKET_FAILURE_TIMEOUT] = "timeout",
- [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
- [SOCKET_FAILURE_SIGNAL] = "signal",
- [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
- [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
- [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
- [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed",
+ [SOCKET_SUCCESS] = "success",
+ [SOCKET_FAILURE_RESOURCES] = "resources",
+ [SOCKET_FAILURE_TIMEOUT] = "timeout",
+ [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
+ [SOCKET_FAILURE_SIGNAL] = "signal",
+ [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+ [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
+ [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
diff --git a/src/core/socket.h b/src/core/socket.h
index b171b94316..2409dbf2a0 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -39,7 +39,6 @@ typedef enum SocketResult {
SOCKET_FAILURE_START_LIMIT_HIT,
SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
- SOCKET_FAILURE_SERVICE_CONDITION_FAILED,
_SOCKET_RESULT_MAX,
_SOCKET_RESULT_INVALID = -1
} SocketResult;
diff --git a/src/core/timer.c b/src/core/timer.c
index 3c8d89771d..990f05fee4 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -567,11 +567,6 @@ static void timer_enter_running(Timer *t) {
return;
}
- if (unit_has_failed_condition_or_assert(trigger)) {
- timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED);
- return;
- }
-
r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
if (r < 0)
goto fail;
@@ -855,10 +850,9 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
- [TIMER_SUCCESS] = "success",
- [TIMER_FAILURE_RESOURCES] = "resources",
- [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
- [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
+ [TIMER_SUCCESS] = "success",
+ [TIMER_FAILURE_RESOURCES] = "resources",
+ [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
diff --git a/src/core/timer.h b/src/core/timer.h
index d23e19d622..833aadb0b8 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -32,7 +32,6 @@ typedef enum TimerResult {
TIMER_SUCCESS,
TIMER_FAILURE_RESOURCES,
TIMER_FAILURE_START_LIMIT_HIT,
- TIMER_FAILURE_UNIT_CONDITION_FAILED,
_TIMER_RESULT_MAX,
_TIMER_RESULT_INVALID = -1
} TimerResult;
diff --git a/src/core/unit.c b/src/core/unit.c
index 0810bf5a58..dfe0c243ef 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -5661,16 +5661,6 @@ int unit_thaw_vtable_common(Unit *u) {
return unit_cgroup_freezer_action(u, FREEZER_THAW);
}
-bool unit_has_failed_condition_or_assert(Unit *u) {
- if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result)
- return true;
-
- if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result)
- return true;
-
- return false;
-}
-
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
diff --git a/src/core/unit.h b/src/core/unit.h
index a924bd2e83..b8b914711f 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -847,8 +847,6 @@ void unit_thawed(Unit *u);
int unit_freeze_vtable_common(Unit *u);
int unit_thaw_vtable_common(Unit *u);
-bool unit_has_failed_condition_or_assert(Unit *u);
-
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \

View File

@ -0,0 +1,137 @@
From e393372ad5ba67acb9b397f044efdb1c9a100644 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Tue, 24 Aug 2021 16:46:47 +0100
Subject: [PATCH] core: Check unit start rate limiting earlier
[dtardon: This adds the test that's been left out by commit
471eda89a25a3ceac91a2d05e39a54aae78038ed]
(cherry picked from commit 9727f2427ff6b2e1f4ab927cc57ad8e888f04e95)
Related: #2114005
---
test/TEST-10-ISSUE-2467/test.sh | 3 ++
test/TEST-63-ISSUE-17433/Makefile | 1 +
test/TEST-63-ISSUE-17433/test.sh | 42 ++++++++++++++++++++++
test/TEST-63-ISSUE-17433/test63.path | 2 ++
test/TEST-63-ISSUE-17433/test63.service | 5 +++
test/TEST-63-ISSUE-17433/testsuite.service | 17 +++++++++
6 files changed, 70 insertions(+)
create mode 120000 test/TEST-63-ISSUE-17433/Makefile
create mode 100755 test/TEST-63-ISSUE-17433/test.sh
create mode 100644 test/TEST-63-ISSUE-17433/test63.path
create mode 100644 test/TEST-63-ISSUE-17433/test63.service
create mode 100644 test/TEST-63-ISSUE-17433/testsuite.service
diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh
index 0e61236686..a839ef79de 100755
--- a/test/TEST-10-ISSUE-2467/test.sh
+++ b/test/TEST-10-ISSUE-2467/test.sh
@@ -42,6 +42,9 @@ EOF
[Unit]
Requires=test.socket
ConditionPathExistsGlob=/tmp/nonexistent
+# Make sure we hit the socket trigger limit in the test and not the service start limit.
+StartLimitInterval=1000
+StartLimitBurst=1000
[Service]
ExecStart=/bin/true
diff --git a/test/TEST-63-ISSUE-17433/Makefile b/test/TEST-63-ISSUE-17433/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-63-ISSUE-17433/test.sh b/test/TEST-63-ISSUE-17433/test.sh
new file mode 100755
index 0000000000..406a1e214c
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/test.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+set -e
+
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/17433"
+
+# shellcheck source=test/test-functions
+. "${TEST_BASE_DIR:?}/test-functions"
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cp testsuite.service $initdir/etc/systemd/system/testsuite.service
+
+ cp test63.path $initdir/etc/systemd/system/test63.path
+ cp test63.service $initdir/etc/systemd/system/test63.service
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-63-ISSUE-17433/test63.path b/test/TEST-63-ISSUE-17433/test63.path
new file mode 100644
index 0000000000..a6573bda0a
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/test63.path
@@ -0,0 +1,2 @@
+[Path]
+PathExists=/tmp/test63
diff --git a/test/TEST-63-ISSUE-17433/test63.service b/test/TEST-63-ISSUE-17433/test63.service
new file mode 100644
index 0000000000..c83801874d
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/test63.service
@@ -0,0 +1,5 @@
+[Unit]
+ConditionPathExists=!/tmp/nonexistent
+
+[Service]
+ExecStart=true
diff --git a/test/TEST-63-ISSUE-17433/testsuite.service b/test/TEST-63-ISSUE-17433/testsuite.service
new file mode 100644
index 0000000000..d3ca5b002b
--- /dev/null
+++ b/test/TEST-63-ISSUE-17433/testsuite.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=TEST-63-ISSUE-17433
+
+[Service]
+ExecStartPre=rm -f /failed /testok
+Type=oneshot
+ExecStart=rm -f /tmp/nonexistent
+ExecStart=systemctl start test63.path
+ExecStart=touch /tmp/test63
+# Make sure systemd has sufficient time to hit the start limit for test63.service.
+ExecStart=sleep 2
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = failed'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = start-limit-hit'
+# FIXME: The path remains active, which it should not
+# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = failed'
+# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = unit-start-limit-hit'
+ExecStart=sh -x -c 'echo OK >/testok'

View File

@ -0,0 +1,127 @@
From 9d3f5e5d222308d29aad9bf7b2bfc440143a8606 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Fri, 17 Dec 2021 20:01:31 +0100
Subject: [PATCH] core: Add trigger limit for path units
When conditions fail on a service unit, a path unit can cause
PID 1 to busy loop as it keeps trying to activate the service unit.
To avoid this from happening, add a trigger limit to the path unit,
identical to the trigger limit we have for socket units.
Initially, let's start with a high limit and not make it configurable.
If needed, we can add properties to configure the rate limit similar
to the ones we have for socket units.
(cherry picked from commit aaae822b37aa3ca39aebb516fdc6bef36d730c25)
Resolves: #2114005
---
src/core/path.c | 10 ++++++++++
src/core/path.h | 3 +++
test/TEST-63-ISSUE-17433/test63.service | 2 +-
test/TEST-63-ISSUE-17433/testsuite.service | 21 +++++++++++++++++----
4 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/src/core/path.c b/src/core/path.c
index c2facf0b16..b899bde0de 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -238,6 +238,9 @@ static void path_init(Unit *u) {
assert(u->load_state == UNIT_STUB);
p->directory_mode = 0755;
+
+ p->trigger_limit.interval = 2 * USEC_PER_SEC;
+ p->trigger_limit.burst = 200;
}
void path_free_specs(Path *p) {
@@ -467,6 +470,12 @@ static void path_enter_running(Path *p) {
if (unit_stop_pending(UNIT(p)))
return;
+ if (!ratelimit_below(&p->trigger_limit)) {
+ log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation.");
+ path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT);
+ return;
+ }
+
trigger = UNIT_TRIGGER(UNIT(p));
if (!trigger) {
log_unit_error(UNIT(p), "Unit to trigger vanished.");
@@ -767,6 +776,7 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = {
[PATH_FAILURE_RESOURCES] = "resources",
[PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
+ [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
diff --git a/src/core/path.h b/src/core/path.h
index 8a69f06c13..12fd13fbe3 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -46,6 +46,7 @@ typedef enum PathResult {
PATH_FAILURE_RESOURCES,
PATH_FAILURE_START_LIMIT_HIT,
PATH_FAILURE_UNIT_START_LIMIT_HIT,
+ PATH_FAILURE_TRIGGER_LIMIT_HIT,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -1
} PathResult;
@@ -63,6 +64,8 @@ struct Path {
mode_t directory_mode;
PathResult result;
+
+ RateLimit trigger_limit;
};
void path_free_specs(Path *p);
diff --git a/test/TEST-63-ISSUE-17433/test63.service b/test/TEST-63-ISSUE-17433/test63.service
index c83801874d..6292434c5c 100644
--- a/test/TEST-63-ISSUE-17433/test63.service
+++ b/test/TEST-63-ISSUE-17433/test63.service
@@ -1,5 +1,5 @@
[Unit]
-ConditionPathExists=!/tmp/nonexistent
+ConditionPathExists=/tmp/nonexistent
[Service]
ExecStart=true
diff --git a/test/TEST-63-ISSUE-17433/testsuite.service b/test/TEST-63-ISSUE-17433/testsuite.service
index d3ca5b002b..39f9643890 100644
--- a/test/TEST-63-ISSUE-17433/testsuite.service
+++ b/test/TEST-63-ISSUE-17433/testsuite.service
@@ -4,14 +4,27 @@ Description=TEST-63-ISSUE-17433
[Service]
ExecStartPre=rm -f /failed /testok
Type=oneshot
+
+# Test that a path unit continuously triggering a service that fails condition checks eventually fails with
+# the trigger-limit-hit error.
ExecStart=rm -f /tmp/nonexistent
ExecStart=systemctl start test63.path
ExecStart=touch /tmp/test63
-# Make sure systemd has sufficient time to hit the start limit for test63.service.
+# Make sure systemd has sufficient time to hit the trigger limit for test63.path.
ExecStart=sleep 2
-ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = failed'
-ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = start-limit-hit'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = inactive'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = success'
# FIXME: The path remains active, which it should not
# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = failed'
-# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = unit-start-limit-hit'
+# ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = trigger-limit-hit'
+
+# Test that starting the service manually doesn't affect the path unit.
+ExecStart=rm -f /tmp/test63
+ExecStart=systemctl reset-failed
+ExecStart=systemctl start test63.path
+ExecStart=systemctl start test63.service
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p ActiveState)" = inactive'
+ExecStart=sh -x -c 'test "$(systemctl show test63.service --value -p Result)" = success'
+ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p ActiveState)" = active'
+ExecStart=sh -x -c 'test "$(systemctl show test63.path --value -p Result)" = success'
ExecStart=sh -x -c 'echo OK >/testok'

View File

@ -0,0 +1,680 @@
From f20ccc0d505eccd59bb3814f59a63ea036be5bd5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 18 Aug 2020 16:27:20 +0200
Subject: [PATCH] meson: add syscall-names-update target
The calls to find_program("tools/*") are moved earlier so they can be used
in libshared/ (and it doesn't make sense to split them).
(cherry picked from commit 47354b440e90626c320d8f142cb742ff569e3a40)
Related: #2040247
---
meson.build | 13 +-
src/shared/meson.build | 6 +
src/shared/syscall-names.text | 597 ++++++++++++++++++++++++++++++++++
tools/syscall-names-update.sh | 6 +
4 files changed, 617 insertions(+), 5 deletions(-)
create mode 100644 src/shared/syscall-names.text
create mode 100755 tools/syscall-names-update.sh
diff --git a/meson.build b/meson.build
index 57de947367..6729a9ea5e 100644
--- a/meson.build
+++ b/meson.build
@@ -1417,6 +1417,14 @@ install_libsystemd_static = static_library(
############################################################
+hwdb_update_sh = find_program('tools/meson-hwdb-update.sh')
+make_directive_index_py = find_program('tools/make-directive-index.py')
+make_man_index_py = find_program('tools/make-man-index.py')
+syscall_names_update_sh = find_program('tools/syscall-names-update.sh')
+xml_helper_py = find_program('tools/xml_helper.py')
+
+############################################################
+
# binaries that have --help and are intended for use by humans,
# usually, but not always, installed in /bin.
public_programs = []
@@ -2721,11 +2729,6 @@ run_target('fuzzers',
############################################################
-make_directive_index_py = find_program('tools/make-directive-index.py')
-make_man_index_py = find_program('tools/make-man-index.py')
-xml_helper_py = find_program('tools/xml_helper.py')
-hwdb_update_sh = find_program('tools/meson-hwdb-update.sh')
-
subdir('units')
subdir('sysctl.d')
subdir('sysusers.d')
diff --git a/src/shared/meson.build b/src/shared/meson.build
index d0a1bba4c6..c9dd0a3a4e 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -165,3 +165,9 @@ libshared = shared_library(
dependencies : libshared_deps,
install : true,
install_dir : rootlibexecdir)
+
+############################################################
+
+run_target(
+ 'syscall-names-update',
+ command : [syscall_names_update_sh, meson.current_source_dir()])
diff --git a/src/shared/syscall-names.text b/src/shared/syscall-names.text
new file mode 100644
index 0000000000..40d18a8894
--- /dev/null
+++ b/src/shared/syscall-names.text
@@ -0,0 +1,597 @@
+_llseek
+_newselect
+_sysctl
+accept
+accept4
+access
+acct
+add_key
+adjtimex
+alarm
+arc_gettls
+arc_settls
+arc_usr_cmpxchg
+arch_prctl
+arm_fadvise64_64
+arm_sync_file_range
+atomic_barrier
+atomic_cmpxchg_32
+bdflush
+bfin_spinlock
+bind
+bpf
+brk
+cache_sync
+cachectl
+cacheflush
+capget
+capset
+chdir
+chmod
+chown
+chown32
+chroot
+clock_adjtime
+clock_adjtime64
+clock_getres
+clock_getres_time64
+clock_gettime
+clock_gettime64
+clock_nanosleep
+clock_nanosleep_time64
+clock_settime
+clock_settime64
+clone
+clone2
+clone3
+close
+close_range
+connect
+copy_file_range
+creat
+create_module
+delete_module
+dipc
+dup
+dup2
+dup3
+epoll_create
+epoll_create1
+epoll_ctl
+epoll_ctl_old
+epoll_pwait
+epoll_wait
+epoll_wait_old
+eventfd
+eventfd2
+exec_with_loader
+execv
+execve
+execveat
+exit
+exit_group
+faccessat
+faccessat2
+fadvise64
+fadvise64_64
+fallocate
+fanotify_init
+fanotify_mark
+fchdir
+fchmod
+fchmodat
+fchown
+fchown32
+fchownat
+fcntl
+fcntl64
+fdatasync
+fgetxattr
+finit_module
+flistxattr
+flock
+fork
+fp_udfiex_crtl
+fremovexattr
+fsconfig
+fsetxattr
+fsmount
+fsopen
+fspick
+fstat
+fstat64
+fstatat64
+fstatfs
+fstatfs64
+fsync
+ftruncate
+ftruncate64
+futex
+futex_time64
+futimesat
+get_kernel_syms
+get_mempolicy
+get_robust_list
+get_thread_area
+getcpu
+getcwd
+getdents
+getdents64
+getdomainname
+getdtablesize
+getegid
+getegid32
+geteuid
+geteuid32
+getgid
+getgid32
+getgroups
+getgroups32
+gethostname
+getitimer
+getpagesize
+getpeername
+getpgid
+getpgrp
+getpid
+getpmsg
+getppid
+getpriority
+getrandom
+getresgid
+getresgid32
+getresuid
+getresuid32
+getrlimit
+getrusage
+getsid
+getsockname
+getsockopt
+gettid
+gettimeofday
+getuid
+getuid32
+getunwind
+getxattr
+getxgid
+getxpid
+getxuid
+idle
+init_module
+inotify_add_watch
+inotify_init
+inotify_init1
+inotify_rm_watch
+io_cancel
+io_destroy
+io_getevents
+io_pgetevents
+io_pgetevents_time64
+io_setup
+io_submit
+io_uring_enter
+io_uring_register
+io_uring_setup
+ioctl
+ioperm
+iopl
+ioprio_get
+ioprio_set
+ipc
+kcmp
+kern_features
+kexec_file_load
+kexec_load
+keyctl
+kill
+lchown
+lchown32
+lgetxattr
+link
+linkat
+listen
+listxattr
+llistxattr
+lookup_dcookie
+lremovexattr
+lseek
+lsetxattr
+lstat
+lstat64
+madvise
+mbind
+membarrier
+memfd_create
+memory_ordering
+migrate_pages
+mincore
+mkdir
+mkdirat
+mknod
+mknodat
+mlock
+mlock2
+mlockall
+mmap
+mmap2
+modify_ldt
+mount
+move_mount
+move_pages
+mprotect
+mq_getsetattr
+mq_notify
+mq_open
+mq_timedreceive
+mq_timedreceive_time64
+mq_timedsend
+mq_timedsend_time64
+mq_unlink
+mremap
+msgctl
+msgget
+msgrcv
+msgsnd
+msync
+multiplexer
+munlock
+munlockall
+munmap
+name_to_handle_at
+nanosleep
+newfstatat
+nfsservctl
+ni_syscall
+nice
+old_adjtimex
+old_getpagesize
+oldfstat
+oldlstat
+oldolduname
+oldstat
+oldumount
+olduname
+open
+open_by_handle_at
+open_tree
+openat
+openat2
+or1k_atomic
+osf_adjtime
+osf_afs_syscall
+osf_alt_plock
+osf_alt_setsid
+osf_alt_sigpending
+osf_asynch_daemon
+osf_audcntl
+osf_audgen
+osf_chflags
+osf_execve
+osf_exportfs
+osf_fchflags
+osf_fdatasync
+osf_fpathconf
+osf_fstat
+osf_fstatfs
+osf_fstatfs64
+osf_fuser
+osf_getaddressconf
+osf_getdirentries
+osf_getdomainname
+osf_getfh
+osf_getfsstat
+osf_gethostid
+osf_getitimer
+osf_getlogin
+osf_getmnt
+osf_getrusage
+osf_getsysinfo
+osf_gettimeofday
+osf_kloadcall
+osf_kmodcall
+osf_lstat
+osf_memcntl
+osf_mincore
+osf_mount
+osf_mremap
+osf_msfs_syscall
+osf_msleep
+osf_mvalid
+osf_mwakeup
+osf_naccept
+osf_nfssvc
+osf_ngetpeername
+osf_ngetsockname
+osf_nrecvfrom
+osf_nrecvmsg
+osf_nsendmsg
+osf_ntp_adjtime
+osf_ntp_gettime
+osf_old_creat
+osf_old_fstat
+osf_old_getpgrp
+osf_old_killpg
+osf_old_lstat
+osf_old_open
+osf_old_sigaction
+osf_old_sigblock
+osf_old_sigreturn
+osf_old_sigsetmask
+osf_old_sigvec
+osf_old_stat
+osf_old_vadvise
+osf_old_vtrace
+osf_old_wait
+osf_oldquota
+osf_pathconf
+osf_pid_block
+osf_pid_unblock
+osf_plock
+osf_priocntlset
+osf_profil
+osf_proplist_syscall
+osf_reboot
+osf_revoke
+osf_sbrk
+osf_security
+osf_select
+osf_set_program_attributes
+osf_set_speculative
+osf_sethostid
+osf_setitimer
+osf_setlogin
+osf_setsysinfo
+osf_settimeofday
+osf_shmat
+osf_signal
+osf_sigprocmask
+osf_sigsendset
+osf_sigstack
+osf_sigwaitprim
+osf_sstk
+osf_stat
+osf_statfs
+osf_statfs64
+osf_subsys_info
+osf_swapctl
+osf_swapon
+osf_syscall
+osf_sysinfo
+osf_table
+osf_uadmin
+osf_usleep_thread
+osf_uswitch
+osf_utc_adjtime
+osf_utc_gettime
+osf_utimes
+osf_utsname
+osf_wait4
+osf_waitid
+pause
+pciconfig_iobase
+pciconfig_read
+pciconfig_write
+perf_event_open
+perfctr
+perfmonctl
+personality
+pidfd_getfd
+pidfd_open
+pidfd_send_signal
+pipe
+pipe2
+pivot_root
+pkey_alloc
+pkey_free
+pkey_mprotect
+poll
+ppoll
+ppoll_time64
+prctl
+pread64
+preadv
+preadv2
+prlimit64
+process_vm_readv
+process_vm_writev
+pselect6
+pselect6_time64
+ptrace
+pwrite64
+pwritev
+pwritev2
+query_module
+quotactl
+read
+readahead
+readdir
+readlink
+readlinkat
+readv
+reboot
+recv
+recvfrom
+recvmmsg
+recvmmsg_time64
+recvmsg
+remap_file_pages
+removexattr
+rename
+renameat
+renameat2
+request_key
+restart_syscall
+riscv_flush_icache
+rmdir
+rseq
+rt_sigaction
+rt_sigpending
+rt_sigprocmask
+rt_sigqueueinfo
+rt_sigreturn
+rt_sigsuspend
+rt_sigtimedwait
+rt_sigtimedwait_time64
+rt_tgsigqueueinfo
+rtas
+s390_guarded_storage
+s390_pci_mmio_read
+s390_pci_mmio_write
+s390_runtime_instr
+s390_sthyi
+sched_get_affinity
+sched_get_priority_max
+sched_get_priority_min
+sched_getaffinity
+sched_getattr
+sched_getparam
+sched_getscheduler
+sched_rr_get_interval
+sched_rr_get_interval_time64
+sched_set_affinity
+sched_setaffinity
+sched_setattr
+sched_setparam
+sched_setscheduler
+sched_yield
+seccomp
+select
+semctl
+semget
+semop
+semtimedop
+semtimedop_time64
+send
+sendfile
+sendfile64
+sendmmsg
+sendmsg
+sendto
+set_mempolicy
+set_robust_list
+set_thread_area
+set_tid_address
+setdomainname
+setfsgid
+setfsgid32
+setfsuid
+setfsuid32
+setgid
+setgid32
+setgroups
+setgroups32
+sethae
+sethostname
+setitimer
+setns
+setpgid
+setpgrp
+setpriority
+setregid
+setregid32
+setresgid
+setresgid32
+setresuid
+setresuid32
+setreuid
+setreuid32
+setrlimit
+setsid
+setsockopt
+settimeofday
+setuid
+setuid32
+setxattr
+sgetmask
+shmat
+shmctl
+shmdt
+shmget
+shutdown
+sigaction
+sigaltstack
+signal
+signalfd
+signalfd4
+sigpending
+sigprocmask
+sigreturn
+sigsuspend
+socket
+socketcall
+socketpair
+splice
+spu_create
+spu_run
+ssetmask
+stat
+stat64
+statfs
+statfs64
+statx
+stime
+subpage_prot
+swapcontext
+swapoff
+swapon
+switch_endian
+symlink
+symlinkat
+sync
+sync_file_range
+sync_file_range2
+syncfs
+sys_debug_setcontext
+syscall
+sysfs
+sysinfo
+syslog
+sysmips
+tee
+tgkill
+time
+timer_create
+timer_delete
+timer_getoverrun
+timer_gettime
+timer_gettime64
+timer_settime
+timer_settime64
+timerfd
+timerfd_create
+timerfd_gettime
+timerfd_gettime64
+timerfd_settime
+timerfd_settime64
+times
+tkill
+truncate
+truncate64
+udftrap
+ugetrlimit
+umask
+umount
+umount2
+uname
+unlink
+unlinkat
+unshare
+uselib
+userfaultfd
+ustat
+utime
+utimensat
+utimensat_time64
+utimes
+utimesat
+utrap_install
+vfork
+vhangup
+vm86
+vm86old
+vmsplice
+wait4
+waitid
+waitpid
+write
+writev
diff --git a/tools/syscall-names-update.sh b/tools/syscall-names-update.sh
new file mode 100755
index 0000000000..c884b93cda
--- /dev/null
+++ b/tools/syscall-names-update.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -eu
+
+cd "$1"
+
+curl -L -o syscall-names.text 'https://raw.githubusercontent.com/hrw/syscalls-table/master/syscall-names.text'

View File

@ -0,0 +1,27 @@
From bcc0f8bfbc0ea220895c1d3a8bf2d3124ddcef16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 25 Oct 2020 13:54:20 +0100
Subject: [PATCH] syscall-names: add process_madvise which is planned for 5.10
It was added in v5.9-11793-gecb8ac8b1f and is still present in v5.10-rc1, so it
seems likely that it'll be in 5.10 too.
(cherry picked from commit 397cca2453465d4ad5a51b16ad71acf45a3de352)
Related: #2040247
---
src/shared/syscall-names.text | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/shared/syscall-names.text b/src/shared/syscall-names.text
index 40d18a8894..f1b7e29d50 100644
--- a/src/shared/syscall-names.text
+++ b/src/shared/syscall-names.text
@@ -392,6 +392,7 @@ pread64
preadv
preadv2
prlimit64
+process_madvise
process_vm_readv
process_vm_writev
pselect6

View File

@ -0,0 +1,157 @@
From f3c6abebbe4718085fcf17ed3ab0690e379fbb7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 19 Aug 2020 17:43:23 +0200
Subject: [PATCH] shared: add @known syscall list
(cherry picked from commit 95aac01259db689dac7d8e5bfafb60e8c70cd734)
Related: #2040247
---
man/systemd.exec.xml | 4 ++++
src/shared/generate-syscall-list.py | 5 +++++
src/shared/meson.build | 11 +++++++++++
src/shared/seccomp-util.c | 6 ++++++
src/shared/seccomp-util.h | 3 ++-
src/test/test-seccomp.c | 19 ++++++++++++-------
6 files changed, 40 insertions(+), 8 deletions(-)
create mode 100755 src/shared/generate-syscall-list.py
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index dc88cf9781..b04b4ba552 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1556,6 +1556,10 @@ RestrictNamespaces=~cgroup net</programlisting>
<entry>@timer</entry>
<entry>System calls for scheduling operations by time (<citerefentry project='man-pages'><refentrytitle>alarm</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>timer_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>, …)</entry>
</row>
+ <row>
+ <entry>@known</entry>
+ <entry>All system calls defined by the kernel. This list is defined statically in systemd based on a kernel version that was available when this systmed version was released. It will become progressively more out-of-date as the kernel is updated.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/src/shared/generate-syscall-list.py b/src/shared/generate-syscall-list.py
new file mode 100755
index 0000000000..13a6ae9241
--- /dev/null
+++ b/src/shared/generate-syscall-list.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+import sys
+
+for line in open(sys.argv[1]):
+ print('"{}\\0"'.format(line.strip()))
diff --git a/src/shared/meson.build b/src/shared/meson.build
index c9dd0a3a4e..fed08571d1 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -109,6 +109,16 @@ shared_sources = files('''
test_tables_h = files('test-tables.h')
shared_sources += [test_tables_h]
+generate_syscall_list = find_program('generate-syscall-list.py')
+fname = 'syscall-list.h'
+syscall_list_h = custom_target(
+ fname,
+ input : 'syscall-names.text',
+ output : fname,
+ command : [generate_syscall_list,
+ '@INPUT@'],
+ capture : true)
+
if conf.get('HAVE_ACL') == 1
shared_sources += files('acl-util.c')
endif
@@ -119,6 +129,7 @@ endif
if conf.get('HAVE_SECCOMP') == 1
shared_sources += files('seccomp-util.c')
+ shared_sources += syscall_list_h
endif
if conf.get('HAVE_LIBIPTC') == 1
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index c57c409433..c2b2f2da92 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -855,6 +855,12 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"timerfd_settime\0"
"times\0"
},
+ [SYSCALL_FILTER_SET_KNOWN] = {
+ .name = "@known",
+ .help = "All known syscalls declared in the kernel",
+ .value =
+#include "syscall-list.h"
+ },
};
const SyscallFilterSet *syscall_filter_set_find(const char *name) {
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index 602f092255..541ba1e067 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -21,7 +21,7 @@ typedef struct SyscallFilterSet {
} SyscallFilterSet;
enum {
- /* Please leave DEFAULT first, but sort the rest alphabetically */
+ /* Please leave DEFAULT first and KNOWN last, but sort the rest alphabetically */
SYSCALL_FILTER_SET_DEFAULT,
SYSCALL_FILTER_SET_AIO,
SYSCALL_FILTER_SET_BASIC_IO,
@@ -49,6 +49,7 @@ enum {
SYSCALL_FILTER_SET_SYNC,
SYSCALL_FILTER_SET_SYSTEM_SERVICE,
SYSCALL_FILTER_SET_TIMER,
+ SYSCALL_FILTER_SET_KNOWN,
_SYSCALL_FILTER_SET_MAX
};
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index 6ec04c4c55..286f01b5ce 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -106,8 +106,10 @@ static void test_filter_sets(void) {
if (pid == 0) { /* Child? */
int fd;
- /* If we look at the default set (or one that includes it), whitelist instead of blacklist */
- if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
+ /* If we look at the default set (or one that includes it), allow-list instead of deny-list */
+ if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT,
+ SYSCALL_FILTER_SET_SYSTEM_SERVICE,
+ SYSCALL_FILTER_SET_KNOWN))
r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true);
else
r = seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EUCLEAN), true);
@@ -639,20 +641,23 @@ static void test_lock_personality(void) {
}
static void test_filter_sets_ordered(void) {
- size_t i;
-
/* Ensure "@default" always remains at the beginning of the list */
assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
assert_se(streq(syscall_filter_sets[0].name, "@default"));
- for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
+ /* Ensure "@known" always remains at the end of the list */
+ assert_se(SYSCALL_FILTER_SET_KNOWN == _SYSCALL_FILTER_SET_MAX - 1);
+ assert_se(streq(syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].name, "@known"));
+
+ for (size_t i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
const char *k, *p = NULL;
/* Make sure each group has a description */
assert_se(!isempty(syscall_filter_sets[0].help));
- /* Make sure the groups are ordered alphabetically, except for the first entry */
- assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
+ /* Make sure the groups are ordered alphabetically, except for the first and last entries */
+ assert_se(i < 2 || i == _SYSCALL_FILTER_SET_MAX - 1 ||
+ strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
NULSTR_FOREACH(k, syscall_filter_sets[i].value) {

View File

@ -0,0 +1,24 @@
From da722bc383c359b77fab671a0e7872fe4c0232ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sat, 22 Aug 2020 16:07:05 +0200
Subject: [PATCH] generate-syscall-list: require python3
Python3.4 works, but 2.7 returns a tuple from os.uname().
(cherry picked from commit 8694114b809f92f6a882134f3635aa42bfb41e11)
Related: #2040247
---
src/shared/generate-syscall-list.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/generate-syscall-list.py b/src/shared/generate-syscall-list.py
index 13a6ae9241..0b90d2d276 100755
--- a/src/shared/generate-syscall-list.py
+++ b/src/shared/generate-syscall-list.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import sys
for line in open(sys.argv[1]):

View File

@ -0,0 +1,82 @@
From 64705366e134f06438e88f0b7fbef341d0a01431 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 19 Aug 2020 17:43:40 +0200
Subject: [PATCH] shared/seccomp: reduce scope of indexing variables
(cherry picked from commit 077e8fc0cad5a4532348d20a1eef8621295dd75a)
Related: #2040247
---
src/shared/seccomp-util.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index c2b2f2da92..4d2ba31d47 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -864,12 +864,10 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
};
const SyscallFilterSet *syscall_filter_set_find(const char *name) {
- unsigned i;
-
if (isempty(name) || name[0] != '@')
return NULL;
- for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++)
+ for (unsigned i = 0; i < _SYSCALL_FILTER_SET_MAX; i++)
if (streq(syscall_filter_sets[i].name, name))
return syscall_filter_sets + i;
@@ -1105,7 +1103,6 @@ int seccomp_restrict_namespaces(unsigned long retain) {
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
- unsigned i;
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
@@ -1135,7 +1132,7 @@ int seccomp_restrict_namespaces(unsigned long retain) {
continue;
}
- for (i = 0; namespace_flag_map[i].name; i++) {
+ for (unsigned i = 0; namespace_flag_map[i].name; i++) {
unsigned long f;
f = namespace_flag_map[i].flag;
@@ -1288,7 +1285,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
return r;
if (whitelist) {
- int af, first = 0, last = 0;
+ int first = 0, last = 0;
void *afp;
/* If this is a whitelist, we first block the address families that are out of range and then
@@ -1296,7 +1293,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
* the set. */
SET_FOREACH(afp, address_families, i) {
- af = PTR_TO_INT(afp);
+ int af = PTR_TO_INT(afp);
if (af <= 0 || af >= af_max())
continue;
@@ -1350,7 +1347,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
}
/* Block everything between the first and last entry */
- for (af = 1; af < af_max(); af++) {
+ for (int af = 1; af < af_max(); af++) {
if (set_contains(address_families, INT_TO_PTR(af)))
continue;
@@ -1378,7 +1375,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
* checks. */
SET_FOREACH(af, address_families, i) {
-
r = seccomp_rule_add_exact(
seccomp,
SCMP_ACT_ERRNO(EAFNOSUPPORT),

View File

@ -0,0 +1,32 @@
From 2e33a4ffdd54de1f88c3cd37ca5ace94a637b1dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 19 Aug 2020 17:46:30 +0200
Subject: [PATCH] shared/syscall-list: filter out some obviously
platform-specific syscalls
(cherry picked from commit 752fedbea7c02c82287c7ff2a4139f528b3f7ba8)
Related: #2040247
---
src/shared/generate-syscall-list.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/shared/generate-syscall-list.py b/src/shared/generate-syscall-list.py
index 0b90d2d276..030c3feec4 100755
--- a/src/shared/generate-syscall-list.py
+++ b/src/shared/generate-syscall-list.py
@@ -1,5 +1,14 @@
#!/usr/bin/env python3
import sys
+import os
+
+s390 = 's390' in os.uname().machine
+arm = 'arm' in os.uname().machine
for line in open(sys.argv[1]):
+ if line.startswith('s390_') and not s390:
+ continue
+ if line.startswith('arm_') and not arm:
+ continue
+
print('"{}\\0"'.format(line.strip()))

View File

@ -0,0 +1,123 @@
From 42ed3377b5817f2c1f84e1bdca301ea51ecc3299 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 20 Sep 2018 14:19:41 +0200
Subject: [PATCH] seccomp: tighten checking of seccomp filter creation
In seccomp code, the code is changed to propagate errors which are about
anything other than unknown/unimplemented syscalls. I *think* such errors
should not happen in normal usage, but so far we would summarilly ignore all
errors, so that part is uncertain. If it turns out that other errors occur and
should be ignored, this should be added later.
In nspawn, we would count the number of added filters, but didn't use this for
anything. Drop that part.
The comments suggested that seccomp_add_syscall_filter_item() returned negative
if the syscall is unknown, but this wasn't true: it returns 0.
The error at this point can only be if the syscall was known but couldn't be
added. If the error comes from our internal whitelist in nspawn, treat this as
error, because it means that our internal table is wrong. If the error comes
from user arguments, warn and ignore. (If some syscall is not known at current
architecture, it is still silently ignored.)
(cherry picked from commit 7e86bd73a47f2b8dd3d9a743e69fb0117f450ad8)
Related: #2040247
---
src/nspawn/nspawn-seccomp.c | 14 +++++---------
src/shared/seccomp-util.c | 26 ++++++++++++++++----------
2 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c
index fba22644da..17abfcec26 100644
--- a/src/nspawn/nspawn-seccomp.c
+++ b/src/nspawn/nspawn-seccomp.c
@@ -140,7 +140,7 @@ static int seccomp_add_default_syscall_filter(
*/
};
- int r, c = 0;
+ int r;
size_t i;
char **p;
@@ -150,21 +150,17 @@ static int seccomp_add_default_syscall_filter(
r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist, false);
if (r < 0)
- /* If the system call is not known on this architecture, then that's fine, let's ignore it */
- log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", whitelist[i].name, seccomp_arch_to_string(arch));
- else
- c++;
+ return log_error_errno(r, "Failed to add syscall filter item %s: %m", whitelist[i].name);
}
STRV_FOREACH(p, syscall_whitelist) {
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
if (r < 0)
- log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", *p, seccomp_arch_to_string(arch));
- else
- c++;
+ log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
+ *p, seccomp_arch_to_string(arch));
}
- return c;
+ return 0;
}
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 4d2ba31d47..710a734715 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -907,9 +907,13 @@ int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name,
r = seccomp_rule_add_exact(seccomp, action, id, 0);
if (r < 0) {
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
- if (log_missing)
- log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m",
- name, id);
+ bool ignore = r == -EDOM;
+
+ if (!ignore || log_missing)
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d%s: %m",
+ name, id, ignore ? ", ignoring" : "");
+ if (!ignore)
+ return r;
}
return 0;
@@ -957,10 +961,8 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
return r;
r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL, log_missing);
- if (r < 0) {
- log_debug_errno(r, "Failed to add filter set, ignoring: %m");
- continue;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add filter set: %m");
r = seccomp_load(seccomp);
if (IN_SET(r, -EPERM, -EACCES))
@@ -1005,11 +1007,15 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
if (r < 0) {
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
_cleanup_free_ char *n = NULL;
+ bool ignore;
n = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, id);
- if (log_missing)
- log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m",
- strna(n), id);
+ ignore = r == -EDOM;
+ if (!ignore || log_missing)
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d%s: %m",
+ strna(n), id, ignore ? ", ignoring" : "");
+ if (!ignore)
+ return r;
}
}

View File

@ -0,0 +1,156 @@
From eaad892c513806801e3d2055788fa202372b3f15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 21 Aug 2020 17:21:04 +0200
Subject: [PATCH] shared/seccomp-util: added functionality to make list of
filtred syscalls
While at it, start removing the "seccomp_" prefix from our
own functions. It is used by libseccomp.
(cherry picked from commit 000c05207d68658b76af9e1caf9aa3a4e3fa697b)
Related: #2040247
---
src/nspawn/nspawn-seccomp.c | 9 +++++++--
src/shared/seccomp-util.c | 39 ++++++++++++++++++++++++++++++-------
src/shared/seccomp-util.h | 8 +++++++-
3 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c
index 17abfcec26..2b4a65e875 100644
--- a/src/nspawn/nspawn-seccomp.c
+++ b/src/nspawn/nspawn-seccomp.c
@@ -148,13 +148,18 @@ static int seccomp_add_default_syscall_filter(
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
- r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist, false);
+ r = seccomp_add_syscall_filter_item(ctx,
+ whitelist[i].name,
+ SCMP_ACT_ALLOW,
+ syscall_blacklist,
+ false,
+ NULL);
if (r < 0)
return log_error_errno(r, "Failed to add syscall filter item %s: %m", whitelist[i].name);
}
STRV_FOREACH(p, syscall_whitelist) {
- r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
+ r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false, NULL);
if (r < 0)
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
*p, seccomp_arch_to_string(arch));
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 710a734715..56075d92e0 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -874,15 +874,31 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name) {
return NULL;
}
-static int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action, char **exclude, bool log_missing);
+static int add_syscall_filter_set(
+ scmp_filter_ctx seccomp,
+ const SyscallFilterSet *set,
+ uint32_t action,
+ char **exclude,
+ bool log_missing,
+ char ***added);
+
+int seccomp_add_syscall_filter_item(
+ scmp_filter_ctx *seccomp,
+ const char *name,
+ uint32_t action,
+ char **exclude,
+ bool log_missing,
+ char ***added) {
-int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name, uint32_t action, char **exclude, bool log_missing) {
assert(seccomp);
assert(name);
if (strv_contains(exclude, name))
return 0;
+ /* Any syscalls that are handled are added to the *added strv. The pointer
+ * must be either NULL or point to a valid pre-initialized possibly-empty strv. */
+
if (name[0] == '@') {
const SyscallFilterSet *other;
@@ -892,7 +908,7 @@ int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name,
return -EINVAL;
}
- return seccomp_add_syscall_filter_set(seccomp, other, action, exclude, log_missing);
+ return add_syscall_filter_set(seccomp, other, action, exclude, log_missing, added);
} else {
int id, r;
@@ -916,25 +932,34 @@ int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name,
return r;
}
+ if (added) {
+ r = strv_extend(added, name);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
}
-static int seccomp_add_syscall_filter_set(
+static int add_syscall_filter_set(
scmp_filter_ctx seccomp,
const SyscallFilterSet *set,
uint32_t action,
char **exclude,
- bool log_missing) {
+ bool log_missing,
+ char ***added) {
const char *sys;
int r;
+ /* Any syscalls that are handled are added to the *added strv. It needs to be initialized. */
+
assert(seccomp);
assert(set);
NULSTR_FOREACH(sys, set->value) {
- r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude, log_missing);
+ r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude, log_missing, added);
if (r < 0)
return r;
}
@@ -960,7 +985,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
if (r < 0)
return r;
- r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL, log_missing);
+ r = add_syscall_filter_set(seccomp, set, action, NULL, log_missing, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add filter set: %m");
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index 541ba1e067..291b2bffe0 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -59,7 +59,13 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name);
int seccomp_filter_set_add(Hashmap *s, bool b, const SyscallFilterSet *set);
-int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude, bool log_missing);
+int seccomp_add_syscall_filter_item(
+ scmp_filter_ctx *ctx,
+ const char *name,
+ uint32_t action,
+ char **exclude,
+ bool log_missing,
+ char ***added);
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action, bool log_missing);
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action, bool log_missing);

View File

@ -0,0 +1,77 @@
From 65d64ba146c30a5f205b650381f331fd8db2eb22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 21 Aug 2020 17:23:48 +0200
Subject: [PATCH] nspawn: return ENOSYS by default, EPERM for "known" calls
(cherry picked from commit 3573e032f26724949e86626eace058d006b8bf70)
Resolves: #2040247
---
src/nspawn/nspawn-seccomp.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c
index 2b4a65e875..563cda140e 100644
--- a/src/nspawn/nspawn-seccomp.c
+++ b/src/nspawn/nspawn-seccomp.c
@@ -20,7 +20,7 @@
#if HAVE_SECCOMP
-static int seccomp_add_default_syscall_filter(
+static int add_syscall_filters(
scmp_filter_ctx ctx,
uint32_t arch,
uint64_t cap_list_retain,
@@ -140,6 +140,7 @@ static int seccomp_add_default_syscall_filter(
*/
};
+ _cleanup_strv_free_ char **added = NULL;
int r;
size_t i;
char **p;
@@ -153,18 +154,25 @@ static int seccomp_add_default_syscall_filter(
SCMP_ACT_ALLOW,
syscall_blacklist,
false,
- NULL);
+ &added);
if (r < 0)
return log_error_errno(r, "Failed to add syscall filter item %s: %m", whitelist[i].name);
}
STRV_FOREACH(p, syscall_whitelist) {
- r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false, NULL);
+ r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true, &added);
if (r < 0)
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
*p, seccomp_arch_to_string(arch));
}
+ /* The default action is ENOSYS. Respond with EPERM to all other "known" but not allow-listed
+ * syscalls. */
+ r = seccomp_add_syscall_filter_item(ctx, "@known", SCMP_ACT_ERRNO(EPERM), added, true, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add rule for @known set on %s, ignoring: %m",
+ seccomp_arch_to_string(arch));
+
return 0;
}
@@ -182,11 +190,13 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **sys
log_debug("Applying whitelist on architecture: %s", seccomp_arch_to_string(arch));
- r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(EPERM));
+ /* We install ENOSYS as the default action, but it will only apply to syscalls which are not
+ * in the @known set, see above. */
+ r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(ENOSYS));
if (r < 0)
return log_error_errno(r, "Failed to allocate seccomp object: %m");
- r = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain, syscall_whitelist, syscall_blacklist);
+ r = add_syscall_filters(seccomp, arch, cap_list_retain, syscall_whitelist, syscall_blacklist);
if (r < 0)
return r;

View File

@ -0,0 +1,75 @@
From 33305c6801c10b741b11a3f329dc339d2e8c5514 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Thu, 18 Aug 2022 16:35:23 +0200
Subject: [PATCH] test-procfs-util: skip test on certain errors
Inspired by upstream bf47f71c1c
RHEL-only
Related: #2087152
---
src/shared/tests.c | 12 ++++++++++++
src/shared/tests.h | 2 ++
src/test/test-procfs-util.c | 6 ++++--
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/shared/tests.c b/src/shared/tests.c
index 1da80d653f..b1c71b992f 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -78,6 +78,18 @@ void test_setup_logging(int level) {
log_open();
}
+int log_tests_skipped(const char *message) {
+ log_notice("%s: %s, skipping tests.",
+ program_invocation_short_name, message);
+ return EXIT_TEST_SKIP;
+}
+
+int log_tests_skipped_errno(int r, const char *message) {
+ log_notice_errno(r, "%s: %s, skipping tests: %m",
+ program_invocation_short_name, message);
+ return EXIT_TEST_SKIP;
+}
+
const char *ci_environment(void) {
/* We return a string because we might want to provide multiple bits of information later on: not
* just the general CI environment type, but also whether we're sanitizing or not, etc. The caller is
diff --git a/src/shared/tests.h b/src/shared/tests.h
index 4f8f349097..d50711338c 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -5,6 +5,8 @@ char* setup_fake_runtime_dir(void);
bool test_is_running_from_builddir(char **exedir);
const char* get_testdata_dir(void);
void test_setup_logging(int level);
+int log_tests_skipped(const char *message);
+int log_tests_skipped_errno(int r, const char *message);
/* Provide a convenient way to check if we're running in CI. */
const char *ci_environment(void);
diff --git a/src/test/test-procfs-util.c b/src/test/test-procfs-util.c
index d656c4df4f..aba5692e54 100644
--- a/src/test/test-procfs-util.c
+++ b/src/test/test-procfs-util.c
@@ -7,6 +7,7 @@
#include "procfs-util.h"
#include "process-util.h"
#include "util.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_BYTES_MAX)];
@@ -52,8 +53,9 @@ int main(int argc, char *argv[]) {
log_info("Reducing limit by one to %"PRIu64"…", v-1);
r = procfs_tasks_set_limit(v-1);
- log_info_errno(r, "procfs_tasks_set_limit: %m");
- assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
+ if (IN_SET(r, -ENOENT, -EROFS) || ERRNO_IS_PRIVILEGE(r))
+ return log_tests_skipped_errno(r, "can't set tasks limit");
+ assert_se(r >= 0);
assert_se(procfs_get_threads_max(&w) >= 0);
assert_se(r >= 0 ? w == v - 1 : w == v);

View File

@ -0,0 +1,292 @@
From c7532112a37ffdd3cc9851ae04fdcb543b99ed1c Mon Sep 17 00:00:00 2001
From: Hubert Kario <hubert@kario.pl>
Date: Sun, 20 Sep 2020 18:59:58 +0200
Subject: [PATCH] Try stopping MD RAID devices in shutdown too
Currently the systemd-shutdown command attempts to stop swaps, DM
(crypt, LVM2) and loop devices, but it doesn't attempt to stop MD
RAID devices, which means that if the RAID is set up on crypt,
loop, etc. device, it won't be able to stop those underlying devices.
This code extends the shutdown application to also attempt stopping
the MD RAID devices.
Signed-off-by: Hubert Kario <hubert@kario.pl>
(cherry picked from commit 0b220a5f2a31844eaa1f5426bab02d41d54f471c)
Resolves: #1817706
---
src/core/shutdown.c | 37 +++++++++----
src/core/umount.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
src/core/umount.h | 2 +
3 files changed, 154 insertions(+), 10 deletions(-)
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 038345b752..b8a983986a 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -251,7 +251,7 @@ static void sync_with_progress(void) {
}
int main(int argc, char *argv[]) {
- bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
+ bool need_umount, need_swapoff, need_loop_detach, need_dm_detach, need_md_detach;
bool in_container, use_watchdog = false, can_initrd;
_cleanup_free_ char *cgroup = NULL;
char *arguments[3];
@@ -331,6 +331,7 @@ int main(int argc, char *argv[]) {
need_swapoff = !in_container;
need_loop_detach = !in_container;
need_dm_detach = !in_container;
+ need_md_detach = !in_container;
can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;
/* Unmount all mountpoints, swaps, and loopback devices */
@@ -383,6 +384,18 @@ int main(int argc, char *argv[]) {
log_error_errno(r, "Failed to detach loop devices: %m");
}
+ if (need_md_detach) {
+ log_info("Stopping MD devices.");
+ r = md_detach_all(&changed, umount_log_level);
+ if (r == 0) {
+ need_md_detach = false;
+ log_info("All MD devices stopped.");
+ } else if (r > 0)
+ log_info("Not all MD devices stopped, %d left.", r);
+ else
+ log_error_errno(r, "Failed to stop MD devices: %m");
+ }
+
if (need_dm_detach) {
log_info("Detaching DM devices.");
r = dm_detach_all(&changed, umount_log_level);
@@ -395,8 +408,9 @@ int main(int argc, char *argv[]) {
log_error_errno(r, "Failed to detach DM devices: %m");
}
- if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
- log_info("All filesystems, swaps, loop devices and DM devices detached.");
+ if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach
+ && !need_md_detach) {
+ log_info("All filesystems, swaps, loop devices, MD devices and DM devices detached.");
/* Yay, done */
break;
}
@@ -414,19 +428,21 @@ int main(int argc, char *argv[]) {
/* If in this iteration we didn't manage to
* unmount/deactivate anything, we simply give up */
if (!changed) {
- log_info("Cannot finalize remaining%s%s%s%s continuing.",
+ log_info("Cannot finalize remaining%s%s%s%s%s continuing.",
need_umount ? " file systems," : "",
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
- need_dm_detach ? " DM devices," : "");
+ need_dm_detach ? " DM devices," : "",
+ need_md_detach ? " MD devices," : "");
break;
}
- log_debug("Couldn't finalize remaining %s%s%s%s trying again.",
+ log_debug("Couldn't finalize remaining %s%s%s%s%s trying again.",
need_umount ? " file systems," : "",
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
- need_dm_detach ? " DM devices," : "");
+ need_dm_detach ? " DM devices," : "",
+ need_md_detach ? " MD devices," : "");
}
/* We're done with the watchdog. */
@@ -455,12 +471,13 @@ int main(int argc, char *argv[]) {
}
- if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
- log_error("Failed to finalize %s%s%s%s ignoring",
+ if (need_umount || need_swapoff || need_loop_detach || need_dm_detach || need_md_detach)
+ log_error("Failed to finalize%s%s%s%s%s ignoring.",
need_umount ? " file systems," : "",
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
- need_dm_detach ? " DM devices," : "");
+ need_dm_detach ? " DM devices," : "",
+ need_md_detach ? " MD devices," : "");
/* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
* sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
diff --git a/src/core/umount.c b/src/core/umount.c
index 3f02bf141a..ed90c6b1fc 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -5,6 +5,8 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/major.h>
+#include <linux/raid/md_u.h>
#include <linux/loop.h>
#include <string.h>
#include <sys/mount.h>
@@ -332,6 +334,66 @@ static int dm_list_get(MountPoint **head) {
return 0;
}
+static int md_list_get(MountPoint **head) {
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
+ struct udev_list_entry *item = NULL, *first = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
+ int r;
+
+ assert(head);
+
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+
+ e = udev_enumerate_new(udev);
+ if (!e)
+ return -ENOMEM;
+
+ r = udev_enumerate_add_match_subsystem(e, "block");
+ if (r < 0)
+ return r;
+
+ r = udev_enumerate_add_match_sysname(e, "md*");
+ if (r < 0)
+ return r;
+
+ first = udev_enumerate_get_list_entry(e);
+ udev_list_entry_foreach(item, first) {
+ _cleanup_(udev_device_unrefp) struct udev_device *d;
+ _cleanup_free_ char *p = NULL;
+ const char *dn;
+ MountPoint *m;
+ dev_t devnum;
+
+ d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
+ if (!d)
+ return -ENOMEM;
+
+ devnum = udev_device_get_devnum(d);
+ dn = udev_device_get_devnode(d);
+ if (major(devnum) == 0 || !dn)
+ continue;
+
+ p = strdup(dn);
+ if (!p)
+ return -ENOMEM;
+
+ m = new(MountPoint, 1);
+ if (!m)
+ return -ENOMEM;
+
+ *m = (MountPoint) {
+ .path = TAKE_PTR(p),
+ .devnum = devnum,
+ };
+
+ LIST_PREPEND(mount_point, *head, m);
+ }
+
+ return 0;
+}
+
static int delete_loopback(const char *device) {
_cleanup_close_ int fd = -1;
int r;
@@ -379,6 +441,23 @@ static int delete_dm(dev_t devnum) {
return 0;
}
+static int delete_md(MountPoint *m) {
+
+ _cleanup_close_ int fd = -1;
+
+ assert(major(m->devnum) != 0);
+ assert(m->path != 0);
+
+ fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
+ if (fd < 0)
+ return -errno;
+
+ if (ioctl(fd, STOP_ARRAY, NULL) < 0)
+ return -errno;
+
+ return 0;
+}
+
static bool nonunmountable_path(const char *path) {
return path_equal(path, "/")
#if ! HAVE_SPLIT_USR
@@ -618,6 +697,37 @@ static int dm_points_list_detach(MountPoint **head, bool *changed, int umount_lo
return n_failed;
}
+static int md_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
+ MountPoint *m, *n;
+ int n_failed = 0, r;
+ dev_t rootdev = 0;
+
+ assert(head);
+ assert(changed);
+
+ (void) get_block_device("/", &rootdev);
+
+ LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+ if (major(rootdev) != 0 && rootdev == m->devnum) {
+ n_failed ++;
+ continue;
+ }
+
+ log_info("Stopping MD %s (%u:%u).", m->path, major(m->devnum), minor(m->devnum));
+ r = delete_md(m);
+ if (r < 0) {
+ log_full_errno(umount_log_level, r, "Could not stop MD %s: %m", m->path);
+ n_failed++;
+ continue;
+ }
+
+ *changed = true;
+ mount_point_free(head, m);
+ }
+
+ return n_failed;
+}
+
static int umount_all_once(bool *changed, int umount_log_level) {
int r;
_cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
@@ -696,3 +806,18 @@ int dm_detach_all(bool *changed, int umount_log_level) {
return dm_points_list_detach(&dm_list_head, changed, umount_log_level);
}
+
+int md_detach_all(bool *changed, int umount_log_level) {
+ _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, md_list_head);
+ int r;
+
+ assert(changed);
+
+ LIST_HEAD_INIT(md_list_head);
+
+ r = md_list_get(&md_list_head);
+ if (r < 0)
+ return r;
+
+ return md_points_list_detach(&md_list_head, changed, umount_log_level);
+}
diff --git a/src/core/umount.h b/src/core/umount.h
index 6f2b24d195..b01062484f 100644
--- a/src/core/umount.h
+++ b/src/core/umount.h
@@ -15,6 +15,8 @@ int loopback_detach_all(bool *changed, int umount_log_level);
int dm_detach_all(bool *changed, int umount_log_level);
+int md_detach_all(bool *changed, int umount_log_level);
+
/* This is exported just for testing */
typedef struct MountPoint {
char *path;

View File

@ -0,0 +1,70 @@
From ebb3e759bba99ea85b3be9608258d6a5bb7e907a Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Tue, 29 Mar 2022 12:49:54 +0200
Subject: [PATCH] shutdown: get only active md arrays.
Current md_list_get() implementation filters all block devices, started from
"md*". This is ambiguous because list could contain:
- partitions created upon md device (mdXpY)
- external metadata container- specific type of md array.
For partitions there is no issue, because they aren't handle STOP_ARRAY
ioctl sent later. It generates misleading errors only.
Second case is more problematic because containers are not locked in kernel.
They are stopped even if container member array is active. For that reason
reboot or shutdown flow could be blocked because metadata manager cannot be
restarted after switch root on shutdown.
Add filters to remove partitions and containers from md_list. Partitions
can be excluded by DEVTYPE. Containers are determined by MD_LEVEL
property, we are excluding all with "container" value.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
(cherry picked from commit 3a3b022d2cc112803ea7b9beea98bbcad110368a)
Related: #1817706
---
src/core/umount.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/core/umount.c b/src/core/umount.c
index ed90c6b1fc..b513e91c4d 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -358,11 +358,16 @@ static int md_list_get(MountPoint **head) {
if (r < 0)
return r;
+ /* Filter out partitions. */
+ r = udev_enumerate_add_match_property(e, "DEVTYPE", "disk");
+ if (r < 0)
+ return r;
+
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
_cleanup_(udev_device_unrefp) struct udev_device *d;
_cleanup_free_ char *p = NULL;
- const char *dn;
+ const char *dn, *md_level;
MountPoint *m;
dev_t devnum;
@@ -375,6 +380,17 @@ static int md_list_get(MountPoint **head) {
if (major(devnum) == 0 || !dn)
continue;
+ md_level = udev_device_get_property_value(d, "MD_LEVEL");
+ if (!m) {
+ log_warning("Failed to get MD_LEVEL property for %s, ignoring", dn);
+ continue;
+ }
+
+ /* MD "containers" are a special type of MD devices, used for external metadata.
+ * Since it doesn't provide RAID functionality in itself we don't need to stop it. */
+ if (streq(md_level, "container"))
+ continue;
+
p = strdup(dn);
if (!p)
return -ENOMEM;

View File

@ -0,0 +1,347 @@
From 5b5571de21d1ddf9a00511a6b2f25d630a903f05 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 1 Jun 2022 10:15:06 +0200
Subject: [PATCH] scope: allow unprivileged delegation on scopes
Previously it was possible to set delegate property for scope, but you
were not able to allow unprivileged process to manage the scope's cgroup
hierarchy. This is useful when launching manager process that will run
unprivileged but is supposed to manage its own (scope) sub-hierarchy.
Fixes #21683
(cherry picked from commit 03860190fefce8bbea3a6f0e77919b882ade517c)
Resolves: #2068575
---
src/basic/unit-def.c | 1 +
src/basic/unit-def.h | 1 +
src/core/dbus-scope.c | 6 ++
src/core/scope.c | 135 +++++++++++++++++++++++++----
src/core/scope.h | 3 +
src/shared/bus-unit-util.c | 5 ++
test/TEST-19-DELEGATE/testsuite.sh | 13 +++
7 files changed, 145 insertions(+), 19 deletions(-)
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index e79cc73dd3..16c4d38d41 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -160,6 +160,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = "dead",
+ [SCOPE_START_CHOWN] = "start-chown",
[SCOPE_RUNNING] = "running",
[SCOPE_ABANDONED] = "abandoned",
[SCOPE_STOP_SIGTERM] = "stop-sigterm",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index 8eea379a6d..03d151ec19 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -99,6 +99,7 @@ typedef enum PathState {
typedef enum ScopeState {
SCOPE_DEAD,
+ SCOPE_START_CHOWN,
SCOPE_RUNNING,
SCOPE_ABANDONED,
SCOPE_STOP_SIGTERM,
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index 0bbf64fff1..534302d188 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -178,6 +178,12 @@ int bus_scope_set_property(
r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
if (r != 0)
return r;
+
+ if (streq(name, "User"))
+ return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
+
+ if (streq(name, "Group"))
+ return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
}
return 0;
diff --git a/src/core/scope.c b/src/core/scope.c
index 5a595c65a6..9cc5f89099 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -5,6 +5,8 @@
#include "alloc-util.h"
#include "dbus-scope.h"
+#include "dbus-unit.h"
+#include "exit-status.h"
#include "load-dropin.h"
#include "log.h"
#include "scope.h"
@@ -14,9 +16,11 @@
#include "strv.h"
#include "unit-name.h"
#include "unit.h"
+#include "user-util.h"
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = UNIT_INACTIVE,
+ [SCOPE_START_CHOWN] = UNIT_ACTIVATING,
[SCOPE_RUNNING] = UNIT_ACTIVE,
[SCOPE_ABANDONED] = UNIT_ACTIVE,
[SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -34,6 +38,7 @@ static void scope_init(Unit *u) {
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
u->ignore_on_isolate = true;
+ s->user = s->group = NULL;
}
static void scope_done(Unit *u) {
@@ -45,6 +50,9 @@ static void scope_done(Unit *u) {
s->controller_track = sd_bus_track_unref(s->controller_track);
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
+
+ s->user = mfree(s->user);
+ s->group = mfree(s->group);
}
static int scope_arm_timer(Scope *s, usec_t usec) {
@@ -84,7 +92,7 @@ static void scope_set_state(Scope *s, ScopeState state) {
old_state = s->state;
s->state = state;
- if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
+ if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN))
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED)) {
@@ -301,26 +309,72 @@ fail:
scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
}
-static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
+static int scope_enter_start_chown(Scope *s) {
+ Unit *u = UNIT(s);
+ pid_t pid;
int r;
assert(s);
+ assert(s->user);
- if (unit_has_name(u, SPECIAL_INIT_SCOPE))
- return -EPERM;
+ r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), u->manager->default_timeout_start_usec));
+ if (r < 0)
+ return r;
- if (s->state == SCOPE_FAILED)
- return -EPERM;
+ r = unit_fork_helper_process(u, "(sd-chown-cgroup)", &pid);
+ if (r < 0)
+ goto fail;
- /* We can't fulfill this right now, please try again later */
- if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
- return -EAGAIN;
+ if (r == 0) {
+ uid_t uid = UID_INVALID;
+ gid_t gid = GID_INVALID;
- assert(s->state == SCOPE_DEAD);
+ if (!isempty(s->user)) {
+ const char *user = s->user;
- if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
- return -ENOENT;
+ r = get_user_creds(&user, &uid, &gid, NULL, NULL);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve user \"%s\": %m", user);
+ _exit(EXIT_USER);
+ }
+ }
+
+ if (!isempty(s->group)) {
+ const char *group = s->group;
+
+ r = get_group_creds(&group, &gid);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve group \"%s\": %m", group);
+ _exit(EXIT_GROUP);
+ }
+ }
+
+ r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, uid, gid);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to adjust control group access: %m");
+ _exit(EXIT_CGROUP);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = unit_watch_pid(UNIT(s), pid, true);
+ if (r < 0)
+ goto fail;
+
+ scope_set_state(s, SCOPE_START_CHOWN);
+
+ return 1;
+fail:
+ s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
+ return r;
+}
+
+static int scope_enter_running(Scope *s) {
+ Unit *u = UNIT(s);
+ int r;
+
+ assert(s);
(void) bus_scope_track_controller(s);
@@ -328,11 +382,7 @@ static int scope_start(Unit *u) {
if (r < 0)
return r;
- (void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_accounting(u);
- (void) unit_reset_ip_accounting(u);
-
- unit_export_state_files(UNIT(s));
+ unit_export_state_files(u);
r = unit_attach_pids_to_cgroup(u, UNIT(s)->pids, NULL);
if (r < 0) {
@@ -350,6 +400,38 @@ static int scope_start(Unit *u) {
return 1;
}
+static int scope_start(Unit *u) {
+ Scope *s = SCOPE(u);
+
+ assert(s);
+
+ if (unit_has_name(u, SPECIAL_INIT_SCOPE))
+ return -EPERM;
+
+ if (s->state == SCOPE_FAILED)
+ return -EPERM;
+
+ /* We can't fulfill this right now, please try again later */
+ if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
+ return -EAGAIN;
+
+ assert(s->state == SCOPE_DEAD);
+
+ if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
+ return -ENOENT;
+
+ (void) unit_realize_cgroup(u);
+ (void) unit_reset_cpu_accounting(u);
+ (void) unit_reset_ip_accounting(u);
+
+ /* We check only for User= option to keep behavior consistent with logic for service units,
+ * i.e. having 'Delegate=true Group=foo' w/o specifing User= has no effect. */
+ if (s->user && unit_cgroup_delegate(u))
+ return scope_enter_start_chown(s);
+
+ return scope_enter_running(s);
+}
+
static int scope_stop(Unit *u) {
Scope *s = SCOPE(u);
@@ -462,7 +544,17 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
}
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- assert(u);
+ Scope *s = SCOPE(u);
+
+ assert(s);
+
+ if (s->state == SCOPE_START_CHOWN) {
+ if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
+ scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
+ else
+ scope_enter_running(s);
+ return;
+ }
/* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to
* watch, under the assumption that we'll sooner or later get a SIGCHLD for them, as the original
@@ -495,6 +587,11 @@ static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *user
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
break;
+ case SCOPE_START_CHOWN:
+ log_unit_warning(UNIT(s), "User lookup timed out. Entering failed state.");
+ scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
+ break;
+
default:
assert_not_reached("Timeout at wrong time.");
}
diff --git a/src/core/scope.h b/src/core/scope.h
index c38afb5e5d..7bed3eed9e 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -32,6 +32,9 @@ struct Scope {
bool was_abandoned;
sd_event_source *timer_event_source;
+
+ char *user;
+ char *group;
};
extern const UnitVTable scope_vtable;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 3910dfa812..c475bbafe0 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1615,6 +1615,11 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const
return bus_append_parse_sec_rename(m, field, eq);
+ /* Scope units don't have execution context but we still want to allow setting these two,
+ * so let's handle them separately. */
+ if (STR_IN_SET(field, "User", "Group"))
+ return bus_append_string(m, field, eq);
+
if (streq(field, "StartLimitBurst"))
return bus_append_safe_atou(m, field, eq);
diff --git a/test/TEST-19-DELEGATE/testsuite.sh b/test/TEST-19-DELEGATE/testsuite.sh
index c738bea10e..c4c948cc11 100755
--- a/test/TEST-19-DELEGATE/testsuite.sh
+++ b/test/TEST-19-DELEGATE/testsuite.sh
@@ -4,6 +4,16 @@
set -ex
set -o pipefail
+test_scope_unpriv_delegation() {
+ useradd test ||:
+ trap "userdel -r test" RETURN
+
+ systemd-run --uid=test -p User=test -p Delegate=yes --slice workload.slice --unit workload0.scope --scope \
+ test -w /sys/fs/cgroup/workload.slice/workload0.scope -a \
+ -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.procs -a \
+ -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.subtree_control
+}
+
if grep -q cgroup2 /proc/filesystems ; then
systemd-run --wait --unit=test0.service -p "DynamicUser=1" -p "Delegate=" \
test -w /sys/fs/cgroup/system.slice/test0.service/ -a \
@@ -15,6 +25,9 @@ if grep -q cgroup2 /proc/filesystems ; then
systemd-run --wait --unit=test2.service -p "DynamicUser=1" -p "Delegate=memory pids" \
grep pids /sys/fs/cgroup/system.slice/test2.service/cgroup.controllers
+
+ # Check that unprivileged delegation works for scopes
+ test_scope_unpriv_delegation
else
echo "Skipping TEST-19-DELEGATE, as the kernel doesn't actually support cgroupsv2" >&2
fi

View File

@ -0,0 +1,39 @@
From 3f3b00c8753fb591a4cd7b770ce069d455dcc4d6 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 4 Dec 2018 22:13:39 +0100
Subject: [PATCH] resolved: pin stream while calling callbacks for it
These callbacks might unref the stream, but we still have to access it,
let's hence ref it explicitly.
Maybe fixes: #10725
(cherry picked from commit d973d94dec349fb676fdd844f6fe2ada3538f27c)
Resolves: #2110549
---
src/resolve/resolved-dns-stream.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 555e200a23..ca0313d1d7 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -42,6 +42,8 @@ static int dns_stream_update_io(DnsStream *s) {
}
static int dns_stream_complete(DnsStream *s, int error) {
+ _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */
+
assert(s);
#if ENABLE_DNS_OVER_TLS
@@ -316,7 +318,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
}
static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- DnsStream *s = userdata;
+ _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
int r;
assert(s);

View File

@ -0,0 +1,28 @@
From 10758905f159bbe87a10f185f7e9afefbbd21fd4 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 26 Aug 2022 13:06:42 +0200
Subject: [PATCH] ci(functions): Add `useradd` and `userdel`
Inspired by upstream commit:
https://github.com/systemd/systemd/commit/9c94ab0f6ff22da4278a6e9a93ddc480607c55ac
RHEL-only
Related: #2110549
---
test/test-functions | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/test-functions b/test/test-functions
index ed8ab98173..19363be858 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -23,7 +23,7 @@ fi
PATH_TO_INIT=$ROOTLIBDIR/systemd
-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs env mktemp mountpoint useradd userdel"
DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"

View File

@ -0,0 +1,377 @@
From d897789b4dc7d115c915842eabf33ed3de20110a Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 7 Aug 2018 13:49:34 +0200
Subject: [PATCH] logind: optionally watch utmp for login data
This allows us to determine the TTY an ssh session is for, which is
useful to to proper idle detection for ssh sessions.
Fixes: #9622
(cherry picked from commit 3d0ef5c7e00155bc74f6f71c34cad518a4ff56ba)
Related: #2122288
---
src/login/logind-core.c | 143 +++++++++++++++++++++++++++++++++++++
src/login/logind-dbus.c | 5 ++
src/login/logind-session.c | 24 +++++++
src/login/logind-session.h | 14 +++-
src/login/logind.c | 10 +++
src/login/logind.h | 8 +++
6 files changed, 203 insertions(+), 1 deletion(-)
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 0ed812a2c8..7e33f8e6aa 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -5,6 +5,9 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/vt.h>
+#if ENABLE_UTMP
+#include <utmpx.h>
+#endif
#include "alloc-util.h"
#include "bus-error.h"
@@ -14,6 +17,7 @@
#include "fd-util.h"
#include "logind.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "strv.h"
#include "terminal-util.h"
@@ -692,3 +696,142 @@ bool manager_all_buttons_ignored(Manager *m) {
return true;
}
+
+int manager_read_utmp(Manager *m) {
+#if ENABLE_UTMP
+ int r;
+
+ assert(m);
+
+ if (utmpxname(_PATH_UTMPX) < 0)
+ return log_error_errno(errno, "Failed to set utmp path to " _PATH_UTMPX ": %m");
+
+ setutxent();
+
+ for (;;) {
+ _cleanup_free_ char *t = NULL;
+ struct utmpx *u;
+ const char *c;
+ Session *s;
+
+ errno = 0;
+ u = getutxent();
+ if (!u) {
+ if (errno != 0)
+ log_warning_errno(errno, "Failed to read " _PATH_UTMPX ", ignoring: %m");
+ r = 0;
+ break;
+ }
+
+ if (u->ut_type != USER_PROCESS)
+ continue;
+
+ if (!pid_is_valid(u->ut_pid))
+ continue;
+
+ t = strndup(u->ut_line, sizeof(u->ut_line));
+ if (!t) {
+ r = log_oom();
+ break;
+ }
+
+ c = path_startswith(t, "/dev/");
+ if (c) {
+ r = free_and_strdup(&t, c);
+ if (r < 0) {
+ log_oom();
+ break;
+ }
+ }
+
+ if (isempty(t))
+ continue;
+
+ s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(u->ut_pid));
+ if (!s)
+ continue;
+
+ if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) {
+ /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In
+ * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY
+ * information and never acquire it again. */
+
+ s->tty = mfree(s->tty);
+ s->tty_validity = TTY_UTMP_INCONSISTENT;
+ log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id);
+ continue;
+ }
+
+ /* Never override what we figured out once */
+ if (s->tty || s->tty_validity >= 0)
+ continue;
+
+ s->tty = TAKE_PTR(t);
+ s->tty_validity = TTY_FROM_UTMP;
+ log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id);
+ }
+
+ endutxent();
+ return r;
+#else
+ return 0
+#endif
+}
+
+#if ENABLE_UTMP
+static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) {
+ Manager *m = userdata;
+
+ assert(m);
+
+ /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's
+ * reestablish the watch on whatever there's now. */
+ if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0)
+ manager_connect_utmp(m);
+
+ (void) manager_read_utmp(m);
+ return 0;
+}
+#endif
+
+void manager_connect_utmp(Manager *m) {
+#if ENABLE_UTMP
+ sd_event_source *s = NULL;
+ int r;
+
+ assert(m);
+
+ /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM
+ * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known
+ * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and
+ * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry.
+ *
+ * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle
+ * detection (which, for tty sessions, relies on the TTY used) */
+
+ r = sd_event_add_inotify(m->event, &s, _PATH_UTMPX, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m);
+ if (r < 0)
+ log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " _PATH_UTMPX ", ignoring: %m");
+ else {
+ r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m");
+
+ (void) sd_event_source_set_description(s, "utmp");
+ }
+
+ sd_event_source_unref(m->utmp_event_source);
+ m->utmp_event_source = s;
+#endif
+}
+
+void manager_reconnect_utmp(Manager *m) {
+#if ENABLE_UTMP
+ assert(m);
+
+ if (m->utmp_event_source)
+ return;
+
+ manager_connect_utmp(m);
+#endif
+}
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 1bb152bc20..0248042308 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -772,6 +772,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
} while (hashmap_get(m->sessions, id));
}
+ /* If we are not watching utmp aleady, try again */
+ manager_reconnect_utmp(m);
+
r = manager_add_user_by_uid(m, uid, &user);
if (r < 0)
goto fail;
@@ -795,6 +798,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
r = -ENOMEM;
goto fail;
}
+
+ session->tty_validity = TTY_FROM_PAM;
}
if (!isempty(display)) {
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 1143a834a4..d666f86d3f 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -56,6 +56,7 @@ int session_new(Session **ret, Manager *m, const char *id) {
.fifo_fd = -1,
.vtfd = -1,
.audit_id = AUDIT_SESSION_INVALID,
+ .tty_validity = _TTY_VALIDITY_INVALID,
};
s->state_file = strappend("/run/systemd/sessions/", id);
@@ -219,6 +220,9 @@ int session_save(Session *s) {
if (s->tty)
fprintf(f, "TTY=%s\n", s->tty);
+ if (s->tty_validity >= 0)
+ fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
+
if (s->display)
fprintf(f, "DISPLAY=%s\n", s->display);
@@ -355,6 +359,7 @@ static int session_load_devices(Session *s, const char *devices) {
int session_load(Session *s) {
_cleanup_free_ char *remote = NULL,
*seat = NULL,
+ *tty_validity = NULL,
*vtnr = NULL,
*state = NULL,
*position = NULL,
@@ -380,6 +385,7 @@ int session_load(Session *s) {
"FIFO", &s->fifo_path,
"SEAT", &seat,
"TTY", &s->tty,
+ "TTY_VALIDITY", &tty_validity,
"DISPLAY", &s->display,
"REMOTE_HOST", &s->remote_host,
"REMOTE_USER", &s->remote_user,
@@ -456,6 +462,16 @@ int session_load(Session *s) {
seat_claim_position(s->seat, s, npos);
}
+ if (tty_validity) {
+ TTYValidity v;
+
+ v = tty_validity_from_string(tty_validity);
+ if (v < 0)
+ log_debug("Failed to parse TTY validity: %s", tty_validity);
+ else
+ s->tty_validity = v;
+ }
+
if (leader) {
if (parse_pid(leader, &s->leader) >= 0)
(void) audit_session_from_pid(s->leader, &s->audit_id);
@@ -1368,3 +1384,11 @@ static const char* const kill_who_table[_KILL_WHO_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
+
+static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
+ [TTY_FROM_PAM] = "from-pam",
+ [TTY_FROM_UTMP] = "from-utmp",
+ [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 9bd0c96a03..7da845cea3 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -46,6 +46,14 @@ enum KillWho {
_KILL_WHO_INVALID = -1
};
+typedef enum TTYValidity {
+ TTY_FROM_PAM,
+ TTY_FROM_UTMP,
+ TTY_UTMP_INCONSISTENT, /* may happen on ssh sessions with multiplexed TTYs */
+ _TTY_VALIDITY_MAX,
+ _TTY_VALIDITY_INVALID = -1,
+} TTYValidity;
+
struct Session {
Manager *manager;
@@ -60,8 +68,9 @@ struct Session {
dual_timestamp timestamp;
- char *tty;
char *display;
+ char *tty;
+ TTYValidity tty_validity;
bool remote;
char *remote_user;
@@ -159,6 +168,9 @@ SessionClass session_class_from_string(const char *s) _pure_;
const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
+const char* tty_validity_to_string(TTYValidity t) _const_;
+TTYValidity tty_validity_from_string(const char *s) _pure_;
+
int session_prepare_vt(Session *s);
void session_restore_vt(Session *s);
void session_leave_vt(Session *s);
diff --git a/src/login/logind.c b/src/login/logind.c
index 6c208c8e89..25de9a6ab2 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -132,6 +132,10 @@ static Manager* manager_unref(Manager *m) {
sd_event_source_unref(m->udev_button_event_source);
sd_event_source_unref(m->lid_switch_ignore_event_source);
+#if ENABLE_UTMP
+ sd_event_source_unref(m->utmp_event_source);
+#endif
+
safe_close(m->console_active_fd);
udev_monitor_unref(m->udev_seat_monitor);
@@ -1095,6 +1099,9 @@ static int manager_startup(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to register SIGHUP handler: %m");
+ /* Connect to utmp */
+ manager_connect_utmp(m);
+
/* Connect to console */
r = manager_connect_console(m);
if (r < 0)
@@ -1150,6 +1157,9 @@ static int manager_startup(Manager *m) {
/* Reserve the special reserved VT */
manager_reserve_vt(m);
+ /* Read in utmp if it exists */
+ manager_read_utmp(m);
+
/* And start everything */
HASHMAP_FOREACH(seat, m->seats, i)
seat_start(seat);
diff --git a/src/login/logind.h b/src/login/logind.h
index d29b01c75b..bb127bf4a5 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -43,6 +43,10 @@ struct Manager {
sd_event_source *udev_vcsa_event_source;
sd_event_source *udev_button_event_source;
+#if ENABLE_UTMP
+ sd_event_source *utmp_event_source;
+#endif
+
int console_active_fd;
unsigned n_autovts;
@@ -150,6 +154,10 @@ bool manager_is_docked_or_external_displays(Manager *m);
bool manager_is_on_external_power(void);
bool manager_all_buttons_ignored(Manager *m);
+int manager_read_utmp(Manager *m);
+void manager_connect_utmp(Manager *m);
+void manager_reconnect_utmp(Manager *m);
+
extern const sd_bus_vtable manager_vtable[];
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);

View File

@ -0,0 +1,188 @@
From fbc394252588325b6e7ecd1ab65ad40b51763c58 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 7 Aug 2018 12:08:24 +0200
Subject: [PATCH] logind: add hashtable for finding session by leader PID
This is useful later on, when we quickly want to find the session for a
leader PID.
(cherry picked from commit 238794b15082e6f61d0ce2943d39205289fff7f0)
Related: #2122288
---
src/login/logind-core.c | 15 ++++++++------
src/login/logind-dbus.c | 3 +--
src/login/logind-session.c | 41 +++++++++++++++++++++++++++++++++++---
src/login/logind-session.h | 1 +
src/login/logind.c | 4 +++-
src/login/logind.h | 1 +
6 files changed, 53 insertions(+), 12 deletions(-)
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 7e33f8e6aa..a1943b6f9d 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -339,13 +339,16 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **ret) {
if (!pid_is_valid(pid))
return -EINVAL;
- r = cg_pid_get_unit(pid, &unit);
- if (r < 0)
- goto not_found;
+ s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(pid));
+ if (!s) {
+ r = cg_pid_get_unit(pid, &unit);
+ if (r < 0)
+ goto not_found;
- s = hashmap_get(m->session_units, unit);
- if (!s)
- goto not_found;
+ s = hashmap_get(m->session_units, unit);
+ if (!s)
+ goto not_found;
+ }
if (ret)
*ret = s;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 0248042308..01bfef4ff7 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -784,9 +784,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
goto fail;
session_set_user(session, user);
+ session_set_leader(session, leader);
- session->leader = leader;
- session->audit_id = audit_id;
session->type = t;
session->class = c;
session->remote = remote;
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index d666f86d3f..cc838ca383 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -121,6 +121,9 @@ Session* session_free(Session *s) {
free(s->scope);
}
+ if (pid_is_valid(s->leader))
+ (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
+
free(s->scope_job);
sd_bus_message_unref(s->create_message);
@@ -149,6 +152,30 @@ void session_set_user(Session *s, User *u) {
user_update_last_session_timer(u);
}
+int session_set_leader(Session *s, pid_t pid) {
+ int r;
+
+ assert(s);
+
+ if (!pid_is_valid(pid))
+ return -EINVAL;
+
+ if (s->leader == pid)
+ return 0;
+
+ r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
+ if (r < 0)
+ return r;
+
+ if (pid_is_valid(s->leader))
+ (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
+
+ s->leader = pid;
+ (void) audit_session_from_pid(pid, &s->audit_id);
+
+ return 1;
+}
+
static void session_save_devices(Session *s, FILE *f) {
SessionDevice *sd;
Iterator i;
@@ -473,8 +500,16 @@ int session_load(Session *s) {
}
if (leader) {
- if (parse_pid(leader, &s->leader) >= 0)
- (void) audit_session_from_pid(s->leader, &s->audit_id);
+ pid_t pid;
+
+ r = parse_pid(leader, &pid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
+ else {
+ r = session_set_leader(s, pid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
+ }
}
if (type) {
@@ -910,7 +945,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
/* For sessions with a leader but no explicitly configured
* tty, let's check the controlling tty of the leader */
- if (s->leader > 0) {
+ if (pid_is_valid(s->leader)) {
r = get_process_ctty_atime(s->leader, &atime);
if (r >= 0)
goto found_atime;
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 7da845cea3..8c7d0301f2 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -124,6 +124,7 @@ Session* session_free(Session *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(Session *, session_free);
void session_set_user(Session *s, User *u);
+int session_set_leader(Session *s, pid_t pid);
bool session_may_gc(Session *s, bool drop_not_started);
void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);
diff --git a/src/login/logind.c b/src/login/logind.c
index 25de9a6ab2..6b576dad0d 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -46,6 +46,7 @@ static int manager_new(Manager **ret) {
m->devices = hashmap_new(&string_hash_ops);
m->seats = hashmap_new(&string_hash_ops);
m->sessions = hashmap_new(&string_hash_ops);
+ m->sessions_by_leader = hashmap_new(NULL);
m->users = hashmap_new(NULL);
m->inhibitors = hashmap_new(&string_hash_ops);
m->buttons = hashmap_new(&string_hash_ops);
@@ -53,7 +54,7 @@ static int manager_new(Manager **ret) {
m->user_units = hashmap_new(&string_hash_ops);
m->session_units = hashmap_new(&string_hash_ops);
- if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
+ if (!m->devices || !m->seats || !m->sessions || !m->sessions_by_leader || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
return -ENOMEM;
m->udev = udev_new();
@@ -112,6 +113,7 @@ static Manager* manager_unref(Manager *m) {
hashmap_free(m->devices);
hashmap_free(m->seats);
hashmap_free(m->sessions);
+ hashmap_free(m->sessions_by_leader);
hashmap_free(m->users);
hashmap_free(m->inhibitors);
hashmap_free(m->buttons);
diff --git a/src/login/logind.h b/src/login/logind.h
index bb127bf4a5..7f94dea2f6 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -26,6 +26,7 @@ struct Manager {
Hashmap *devices;
Hashmap *seats;
Hashmap *sessions;
+ Hashmap *sessions_by_leader;
Hashmap *users;
Hashmap *inhibitors;
Hashmap *buttons;

View File

@ -0,0 +1,93 @@
From 69ec7c9170e29fdf745fa282448d051edd1f88b2 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 9 Aug 2022 11:41:04 +0200
Subject: [PATCH] core/load-fragment: move config_parse_sec_fix_0 to src/shared
(cherry picked from commit 4ee8176fe33bbcd0971c4583a0e7d1cc2a64ac06)
Related: #2122288
---
src/core/load-fragment.c | 33 ---------------------------------
src/core/load-fragment.h | 1 -
src/shared/conf-parser.c | 2 ++
src/shared/conf-parser.h | 1 +
4 files changed, 3 insertions(+), 34 deletions(-)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index c0b1fd4f91..53de7ff5e9 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1865,39 +1865,6 @@ int config_parse_service_timeout(
return 0;
}
-int config_parse_sec_fix_0(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- usec_t *usec = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(usec);
-
- /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
- * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
- * timeout. */
-
- r = parse_sec_fix_0(rvalue, usec);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
- return 0;
- }
-
- return 0;
-}
-
int config_parse_user_group_compat(
const char *unit,
const char *filename,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index f9d34d484d..b964737f9e 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -95,7 +95,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bus_name);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_utmp_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_working_directory);
CONFIG_PARSER_PROTOTYPE(config_parse_fdname);
-CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0);
CONFIG_PARSER_PROTOTYPE(config_parse_user_group_compat);
CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv_compat);
CONFIG_PARSER_PROTOTYPE(config_parse_restrict_namespaces);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 1f40f00c72..414dde2e3d 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -1286,3 +1286,5 @@ int config_parse_permille(const char* unit,
return 0;
}
+
+DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t, "Failed to parse time value");
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 375b2e5a74..56fd302db8 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -142,6 +142,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
CONFIG_PARSER_PROTOTYPE(config_parse_join_controllers);
CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
+CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0);
typedef enum Disabled {
DISABLED_CONFIGURATION,

View File

@ -0,0 +1,123 @@
From 30f5836253f820086caa24fc9283344615b8fc00 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 28 Jul 2020 11:17:00 +0200
Subject: [PATCH] sd-event: add relative timer calls
We frequently want to set a timer relative to the current time. Let's
add an explicit API for this. This not only saves us a few lines of code
everywhere and simplifies things, but also allows us to do correct
overflow checking.
(cherry picked from commit d6a83dc48ad1981665ff427858ae8e59d4cfd6cb)
Related: #2122288
---
src/libsystemd/libsystemd.sym | 8 +++++-
src/libsystemd/sd-event/sd-event.c | 42 ++++++++++++++++++++++++++++++
src/systemd/sd-event.h | 2 ++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 3b55fc6473..449918093c 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -578,12 +578,18 @@ LIBSYSTEMD_240 {
sd_bus_get_method_call_timeout;
} LIBSYSTEMD_239;
+LIBSYSTEMD_247 {
+global:
+ sd_event_add_time_relative;
+ sd_event_source_set_time_relative;
+} LIBSYSTEMD_240;
+
LIBSYSTEMD_248 {
global:
sd_event_source_set_ratelimit;
sd_event_source_get_ratelimit;
sd_event_source_is_ratelimited;
-} LIBSYSTEMD_240;
+} LIBSYSTEMD_247;
LIBSYSTEMD_250 {
global:
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 09d4584bf9..2c9d331bf2 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -1415,6 +1415,31 @@ fail:
return r;
}
+_public_ int sd_event_add_time_relative(
+ sd_event *e,
+ sd_event_source **ret,
+ clockid_t clock,
+ uint64_t usec,
+ uint64_t accuracy,
+ sd_event_time_handler_t callback,
+ void *userdata) {
+
+ usec_t t;
+ int r;
+
+ /* Same as sd_event_add_time() but operates relative to the event loop's current point in time, and
+ * checks for overflow. */
+
+ r = sd_event_now(e, clock, &t);
+ if (r < 0)
+ return r;
+
+ if (usec >= USEC_INFINITY - t)
+ return -EOVERFLOW;
+
+ return sd_event_add_time(e, ret, clock, t + usec, accuracy, callback, userdata);
+}
+
static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
@@ -2578,6 +2603,23 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
return 0;
}
+_public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec) {
+ usec_t t;
+ int r;
+
+ assert_return(s, -EINVAL);
+ assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
+
+ r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
+ if (r < 0)
+ return r;
+
+ if (usec >= USEC_INFINITY - t)
+ return -EOVERFLOW;
+
+ return sd_event_source_set_time(s, t + usec);
+}
+
_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
assert_return(s, -EINVAL);
assert_return(usec, -EINVAL);
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index c2e9c9614d..960bea1ac4 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -87,6 +87,7 @@ sd_event* sd_event_unref(sd_event *e);
int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata);
int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
+int sd_event_add_time_relative(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
@@ -136,6 +137,7 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events);
int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents);
int sd_event_source_get_time(sd_event_source *s, uint64_t *usec);
int sd_event_source_set_time(sd_event_source *s, uint64_t usec);
+int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec);
int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec);
int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);

View File

@ -0,0 +1,233 @@
From 24439b08e3a3437b423553c385cde1d4cddf18f6 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 8 Aug 2022 09:13:50 +0200
Subject: [PATCH] logind: add option to stop idle sessions after specified
timeout
Thanks to Jan Pazdziora <jpazdziora@redhat.com> for providing a patch
which implemeted a PoC of this feature.
(cherry picked from commit 82325af3ae41bc7efb3d5cd8f56a4652fef498c2)
Resolves: #2122288
---
man/logind.conf.xml | 11 ++++++
src/login/logind-core.c | 2 +
src/login/logind-dbus.c | 1 +
src/login/logind-gperf.gperf | 1 +
src/login/logind-session.c | 72 +++++++++++++++++++++++++++++++++---
src/login/logind-session.h | 2 +
src/login/logind.conf.in | 1 +
src/login/logind.h | 2 +
8 files changed, 86 insertions(+), 6 deletions(-)
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index 0cf8a7d1f2..00b5b1f2e8 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -333,6 +333,17 @@
are excluded from the effect of this setting. Defaults to <literal>no</literal>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>StopIdleSessionSec=</varname></term>
+
+ <listitem><para>Specifies a timeout in seconds, or a time span value after which
+ <filename>systemd-logind</filename> checks the idle state of all sessions. Every session that is idle for
+ longer then the timeout will be stopped. Defaults to <literal>infinity</literal>
+ (<filename>systemd-logind</filename> is not checking the idle state of sessions). For details about the syntax
+ of time spans, see
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ </para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index a1943b6f9d..abe6eecffb 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -58,6 +58,8 @@ void manager_reset_config(Manager *m) {
m->kill_only_users = strv_free(m->kill_only_users);
m->kill_exclude_users = strv_free(m->kill_exclude_users);
+
+ m->stop_idle_session_usec = USEC_INFINITY;
}
int manager_parse_config_file(Manager *m) {
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 01bfef4ff7..81aacb4eed 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2720,6 +2720,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0),
SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("StopIdleSessionUSec", "t", NULL, offsetof(Manager, stop_idle_session_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_NAMES("GetSession",
"s",
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 8829ce7d85..214ac5c4a3 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -42,3 +42,4 @@ Login.RemoveIPC, config_parse_bool, 0, offse
Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max)
Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max)
Login.UserTasksMax, config_parse_compat_user_tasks_max, 0, offsetof(Manager, user_tasks_max)
+Login.StopIdleSessionSec, config_parse_sec_fix_0, 0, offsetof(Manager, stop_idle_session_usec)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index cc838ca383..56f40fbec4 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -29,6 +29,7 @@
#include "string-table.h"
#include "strv.h"
#include "terminal-util.h"
+#include "time-util.h"
#include "user-util.h"
#include "util.h"
@@ -139,6 +140,8 @@ Session* session_free(Session *s) {
free(s->state_file);
+ sd_event_source_unref(s->stop_on_idle_event_source);
+
return mfree(s);
}
@@ -658,6 +661,55 @@ static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_er
return 0;
}
+static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, void *userdata) {
+ Session *s = userdata;
+ dual_timestamp ts;
+ int r, idle;
+
+ assert(s);
+
+ if (s->stopping)
+ return 0;
+
+ idle = session_get_idle_hint(s, &ts);
+ if (idle) {
+ log_debug("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->name);
+
+ return session_stop(s, /* force */ true);
+ }
+
+ r = sd_event_source_set_time(source, usec_add(ts.monotonic, s->manager->stop_idle_session_usec));
+ if (r < 0)
+ return log_error_errno(r, "Failed to configure stop on idle session event source: %m");
+
+ r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable stop on idle session event source: %m");
+
+ return 1;
+}
+
+static int session_setup_stop_on_idle_timer(Session *s) {
+ int r;
+
+ assert(s);
+
+ if (s->manager->stop_idle_session_usec == USEC_INFINITY)
+ return 0;
+
+ r = sd_event_add_time_relative(
+ s->manager->event,
+ &s->stop_on_idle_event_source,
+ CLOCK_MONOTONIC,
+ s->manager->stop_idle_session_usec,
+ 0,
+ session_dispatch_stop_on_idle, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add stop on idle session event source: %m");
+
+ return 0;
+}
+
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
int r;
@@ -680,6 +732,10 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
if (r < 0)
return r;
+ r = session_setup_stop_on_idle_timer(s);
+ if (r < 0)
+ return r;
+
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
"SESSION_ID=%s", s->id,
@@ -917,7 +973,7 @@ static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
}
int session_get_idle_hint(Session *s, dual_timestamp *t) {
- usec_t atime = 0, n;
+ usec_t atime = 0, dtime = 0;
int r;
assert(s);
@@ -961,12 +1017,16 @@ found_atime:
if (t)
dual_timestamp_from_realtime(t, atime);
- n = now(CLOCK_REALTIME);
-
- if (s->manager->idle_action_usec <= 0)
- return 0;
+ if (s->manager->idle_action_usec > 0 && s->manager->stop_idle_session_usec != USEC_INFINITY)
+ dtime = MIN(s->manager->idle_action_usec, s->manager->stop_idle_session_usec);
+ else if (s->manager->idle_action_usec > 0)
+ dtime = s->manager->idle_action_usec;
+ else if (s->manager->stop_idle_session_usec != USEC_INFINITY)
+ dtime = s->manager->stop_idle_session_usec;
+ else
+ return false;
- return atime + s->manager->idle_action_usec <= n;
+ return usec_add(atime, dtime) <= now(CLOCK_REALTIME);
}
void session_set_idle_hint(Session *s, bool b) {
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 8c7d0301f2..6678441bb9 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -112,6 +112,8 @@ struct Session {
Hashmap *devices;
sd_bus_track *track;
+ sd_event_source *stop_on_idle_event_source;
+
LIST_FIELDS(Session, sessions_by_user);
LIST_FIELDS(Session, sessions_by_seat);
diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in
index c7346f9819..a62c2b0b57 100644
--- a/src/login/logind.conf.in
+++ b/src/login/logind.conf.in
@@ -35,3 +35,4 @@
#RemoveIPC=no
#InhibitorsMax=8192
#SessionsMax=8192
+#StopIdleSessionSec=infinity
diff --git a/src/login/logind.h b/src/login/logind.h
index 7f94dea2f6..606adf4fe6 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -102,6 +102,8 @@ struct Manager {
usec_t idle_action_not_before_usec;
HandleAction idle_action;
+ usec_t stop_idle_session_usec;
+
HandleAction handle_power_key;
HandleAction handle_suspend_key;
HandleAction handle_hibernate_key;

View File

@ -0,0 +1,29 @@
From e48edc1b923267a5fcc808c3eb7151bf460a68ba Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 9 Sep 2022 13:38:58 +0200
Subject: [PATCH] logind: schedule idle check full interval from now if we
couldn't figure out atime timestamp
(cherry picked from commit 6edf707fd59347024fa6be0342b108527825db1f)
Related: #2122288
---
src/login/logind-session.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 56f40fbec4..18a07efcdb 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -678,7 +678,10 @@ static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, vo
return session_stop(s, /* force */ true);
}
- r = sd_event_source_set_time(source, usec_add(ts.monotonic, s->manager->stop_idle_session_usec));
+ r = sd_event_source_set_time(
+ source,
+ usec_add(dual_timestamp_is_set(&ts) ? ts.monotonic : now(CLOCK_MONOTONIC),
+ s->manager->stop_idle_session_usec));
if (r < 0)
return log_error_errno(r, "Failed to configure stop on idle session event source: %m");

View File

@ -0,0 +1,59 @@
From 5f69ba3919d32ed93c68bb6b8b70a516f2bb56a8 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 16 Aug 2022 14:34:49 +0200
Subject: [PATCH] ci(lint): add shell linter - Differential ShellCheck
It performs differential ShellCheck scans and report results directly in
pull request.
documentation:
https://github.com/redhat-plumbers-in-action/differential-shellcheck
(inspired by commit
https://github.com/systemd/systemd/commit/3f3c718e79abdac698ae90de5cd4c0560a0a75d4)
RHEL-only
Related: #2122499
---
.github/workflows/differential-shellcheck.yml | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 .github/workflows/differential-shellcheck.yml
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
new file mode 100644
index 0000000000..fa94679b51
--- /dev/null
+++ b/.github/workflows/differential-shellcheck.yml
@@ -0,0 +1,31 @@
+---
+# https://github.com/redhat-plumbers-in-action/differential-shellcheck#readme
+
+name: Differential ShellCheck
+on:
+ pull_request:
+ branches:
+ - master
+ - rhel-8.*.0
+
+permissions:
+ contents: read
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+
+ permissions:
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Repository checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Differential ShellCheck
+ uses: redhat-plumbers-in-action/differential-shellcheck@v3
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,34 @@
From deb09b3bd826571149f6b018f3a3ff8a33cd104b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 28 Jun 2018 16:09:04 +0900
Subject: [PATCH] meson: do not compare objects of different types
This fixes the following warning:
```
meson.build:1140: WARNING: Trying to compare values of different types (DependencyHolder, list) using !=.
The result of this is undefined and will become a hard error in a future Meson release.
```
Follow-up for f02582f69fe1e7663a87ba80bd4f90d5d23ee75f(#9410).
(cherry picked from commit 48f5da19b6e8f0d05f5217bc9856093d354ce5d0)
Related: #2122499
---
meson.build | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index 6729a9ea5e..af4cf331da 100644
--- a/meson.build
+++ b/meson.build
@@ -1165,7 +1165,8 @@ substs.set('DEFAULT_DNSSEC_MODE', default_dnssec)
dns_over_tls = get_option('dns-over-tls')
if dns_over_tls != 'false'
- have = libgnutls != [] and libgnutls.version().version_compare('>=3.5.3')
+ have = (conf.get('HAVE_GNUTLS') == 1 and
+ libgnutls.version().version_compare('>=3.5.3'))
if dns_over_tls == 'true' and not have
error('DNS-over-TLS support was requested, but dependencies are not available')
endif

View File

@ -0,0 +1,48 @@
From ea9b3a664f5e67d0ee6b0bf6ca362835ae11fedc Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 20 Dec 2021 20:48:32 +0900
Subject: [PATCH] journal-remote: use MHD_HTTP_CONTENT_TOO_LARGE as
MHD_HTTP_PAYLOAD_TOO_LARGE is deprecated since 0.9.74
(cherry picked from commit 30df858f43b14a55c6650b43bea12cbf2cc0bc67)
Related: #2122499
---
src/journal-remote/journal-remote-main.c | 2 +-
src/journal-remote/microhttpd-util.h | 10 +++++++---
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index 47fe9d7433..bcaa370099 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -304,7 +304,7 @@ static int request_handler(
/* When serialized, an entry of maximum size might be slightly larger,
* so this does not correspond exactly to the limit in journald. Oh well.
*/
- return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
+ return mhd_respondf(connection, 0, MHD_HTTP_CONTENT_TOO_LARGE,
"Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
}
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index 26909082a1..dd0ca1d9bd 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -38,9 +38,13 @@
# define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE
#endif
-/* Renamed in µhttpd 0.9.53 */
-#ifndef MHD_HTTP_PAYLOAD_TOO_LARGE
-# define MHD_HTTP_PAYLOAD_TOO_LARGE MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
+/* Renamed in µhttpd 0.9.74 (8c644fc1f4d498ea489add8d40a68f5d3e5899fa) */
+#ifndef MHD_HTTP_CONTENT_TOO_LARGE
+# ifdef MHD_HTTP_PAYLOAD_TOO_LARGE
+# define MHD_HTTP_CONTENT_TOO_LARGE MHD_HTTP_PAYLOAD_TOO_LARGE /* 0.9.53 or newer */
+# else
+# define MHD_HTTP_CONTENT_TOO_LARGE MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
+# endif
#endif
#if MHD_VERSION < 0x00094203

View File

@ -0,0 +1,71 @@
From ca86de228e19cea268ec3eeabc9097d7c28fbf24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 30 Jun 2020 09:56:10 +0200
Subject: [PATCH] =?UTF-8?q?Fix=20build=20with=20=C2=B5httpd=200.9.71?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The return type of callbacks was changed from int to an enum.
(cherry picked from commit d17eabb1052e7c8c432331a7a782845e36164f01)
Related: #2122499
---
src/journal-remote/journal-gatewayd.c | 4 ++--
src/journal-remote/journal-remote-main.c | 2 +-
src/journal-remote/microhttpd-util.h | 6 ++++++
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 54446ff7b5..3ff05a4d72 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -338,7 +338,7 @@ static int request_parse_range(
return 0;
}
-static int request_parse_arguments_iterator(
+static mhd_result request_parse_arguments_iterator(
void *cls,
enum MHD_ValueKind kind,
const char *key,
@@ -795,7 +795,7 @@ static int request_handler_machine(
return MHD_queue_response(connection, MHD_HTTP_OK, response);
}
-static int request_handler(
+static mhd_result request_handler(
void *cls,
struct MHD_Connection *connection,
const char *url,
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index bcaa370099..a1008db6eb 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -241,7 +241,7 @@ static int process_http_upload(
return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.");
};
-static int request_handler(
+static mhd_result request_handler(
void *cls,
struct MHD_Connection *connection,
const char *url,
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index dd0ca1d9bd..792c07ac20 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -51,6 +51,12 @@
# define MHD_create_response_from_fd_at_offset64 MHD_create_response_from_fd_at_offset
#endif
+#if MHD_VERSION >= 0x00097002
+# define mhd_result enum MHD_Result
+#else
+# define mhd_result int
+#endif
+
void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0);
/* respond_oom() must be usable with return, hence this form. */

View File

@ -0,0 +1,303 @@
From 2b1dbcab1af1a22f3a46fa23aa551a7394673938 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Thu, 15 Sep 2022 15:29:23 +0200
Subject: [PATCH] ci: replace LGTM with CodeQL
As LGTM is going to be shut down by EOY, let's use CodeQL instead.
This is loosely based on upstream's CodeQL configs with some minor
tweaks to avoid backporting tons of unrelated commits.
rhel-only
Related: #2122499
---
.github/codeql-config.yml | 12 ++++
.github/codeql-custom.qls | 44 ++++++++++++
.../PotentiallyDangerousFunction.ql | 3 +
.../UninitializedVariableWithCleanup.ql | 16 ++---
.github/codeql-queries/qlpack.yml | 11 +++
.github/workflows/codeql.yml | 68 +++++++++++++++++++
.lgtm.yml | 37 ----------
7 files changed, 146 insertions(+), 45 deletions(-)
create mode 100644 .github/codeql-config.yml
create mode 100644 .github/codeql-custom.qls
rename {.lgtm/cpp-queries => .github/codeql-queries}/PotentiallyDangerousFunction.ql (93%)
rename {.lgtm/cpp-queries => .github/codeql-queries}/UninitializedVariableWithCleanup.ql (86%)
create mode 100644 .github/codeql-queries/qlpack.yml
create mode 100644 .github/workflows/codeql.yml
delete mode 100644 .lgtm.yml
diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml
new file mode 100644
index 0000000000..7c01d32caa
--- /dev/null
+++ b/.github/codeql-config.yml
@@ -0,0 +1,12 @@
+---
+# vi: ts=2 sw=2 et:
+# SPDX-License-Identifier: LGPL-2.1-or-later
+name: "CodeQL config"
+
+disable-default-queries: false
+
+queries:
+ - name: Enable possibly useful queries which are disabled by default
+ uses: ./.github/codeql-custom.qls
+ - name: systemd-specific CodeQL queries
+ uses: ./.github/codeql-queries/
diff --git a/.github/codeql-custom.qls b/.github/codeql-custom.qls
new file mode 100644
index 0000000000..d35fbe3114
--- /dev/null
+++ b/.github/codeql-custom.qls
@@ -0,0 +1,44 @@
+---
+# vi: ts=2 sw=2 et syntax=yaml:
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Note: it is not recommended to directly reference the respective queries from
+# the github/codeql repository, so we have to "dance" around it using
+# a custom QL suite
+# See:
+# - https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#running-additional-queries
+# - https://github.com/github/codeql-action/issues/430#issuecomment-806092120
+# - https://codeql.github.com/docs/codeql-cli/creating-codeql-query-suites/
+
+# Note: the codeql/<lang>-queries pack name can be found in the CodeQL repo[0]
+# in <lang>/ql/src/qlpack.yml. The respective codeql-suites are then
+# under <lang>/ql/src/codeql-suites/.
+#
+# [0] https://github.com/github/codeql
+- import: codeql-suites/cpp-lgtm.qls
+ from: codeql/cpp-queries
+- import: codeql-suites/python-lgtm.qls
+ from: codeql/python-queries
+- include:
+ id:
+ - cpp/bad-strncpy-size
+ - cpp/declaration-hides-variable
+ - cpp/include-non-header
+ - cpp/inconsistent-null-check
+ - cpp/mistyped-function-arguments
+ - cpp/nested-loops-with-same-variable
+ - cpp/sizeof-side-effect
+ - cpp/suspicious-pointer-scaling
+ - cpp/suspicious-pointer-scaling-void
+ - cpp/suspicious-sizeof
+ - cpp/unsafe-strcat
+ - cpp/unsafe-strncat
+ - cpp/unsigned-difference-expression-compared-zero
+ - cpp/unused-local-variable
+ tags:
+ - "security"
+ - "correctness"
+ severity: "error"
+- exclude:
+ id:
+ - cpp/fixme-comment
diff --git a/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql b/.github/codeql-queries/PotentiallyDangerousFunction.ql
similarity index 93%
rename from .lgtm/cpp-queries/PotentiallyDangerousFunction.ql
rename to .github/codeql-queries/PotentiallyDangerousFunction.ql
index 39e8dddd13..63fd14e75f 100644
--- a/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql
+++ b/.github/codeql-queries/PotentiallyDangerousFunction.ql
@@ -46,6 +46,9 @@ predicate potentiallyDangerousFunction(Function f, string message) {
) or (
f.getQualifiedName() = "accept" and
message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead."
+ ) or (
+ f.getQualifiedName() = "dirname" and
+ message = "Call dirname() is icky. Use path_extract_directory() instead."
)
}
diff --git a/.lgtm/cpp-queries/UninitializedVariableWithCleanup.ql b/.github/codeql-queries/UninitializedVariableWithCleanup.ql
similarity index 86%
rename from .lgtm/cpp-queries/UninitializedVariableWithCleanup.ql
rename to .github/codeql-queries/UninitializedVariableWithCleanup.ql
index 6b3b62f8bc..e514111f28 100644
--- a/.lgtm/cpp-queries/UninitializedVariableWithCleanup.ql
+++ b/.github/codeql-queries/UninitializedVariableWithCleanup.ql
@@ -50,16 +50,16 @@ class UninitialisedLocalReachability extends StackVariableReachability {
* fun(&x);
* puts(x);
*
- * `useOfVarActual()` won't treat this an an uninitialized read even if the callee
+ * `useOfVarActual()` won't treat this as an uninitialized read even if the callee
* doesn't modify the argument, however, `useOfVar()` will
*/
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVar(v, node) }
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
- // only report the _first_ possibly uninitialized use
+ /* only report the _first_ possibly uninitialized use */
useOfVar(v, node) or
(
- /* If there's an return statement somewhere between the variable declaration
+ /* If there's a return statement somewhere between the variable declaration
* and a possible definition, don't accept is as a valid initialization.
*
* E.g.:
@@ -71,7 +71,7 @@ class UninitialisedLocalReachability extends StackVariableReachability {
* x = malloc(...);
*
* is not a valid initialization, since we might return from the function
- * _before_ the actual iniitialization (emphasis on _might_, since we
+ * _before_ the actual initialization (emphasis on _might_, since we
* don't know if the return statement might ever evaluate to true).
*/
definitionBarrier(v, node) and
@@ -92,14 +92,14 @@ predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosing
* for this check to exclude them.
*/
VariableAccess commonException() {
- // If the uninitialized use we've found is in a macro expansion, it's
- // typically something like va_start(), and we don't want to complain.
+ /* If the uninitialized use we've found is in a macro expansion, it's
+ * typically something like va_start(), and we don't want to complain. */
result.getParent().isInMacroExpansion()
or
result.getParent() instanceof BuiltInOperation
or
- // Finally, exclude functions that contain assembly blocks. It's
- // anyone's guess what happens in those.
+ /* Finally, exclude functions that contain assembly blocks. It's
+ * anyone's guess what happens in those. */
containsInlineAssembly(result.getEnclosingFunction())
}
diff --git a/.github/codeql-queries/qlpack.yml b/.github/codeql-queries/qlpack.yml
new file mode 100644
index 0000000000..a1a2dec6d6
--- /dev/null
+++ b/.github/codeql-queries/qlpack.yml
@@ -0,0 +1,11 @@
+---
+# vi: ts=2 sw=2 et syntax=yaml:
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+library: false
+name: systemd/cpp-queries
+version: 0.0.1
+dependencies:
+ codeql/cpp-all: "*"
+ codeql/suite-helpers: "*"
+extractor: cpp
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000000..c5426d5686
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,68 @@
+---
+# vi: ts=2 sw=2 et:
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+name: "CodeQL"
+
+on:
+ pull_request:
+ branches:
+ - master
+ - rhel-*
+ paths:
+ - '**/meson.build'
+ - '.github/**/codeql*'
+ - 'src/**'
+ - 'test/**'
+ - 'tools/**'
+ push:
+ branches:
+ - master
+ - rhel-*
+
+permissions:
+ contents: read
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-22.04
+ concurrency:
+ group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
+ cancel-in-progress: true
+ permissions:
+ actions: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: ['cpp', 'python']
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ config-file: ./.github/codeql-config.yml
+
+ - name: Install dependencies
+ if: matrix.language == 'cpp'
+ run: |
+ echo "deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
+ sudo apt-get -y update
+ sudo apt-get -y build-dep systemd
+ sudo apt-get -y install libfdisk-dev libpwquality-dev libqrencode-dev libssl-dev libxkbcommon-dev libzstd-dev
+
+ - name: Build
+ if: matrix.language == 'cpp'
+ run: |
+ # EL 8 systemd fails to build with newer gnu-efi (3.0.13 on Ubuntu Jammy ATTOW)
+ meson build -Dlibiptc=false -Dgnu-efi=false
+ ninja -C build -v
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.lgtm.yml b/.lgtm.yml
deleted file mode 100644
index fe93957b67..0000000000
--- a/.lgtm.yml
+++ /dev/null
@@ -1,37 +0,0 @@
----
-# vi: ts=2 sw=2 et:
-
-# Explicitly enable certain checks which are hidden by default
-queries:
- - include: cpp/bad-strncpy-size
- - include: cpp/declaration-hides-variable
- - include: cpp/inconsistent-null-check
- - include: cpp/mistyped-function-arguments
- - include: cpp/nested-loops-with-same-variable
- - include: cpp/sizeof-side-effect
- - include: cpp/suspicious-pointer-scaling
- - include: cpp/suspicious-pointer-scaling-void
- - include: cpp/suspicious-sizeof
- - include: cpp/unsafe-strcat
- - include: cpp/unsafe-strncat
- - include: cpp/unsigned-difference-expression-compared-zero
- - include: cpp/unused-local-variable
- - include:
- tags:
- - "security"
- - "correctness"
- severity: "error"
-
-extraction:
- cpp:
- prepare:
- packages:
- - python3-pip
- - python3-setuptools
- - python3-wheel
- after_prepare:
- - pip3 install meson
- - export PATH="$HOME/.local/bin/:$PATH"
- python:
- python_setup:
- version: 3

View File

@ -0,0 +1,71 @@
From 4c241b812ea79f3faa02c45f95834842c7847b76 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Wed, 21 Sep 2022 15:14:26 +0200
Subject: [PATCH] ci(mergify): Update policy - Drop LGTM checks
rhel-only
Related: #2122499
---
.github/workflows/differential-shellcheck.yml | 1 +
.mergify.yml | 28 ++++++-------------
2 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
index fa94679b51..4399f0bc64 100644
--- a/.github/workflows/differential-shellcheck.yml
+++ b/.github/workflows/differential-shellcheck.yml
@@ -13,6 +13,7 @@ permissions:
jobs:
lint:
+ name: Differential ShellCheck
runs-on: ubuntu-latest
permissions:
diff --git a/.mergify.yml b/.mergify.yml
index 3afd04f18e..a5eed6a82a 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -11,16 +11,10 @@ pull_request_rules:
- -check-success=build (stream8, GCC_ASAN)
# CentOS Stream CI
- -check-success=CentOS CI (CentOS Stream 8)
- # LGTM
- - and:
- - "-check-success=LGTM analysis: JavaScript"
- - "-check-neutral=LGTM analysis: JavaScript"
- - and:
- - "-check-success=LGTM analysis: Python"
- - "-check-neutral=LGTM analysis: Python"
- - and:
- - "-check-success=LGTM analysis: C/C++"
- - "-check-neutral=LGTM analysis: C/C++"
+ # CodeQL
+ - -check-success=CodeQL
+ # Other
+ - -check-success=Differential ShellCheck
actions:
label:
add:
@@ -36,16 +30,10 @@ pull_request_rules:
- check-success=build (stream8, GCC_ASAN)
# CentOS Stream CI
- check-success=CentOS CI (CentOS Stream 8)
- # LGTM
- - or:
- - "check-success=LGTM analysis: JavaScript"
- - "check-neutral=LGTM analysis: JavaScript"
- - or:
- - "check-success=LGTM analysis: Python"
- - "check-neutral=LGTM analysis: Python"
- - or:
- - "check-success=LGTM analysis: C/C++"
- - "check-neutral=LGTM analysis: C/C++"
+ # CodeQL
+ - check-success=CodeQL
+ # Other
+ - check-success=Differential ShellCheck
actions:
label:
remove:

View File

@ -0,0 +1,44 @@
From a521f942d5c304bca7c61bacb3c79e565853718e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 7 Jul 2022 18:27:02 +0900
Subject: [PATCH] time-util: fix buffer-over-run
Fixes #23928.
(cherry picked from commit 9102c625a673a3246d7e73d8737f3494446bad4e)
Resolves: #2139391
---
src/basic/time-util.c | 2 +-
src/test/test-time-util.c | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index c36e462193..d46d884be5 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -515,7 +515,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
t = b;
}
- n = MIN((size_t) k, l);
+ n = MIN((size_t) k, l-1);
l -= n;
p += n;
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 354a01dd1a..6ebde4153c 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -187,6 +187,11 @@ static void test_format_timespan(usec_t accuracy) {
test_format_timespan_one(500 * USEC_PER_MSEC, accuracy);
test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy);
test_format_timespan_one(USEC_INFINITY, accuracy);
+
+ /* See issue #23928. */
+ _cleanup_free_ char *buf;
+ assert_se(buf = new(char, 5));
+ assert_se(buf == format_timespan(buf, 5, 100005, 1000));
}
static void test_timezone_is_valid(void) {

View File

@ -0,0 +1,32 @@
From 2fe9fb3e844d7991105c40d4363eed9069a6837d Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 18 Nov 2022 16:16:36 +0100
Subject: [PATCH] basic: recognize pdfs filesystem as a network filesystem
Fujitsu advises their users to always use _netdev mount option with pdfs
mounts. Hence it makes sense to simply consider pdfs mounts as network
filesystem mounts.
https://software.fujitsu.com/jp/manual/manualfiles/m130027/j2ul1563/02enz200/j1563-02-06-02-02.html
RHEL-only
Resolves: #2094661
---
src/basic/mount-util.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index e7f9e514c2..983566b46b 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -634,7 +634,8 @@ bool fstype_is_network(const char *fstype) {
"glusterfs",
"pvfs2", /* OrangeFS */
"ocfs2",
- "lustre");
+ "lustre",
+ "pdfs");
}
bool fstype_is_api_vfs(const char *fstype) {

View File

@ -0,0 +1,49 @@
From 4bb425eea9f3037a583a23d99f15aa71562f2481 Mon Sep 17 00:00:00 2001
From: Anita Zhang <the.anitazha@gmail.com>
Date: Thu, 17 Sep 2020 01:49:17 -0700
Subject: [PATCH] core: move reset_arguments() to the end of main's finish
Fixes #16991
fb39af4ce42d7ef9af63009f271f404038703704 replaced `free_arguments()` with
`reset_arguments()`, which frees arg_* variables as before, but also resets all
of them to the default values. `reset_arguments()` was positioned
in such a way that it overrode some arg_* values still in use at shutdown.
To avoid further unintentional resets, I moved `reset_arguments()`
right before the return, when nothing else will be using the arg_* variables.
(cherry picked from commit 7d9eea2bd3d4f83668c7a78754d201b226acbf1e)
Resolves: #2127131
---
src/core/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/core/main.c b/src/core/main.c
index bfd4c531a7..cfa6fec930 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2631,7 +2631,6 @@ finish:
m = manager_free(m);
}
- reset_arguments();
mac_selinux_finish();
if (reexecute)
@@ -2656,6 +2655,7 @@ finish:
* in become_shutdown() so normally we cannot free them yet. */
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);
+ reset_arguments();
return retval;
}
#endif
@@ -2677,5 +2677,6 @@ finish:
freeze_or_reboot();
}
+ reset_arguments();
return retval;
}

View File

@ -0,0 +1,91 @@
From 708c394b7ca35fe2328fa0760696ff95caab8ff8 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 29 Nov 2022 16:15:47 +0100
Subject: [PATCH] manager: move inc. of n_reloading into a function
[dtardon: This is inspired by commit d147e2b66b4d6b71db1bc59b62286b2eb9c3d29f ,
but it does just the minimal change needed for the next commit.]
Related: #2136869
---
src/core/main.c | 2 +-
src/core/manager.c | 12 ++++++++----
src/core/manager.h | 1 +
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/core/main.c b/src/core/main.c
index cfa6fec930..c3e2ce8956 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1131,7 +1131,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
return log_error_errno(r, "Failed to create serialization file: %m");
/* Make sure nothing is really destructed when we shut down */
- m->n_reloading++;
+ manager_reloading_start(m);
bus_manager_send_reloading(m, true);
fds = fdset_new();
diff --git a/src/core/manager.c b/src/core/manager.c
index f4611e6f8f..f923cbce37 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1578,6 +1578,10 @@ static void manager_preset_all(Manager *m) {
log_info("Populated /etc with preset unit settings.");
}
+void manager_reloading_start(Manager *m) {
+ m->n_reloading++;
+}
+
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
int r;
@@ -1609,7 +1613,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
* this is already known, so we increase the counter here
* already */
if (serialization)
- m->n_reloading++;
+ manager_reloading_start(m);
/* First, enumerate what we can from all config files */
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
@@ -3093,7 +3097,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
assert(f);
assert(fds);
- m->n_reloading++;
+ manager_reloading_start(m);
fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id);
fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
@@ -3211,7 +3215,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
log_debug("Deserializing state...");
- m->n_reloading++;
+ manager_reloading_start(m);
for (;;) {
_cleanup_free_ char *line = NULL;
@@ -3455,7 +3459,7 @@ int manager_reload(Manager *m) {
if (r < 0)
return r;
- m->n_reloading++;
+ manager_reloading_start(m);
bus_manager_send_reloading(m, true);
fds = fdset_new();
diff --git a/src/core/manager.h b/src/core/manager.h
index 3f2cfc5e2e..adbbb518cb 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -386,6 +386,7 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **m);
Manager* manager_free(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+void manager_reloading_start(Manager *m);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);

View File

@ -0,0 +1,59 @@
From 22eb8fbdab14e5b1b11a4d84c83bef97317e1d2a Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 2 Sep 2021 16:37:13 +0200
Subject: [PATCH] core: Add new DBUS properties UnitsReloadStartTimestamp and
UnitsLoadTimestampMontonic
(cherry picked from commit 49fbe940a429c3d8807bacdfce03af834275257c)
Related: #2136869
---
src/core/dbus-manager.c | 1 +
src/core/manager.c | 2 ++
src/core/manager.h | 1 +
3 files changed, 4 insertions(+)
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 5b1ed3646e..8a41eda4a6 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2486,6 +2486,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0),
diff --git a/src/core/manager.c b/src/core/manager.c
index f923cbce37..8aa398cac8 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1580,6 +1580,7 @@ static void manager_preset_all(Manager *m) {
void manager_reloading_start(Manager *m) {
m->n_reloading++;
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD);
}
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
@@ -4622,6 +4623,7 @@ static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
[MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
[MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
+ [MANAGER_TIMESTAMP_UNITS_LOAD] = "units-load",
};
DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp);
diff --git a/src/core/manager.h b/src/core/manager.h
index adbbb518cb..98d381bc5b 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -67,6 +67,7 @@ typedef enum ManagerTimestamp {
MANAGER_TIMESTAMP_GENERATORS_FINISH,
MANAGER_TIMESTAMP_UNITS_LOAD_START,
MANAGER_TIMESTAMP_UNITS_LOAD_FINISH,
+ MANAGER_TIMESTAMP_UNITS_LOAD,
_MANAGER_TIMESTAMP_MAX,
_MANAGER_TIMESTAMP_INVALID = -1,
} ManagerTimestamp;

View File

@ -0,0 +1,29 @@
From f2de5398b0a1ebb3e6390506368c11329b843524 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 2 Sep 2021 16:50:50 +0200
Subject: [PATCH] core: Indicate the time when the manager started loading
units the last time
(cherry picked from commit 15b9243c0d7f6d1531fa65dbc01bd11e8e6c12ca)
Resolves: #2136869
---
src/core/manager.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/core/manager.c b/src/core/manager.c
index 8aa398cac8..a9cd51b624 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3554,6 +3554,11 @@ int manager_reload(Manager *m) {
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
+ /* Create a file which will indicate when the manager started loading units the last time. */
+ (void) touch_file("/run/systemd/systemd-units-load", false,
+ m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME),
+ UID_INVALID, GID_INVALID, 0444);
+
/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);
if (q < 0 && r >= 0)

View File

@ -0,0 +1,34 @@
From 3c2d2345814935cea8525e802e764fb2949eb3df Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@microsoft.com>
Date: Mon, 27 Dec 2021 18:22:43 +0000
Subject: [PATCH] core: do not touch /run/systemd/systemd-units-load from user
session instances
Follow-up for: https://github.com/systemd/systemd/commit/15b9243c0d7f6d1531fa65dbc01bd11e8e6c12ca
Fixes: https://github.com/systemd/systemd/issues/21911
(cherry picked from commit 4b3ad81bfafcd97acb06db463495e348d159d8e6)
Related: #2136869
---
src/core/manager.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index a9cd51b624..e083596e58 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3555,9 +3555,10 @@ int manager_reload(Manager *m) {
manager_catchup(m);
/* Create a file which will indicate when the manager started loading units the last time. */
- (void) touch_file("/run/systemd/systemd-units-load", false,
- m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME),
- UID_INVALID, GID_INVALID, 0444);
+ if (MANAGER_IS_SYSTEM(m))
+ (void) touch_file("/run/systemd/systemd-units-load", false,
+ m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME),
+ UID_INVALID, GID_INVALID, 0444);
/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);

View File

@ -0,0 +1,49 @@
From ffe4233155085b479c69abe844a34de212b8e5e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 16 Jan 2020 14:45:28 +0100
Subject: [PATCH] sysctl: downgrade message when we have no permission
We need to run sysctl also in containers, because the network
subtree is namespaces and may legitimately be writable. But logging
all "errors" at notice level creates unwanted noise.
Also downgrade message about missing sysctls to log_info. This might also be
relatively common when configuration is targeted at different kernel
versions. With log_debug it'll still end up in the logs, but isn't really worth
of "notice" most of the time.
https://bugzilla.redhat.com/show_bug.cgi?id=1609806
(cherry picked from commit 32458cc9687c1b60ff0f22c0e71da93ce78b1534)
Resolves: #2158160
---
src/sysctl/sysctl.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 4c85d6887f..dc14e1aaf1 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -82,13 +82,15 @@ static int apply_all(OrderedHashmap *sysctl_options) {
k = sysctl_write(option->key, option->value);
if (k < 0) {
/* If the sysctl is not available in the kernel or we are running with reduced
- * privileges and cannot write it, then log about the issue at LOG_NOTICE level, and
- * proceed without failing. (EROFS is treated as a permission problem here, since
- * that's how container managers usually protected their sysctls.) In all other cases
- * log an error and make the tool fail. */
-
- if (IN_SET(k, -EPERM, -EACCES, -EROFS, -ENOENT) || option->ignore_failure)
- log_notice_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key);
+ * privileges and cannot write it, then log about the issue, and proceed without
+ * failing. (EROFS is treated as a permission problem here, since that's how
+ * container managers usually protected their sysctls.) In all other cases log an
+ * error and make the tool fail. */
+
+ if (option->ignore_failure || k == -EROFS || ERRNO_IS_PRIVILEGE(k))
+ log_debug_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key);
+ else if (k == -ENOENT)
+ log_info_errno(k, "Couldn't write '%s' to '%s', ignoring: %m", option->value, option->key);
else {
log_error_errno(k, "Couldn't write '%s' to '%s': %m", option->value, option->key);
if (r == 0)

View File

@ -0,0 +1,53 @@
From 1f408c8d9739b1038012eeec7bf0f918c8095bc4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 23 Sep 2022 19:00:22 +0200
Subject: [PATCH] core: respect SELinuxContext= for socket creation
On socket creation respect the SELinuxContext= setting of the associated
service, such that the initial created socket has the same label as the
future process accepting the connection (since w.r.t SELinux sockets
normally have the same label as the owning process).
Triggered by #24702
(cherry picked from commit 599b384924bbef9f8f7fa5700c6fa35a404d9a98)
Related: #2136738
---
src/core/socket.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/core/socket.c b/src/core/socket.c
index 9d47ca2616..d1ca0a07c5 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1427,6 +1427,7 @@ fail:
static int socket_determine_selinux_label(Socket *s, char **ret) {
Service *service;
ExecCommand *c;
+ const char *exec_context;
_cleanup_free_ char *path = NULL;
int r;
@@ -1448,8 +1449,20 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
if (!UNIT_ISSET(s->service))
goto no_label;
-
service = SERVICE(UNIT_DEREF(s->service));
+
+ exec_context = service->exec_context.selinux_context;
+ if (exec_context) {
+ char *con;
+
+ con = strdup(exec_context);
+ if (!con)
+ return -ENOMEM;
+
+ *ret = TAKE_PTR(con);
+ return 0;
+ }
+
c = service->exec_command[SERVICE_EXEC_START];
if (!c)
goto no_label;

View File

@ -0,0 +1,128 @@
From 3f90090e70a5fa81bced17792fe08d9c46324da9 Mon Sep 17 00:00:00 2001
From: "Ted X. Toth" <txtoth@flycast.org>
Date: Thu, 13 Oct 2022 12:58:26 -0700
Subject: [PATCH] manager: use target process context to set socket context
Use target process context to set socket context when using SELinuxContextFromNet
not systemd's context. Currently when using the SELinuxContextFromNet option for
a socket activated services, systemd calls getcon_raw which returns init_t and
uses the resulting context to compute the context to be passed to the
setsockcreatecon call. A socket of type init_t is created and listened on and
this means that SELinux policy cannot be written to control which processes
(SELinux types) can connect to the socket since the ref policy allows all
'types' to connect to sockets of the type init_t. When security accessors see
that any process can connect to a socket this raises serious concerns. I have
spoken with SELinux contributors in person and on the mailing list and the
consensus is that the best solution is to use the target executables context
when computing the sockets context in all cases.
[zjs review/comment:
This removes the branch that was added in 16115b0a7b7cdf08fb38084d857d572d8a9088dc.
16115b0a7b7cdf08fb38084d857d572d8a9088dc did two things: it had the branch here
in 'socket_determine_selinux_label()' and a code in 'exec_child()' to call
'label_get_child_mls_label(socket_fd, command->path, &label)'.
Before this patch, the flow was:
'''
mac_selinux_get_child_mls_label:
peercon = getpeercon_raw(socket_fd);
if (!exec_label)
exec_label = getfilecon_raw(exe);
socket_open_fds:
if (params->selinux_context_net) #
label = mac_selinux_get_our_label(); # this part is removed
else #
label = mac_selinux_get_create_label_from_exe(path);
socket_address_listen_in_cgroup(s, &p->address, label);
exec_child():
exec_context = mac_selinux_get_child_mls_label(fd, executable, context->selinux_context);
setexeccon(exec_context);
'''
]
(cherry picked from commit 29dbc62d74f7b7881dc3136e68e03a03ea055b36)
Resolves: #2136738
---
src/core/socket.c | 58 ++++++++++++++++++++---------------------------
1 file changed, 24 insertions(+), 34 deletions(-)
diff --git a/src/core/socket.c b/src/core/socket.c
index d1ca0a07c5..8aa5463b25 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1434,47 +1434,37 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
assert(s);
assert(ret);
- if (s->selinux_context_from_net) {
- /* If this is requested, get label from the network label */
-
- r = mac_selinux_get_our_label(ret);
- if (r == -EOPNOTSUPP)
- goto no_label;
-
- } else {
- /* Otherwise, get it from the executable we are about to start */
- r = socket_instantiate_service(s);
- if (r < 0)
- return r;
+ r = socket_instantiate_service(s);
+ if (r < 0)
+ return r;
- if (!UNIT_ISSET(s->service))
- goto no_label;
- service = SERVICE(UNIT_DEREF(s->service));
+ if (!UNIT_ISSET(s->service))
+ goto no_label;
+ service = SERVICE(UNIT_DEREF(s->service));
- exec_context = service->exec_context.selinux_context;
- if (exec_context) {
- char *con;
+ exec_context = service->exec_context.selinux_context;
+ if (exec_context) {
+ char *con;
- con = strdup(exec_context);
- if (!con)
- return -ENOMEM;
+ con = strdup(exec_context);
+ if (!con)
+ return -ENOMEM;
- *ret = TAKE_PTR(con);
- return 0;
- }
+ *ret = TAKE_PTR(con);
+ return 0;
+ }
- c = service->exec_command[SERVICE_EXEC_START];
- if (!c)
- goto no_label;
+ c = service->exec_command[SERVICE_EXEC_START];
+ if (!c)
+ goto no_label;
- r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path);
- if (r < 0)
- goto no_label;
+ r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path);
+ if (r < 0)
+ goto no_label;
- r = mac_selinux_get_create_label_from_exe(path, ret);
- if (IN_SET(r, -EPERM, -EOPNOTSUPP))
- goto no_label;
- }
+ r = mac_selinux_get_create_label_from_exe(path, ret);
+ if (IN_SET(r, -EPERM, -EOPNOTSUPP))
+ goto no_label;
return r;

View File

@ -0,0 +1,142 @@
From 6ffd3de2ccc5901974f292c9694829e25441060d Mon Sep 17 00:00:00 2001
From: Bertrand Jacquin <bertrand@jacquin.bzh>
Date: Sun, 11 Oct 2020 21:25:00 +0100
Subject: [PATCH] virt: detect Amazon EC2 Nitro instance
Amazon EC2 Nitro hypervisor is technically based on KVM[1], which
systemd-detect-virt identify propely from CPUID. However the lack of
CPUID on aarch64 (A1, T4 instance type) prevents a correct
identification, impacting hostnamectl and systemd-random-seed. Instead
it's possible to identify virtualization from DMI vendor ID.
Prior to this commit:
# hostnamectl
Static hostname: n/a
Transient hostname: ip-10-97-8-12
Icon name: computer
Machine ID: 8e3772fbcfa3dd6f330a12ff5df5a63b
Boot ID: b7b7e2fe0079448db664839df59f9817
Operating System: Gentoo/Linux
Kernel: Linux 5.4.69-longterm
Architecture: arm64
After this commit:
# hostnamectl
Static hostname: n/a
Transient hostname: ip-10-97-8-12
Icon name: computer-vm
Chassis: vm
Machine ID: 8e3772fbcfa3dd6f330a12ff5df5a63b
Boot ID: bd04da57084e41078f20541101867113
Virtualization: amazon
Operating System: Gentoo/Linux
Kernel: Linux 5.4.69-longterm
Architecture: arm64
[1] https://aws.amazon.com/ec2/faqs/
(cherry picked from commit b6eca3731dd92b009b182f188936e1c2544574da)
Resolves: #2117948
---
man/systemd-detect-virt.xml | 7 ++++++-
man/systemd.unit.xml | 1 +
src/basic/virt.c | 8 +++++---
src/basic/virt.h | 1 +
src/test/test-condition.c | 1 +
5 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 6beb2c2aa1..61c210e24d 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -72,7 +72,12 @@
<row>
<entry><varname>kvm</varname></entry>
- <entry>Linux KVM kernel virtual machine, with whatever software, except Oracle Virtualbox</entry>
+ <entry>Linux KVM kernel virtual machine, in combination with QEMU. Not used for other virtualizers using the KVM interfaces, such as Oracle VirtualBox or Amazon EC2 Nitro, see below.</entry>
+ </row>
+
+ <row>
+ <entry><varname>amazon</varname></entry>
+ <entry>Amazon EC2 Nitro using Linux KVM</entry>
</row>
<row>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 6f213ccd56..5207a5bb3c 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -1068,6 +1068,7 @@
virtualization solution, or one of
<varname>qemu</varname>,
<varname>kvm</varname>,
+ <literal>amazon</literal>,
<varname>zvm</varname>,
<varname>vmware</varname>,
<varname>microsoft</varname>,
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 8d862b6d67..78c68d66e0 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -147,6 +147,7 @@ static int detect_vm_dmi(void) {
int id;
} dmi_vendor_table[] = {
{ "KVM", VIRTUALIZATION_KVM },
+ { "Amazon EC2", VIRTUALIZATION_AMAZON },
{ "QEMU", VIRTUALIZATION_QEMU },
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMware", VIRTUALIZATION_VMWARE },
@@ -339,8 +340,8 @@ int detect_vm(void) {
/* We have to use the correct order here:
*
- * → First, try to detect Oracle Virtualbox, even if it uses KVM, as well as Xen even if it cloaks as Microsoft
- * Hyper-V.
+ * → First, try to detect Oracle Virtualbox and Amazon EC2 Nitro, even if they use KVM, as well as Xen even if
+ * it cloaks as Microsoft Hyper-V.
*
* → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
* overwritten.
@@ -348,7 +349,7 @@ int detect_vm(void) {
* → Third, try to detect from DMI. */
dmi = detect_vm_dmi();
- if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN)) {
+ if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN, VIRTUALIZATION_AMAZON)) {
r = dmi;
goto finish;
}
@@ -631,6 +632,7 @@ int running_in_chroot(void) {
static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_NONE] = "none",
[VIRTUALIZATION_KVM] = "kvm",
+ [VIRTUALIZATION_AMAZON] = "amazon",
[VIRTUALIZATION_QEMU] = "qemu",
[VIRTUALIZATION_BOCHS] = "bochs",
[VIRTUALIZATION_XEN] = "xen",
diff --git a/src/basic/virt.h b/src/basic/virt.h
index 640b3ed779..ed4ff063e0 100644
--- a/src/basic/virt.h
+++ b/src/basic/virt.h
@@ -10,6 +10,7 @@ enum {
VIRTUALIZATION_VM_FIRST,
VIRTUALIZATION_KVM = VIRTUALIZATION_VM_FIRST,
+ VIRTUALIZATION_AMAZON,
VIRTUALIZATION_QEMU,
VIRTUALIZATION_BOCHS,
VIRTUALIZATION_XEN,
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 24395dafc6..29ea63c4ff 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -510,6 +510,7 @@ static void test_condition_test_virtualization(void) {
NULSTR_FOREACH(virt,
"kvm\0"
+ "amazon\0"
"qemu\0"
"bochs\0"
"xen\0"

View File

@ -0,0 +1,37 @@
From e320f72150829228f10ec24f3fba34d5377c5120 Mon Sep 17 00:00:00 2001
From: Bertrand Jacquin <bertrand@jacquin.bzh>
Date: Sun, 11 Oct 2020 22:25:56 +0100
Subject: [PATCH] machine-id-setup: generate machine-id from DMI product ID on
Amazon EC2
Amazon EC2 Nitro hypervisor is technically based on KVM[1].
[1] https://aws.amazon.com/ec2/faqs/
(cherry picked from commit 382a46d129899ca9027b07c325102cab173dd563)
Related: #2117948
---
src/core/machine-id-setup.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 11528f83c4..fe2abc4e68 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -57,11 +57,11 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
return 0;
}
- } else if (detect_vm() == VIRTUALIZATION_KVM) {
+ } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU)) {
- /* If we are not running in a container, see if we are
- * running in qemu/kvm and a machine ID was passed in
- * via -uuid on the qemu/kvm command line */
+ /* If we are not running in a container, see if we are running in a VM that provides
+ * a system UUID via the SMBIOS/DMI interfaces. Such environments include QEMU/KVM
+ * with the -uuid on the qemu command line or the Amazon EC2 Nitro hypervisor. */
if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) {
log_info("Initializing machine ID from KVM UUID.");

View File

@ -0,0 +1,134 @@
From efa2cdb699df3e5d5d7180e50f3ebfff74788c5c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 7 Jan 2020 11:49:39 +0900
Subject: [PATCH] virt: use string table to detect VM or container
(cherry picked from commit 735ea55f5cd87a82757a8911edd80fba799b46ee)
Related: #2117948
---
src/basic/virt.c | 73 ++++++++++++++++++++++--------------------------
1 file changed, 33 insertions(+), 40 deletions(-)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 78c68d66e0..6e4c702051 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -22,27 +22,26 @@
#include "string-util.h"
#include "virt.h"
+static const char *const vm_table[_VIRTUALIZATION_MAX] = {
+ [VIRTUALIZATION_XEN] = "XenVMMXenVMM",
+ [VIRTUALIZATION_KVM] = "KVMKVMKVM",
+ [VIRTUALIZATION_QEMU] = "TCGTCGTCGTCG",
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ [VIRTUALIZATION_VMWARE] = "VMwareVMware",
+ /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
+ [VIRTUALIZATION_MICROSOFT] = "Microsoft Hv",
+ /* https://wiki.freebsd.org/bhyve */
+ [VIRTUALIZATION_BHYVE] = "bhyve bhyve ",
+ [VIRTUALIZATION_QNX] = "QNXQVMBSQG",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(vm, int);
+
static int detect_vm_cpuid(void) {
/* CPUID is an x86 specific interface. */
#if defined(__i386__) || defined(__x86_64__)
- static const struct {
- const char *cpuid;
- int id;
- } cpuid_vendor_table[] = {
- { "XenVMMXenVMM", VIRTUALIZATION_XEN },
- { "KVMKVMKVM", VIRTUALIZATION_KVM },
- { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- { "VMwareVMware", VIRTUALIZATION_VMWARE },
- /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
- { "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
- /* https://wiki.freebsd.org/bhyve */
- { "bhyve bhyve ", VIRTUALIZATION_BHYVE },
- { "QNXQVMBSQG", VIRTUALIZATION_QNX },
- };
-
uint32_t eax, ebx, ecx, edx;
bool hypervisor;
@@ -59,7 +58,7 @@ static int detect_vm_cpuid(void) {
uint32_t sig32[3];
char text[13];
} sig = {};
- unsigned j;
+ int v;
/* There is a hypervisor, see what it is */
__cpuid(0x40000000U, eax, ebx, ecx, edx);
@@ -70,11 +69,11 @@ static int detect_vm_cpuid(void) {
log_debug("Virtualization found, CPUID=%s", sig.text);
- for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
- if (streq(sig.text, cpuid_vendor_table[j].cpuid))
- return cpuid_vendor_table[j].id;
+ v = vm_from_string(sig.text);
+ if (v < 0)
+ return VIRTUALIZATION_VM_OTHER;
- return VIRTUALIZATION_VM_OTHER;
+ return v;
}
#endif
log_debug("No virtualization found in CPUID");
@@ -434,22 +433,20 @@ finish:
return r;
}
-int detect_container(void) {
- static const struct {
- const char *value;
- int id;
- } value_table[] = {
- { "lxc", VIRTUALIZATION_LXC },
- { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
- { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
- { "docker", VIRTUALIZATION_DOCKER },
- { "rkt", VIRTUALIZATION_RKT },
- };
+static const char *const container_table[_VIRTUALIZATION_MAX] = {
+ [VIRTUALIZATION_LXC] = "lxc",
+ [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
+ [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
+ [VIRTUALIZATION_DOCKER] = "docker",
+ [VIRTUALIZATION_RKT] = "rkt",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int);
+int detect_container(void) {
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
_cleanup_free_ char *m = NULL;
const char *e = NULL;
- unsigned j;
int r;
if (cached_found >= 0)
@@ -522,13 +519,9 @@ int detect_container(void) {
goto finish;
translate_name:
- for (j = 0; j < ELEMENTSOF(value_table); j++)
- if (streq(e, value_table[j].value)) {
- r = value_table[j].id;
- goto finish;
- }
-
- r = VIRTUALIZATION_CONTAINER_OTHER;
+ r = container_from_string(e);
+ if (r < 0)
+ r = VIRTUALIZATION_CONTAINER_OTHER;
finish:
log_debug("Found container virtualization %s.", virtualization_to_string(r));

View File

@ -0,0 +1,194 @@
From 7a3843972ea290daf1bec5e1133db654749b8c02 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Tue, 22 Oct 2019 16:09:21 +0200
Subject: [PATCH] fileio: introduce read_full_virtual_file() for reading
virtual files in sysfs, procfs
Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work
with two sorts of virtual files.
One sort uses "seq_file", and the results of the first read are buffered for
the second read. The other sort uses "raw" reads which always go direct to the
device.
In the later case, the content of the virtual file must be retrieved with a
single read otherwise subsequent read might get the new value instead of
finding EOF immediately. That's the reason why the usage of fread(3) is
prohibited in this case as it always performs a second call to read(2) looking
for EOF which is subject to the race described previously.
Fixes: #13585.
(cherry picked from commit 21b40f16622f171a9969dc334d74fb5eb2f575c2)
Related: #2117948
---
src/basic/fileio.c | 115 ++++++++++++++++++++++++++-
src/basic/fileio.h | 1 +
src/libsystemd/sd-device/sd-device.c | 2 +-
3 files changed, 113 insertions(+), 5 deletions(-)
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 6b0bad5b71..733fb42463 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -276,6 +276,113 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
return 1;
}
+int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ size_t n, size;
+ int n_retries;
+ char *p;
+
+ assert(ret_contents);
+
+ /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work
+ * with two sorts of virtual files. One sort uses "seq_file", and the results of
+ * the first read are buffered for the second read. The other sort uses "raw"
+ * reads which always go direct to the device. In the latter case, the content of
+ * the virtual file must be retrieved with a single read otherwise a second read
+ * might get the new value instead of finding EOF immediately. That's the reason
+ * why the usage of fread(3) is prohibited in this case as it always performs a
+ * second call to read(2) looking for EOF. See issue 13585. */
+
+ fd = open(filename, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ /* Start size for files in /proc which usually report a file size of 0. */
+ size = LINE_MAX / 2;
+
+ /* Limit the number of attempts to read the number of bytes returned by fstat(). */
+ n_retries = 3;
+
+ for (;;) {
+ if (n_retries <= 0)
+ return -EIO;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISREG(st.st_mode))
+ return -EBADF;
+
+ /* Be prepared for files from /proc which generally report a file size of 0. */
+ if (st.st_size > 0) {
+ size = st.st_size;
+ n_retries--;
+ } else
+ size = size * 2;
+
+ if (size > READ_FULL_BYTES_MAX)
+ return -E2BIG;
+
+ p = realloc(buf, size + 1);
+ if (!p)
+ return -ENOMEM;
+ buf = TAKE_PTR(p);
+
+ for (;;) {
+ ssize_t k;
+
+ /* Read one more byte so we can detect whether the content of the
+ * file has already changed or the guessed size for files from /proc
+ * wasn't large enough . */
+ k = read(fd, buf, size + 1);
+ if (k >= 0) {
+ n = k;
+ break;
+ }
+
+ if (errno != -EINTR)
+ return -errno;
+ }
+
+ /* Consider a short read as EOF */
+ if (n <= size)
+ break;
+
+ /* Hmm... either we read too few bytes from /proc or less likely the content
+ * of the file might have been changed (and is now bigger) while we were
+ * processing, let's try again either with a bigger guessed size or the new
+ * file size. */
+
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -errno;
+ }
+
+ if (n < size) {
+ p = realloc(buf, n + 1);
+ if (!p)
+ return -ENOMEM;
+ buf = TAKE_PTR(p);
+ }
+
+ if (!ret_size) {
+ /* Safety check: if the caller doesn't want to know the size of what we
+ * just read it will rely on the trailing NUL byte. But if there's an
+ * embedded NUL byte, then we should refuse operation as otherwise
+ * there'd be ambiguity about what we just read. */
+
+ if (memchr(buf, 0, n))
+ return -EBADMSG;
+ } else
+ *ret_size = n;
+
+ buf[n] = 0;
+ *ret_contents = TAKE_PTR(buf);
+
+ return 0;
+}
+
int read_full_stream(FILE *f, char **contents, size_t *size) {
_cleanup_free_ char *buf = NULL;
struct stat st;
@@ -300,9 +407,9 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
if (st.st_size > READ_FULL_BYTES_MAX)
return -E2BIG;
- /* Start with the right file size, but be prepared for files from /proc which generally report a file
- * size of 0. Note that we increase the size to read here by one, so that the first read attempt
- * already makes us notice the EOF. */
+ /* Start with the right file size. Note that we increase the size
+ * to read here by one, so that the first read attempt already
+ * makes us notice the EOF. */
if (st.st_size > 0)
n = st.st_size + 1;
}
@@ -986,7 +1093,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
assert(pattern);
assert(field);
- r = read_full_file(filename, &status, NULL);
+ r = read_full_virtual_file(filename, &status, NULL);
if (r < 0)
return r;
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 77e6206e95..c6ad375b8d 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -38,6 +38,7 @@ int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *f
int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size);
int read_full_stream(FILE *f, char **contents, size_t *size);
+int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index be29053f8c..49750ba9d7 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -1798,7 +1798,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
size_t size;
/* read attribute value */
- r = read_full_file(path, &value, &size);
+ r = read_full_virtual_file(path, &value, &size);
if (r < 0)
return r;

View File

@ -0,0 +1,118 @@
From 44cbd79562ed55a8b0f2e5b5dc708265568ed9f8 Mon Sep 17 00:00:00 2001
From: Noah Meyerhans <nmeyerha@amazon.com>
Date: Fri, 30 Apr 2021 09:30:52 -0700
Subject: [PATCH] Use BIOS characteristics to distinguish EC2 bare-metal from
VMs
DMI vendor information fields do not provide enough information for us to
distinguish between Amazon EC2 virtual machines and bare-metal instances.
SMBIOS provides a BIOS Information
table (https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf
Ch. 7) that provides a field to indicate that the current machine is a virtual
machine. On EC2 virtual machine instances, this field is set, while bare-metal
instances leave this unset, so we inspect the field via the kernel's
/sys/firemware/dmi/entries interface.
Fixes #18929
(cherry picked from commit ce35037928f4c4c931088256853f07804ec7d235)
Related: #2117948
---
src/basic/virt.c | 65 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 4 deletions(-)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 6e4c702051..00d1c894e6 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -22,6 +22,12 @@
#include "string-util.h"
#include "virt.h"
+enum {
+ SMBIOS_VM_BIT_SET,
+ SMBIOS_VM_BIT_UNSET,
+ SMBIOS_VM_BIT_UNKNOWN,
+};
+
static const char *const vm_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_XEN] = "XenVMMXenVMM",
[VIRTUALIZATION_KVM] = "KVMKVMKVM",
@@ -131,9 +137,8 @@ static int detect_vm_device_tree(void) {
#endif
}
-static int detect_vm_dmi(void) {
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
-
+static int detect_vm_dmi_vendor(void) {
static const char *const dmi_vendors[] = {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
"/sys/class/dmi/id/sys_vendor",
@@ -179,11 +184,63 @@ static int detect_vm_dmi(void) {
return dmi_vendor_table[j].id;
}
}
-#endif
+ return VIRTUALIZATION_NONE;
+}
+
+static int detect_vm_smbios(void) {
+ /* The SMBIOS BIOS Charateristics Extension Byte 2 (Section 2.1.2.2 of
+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf), specifies that
+ * the 4th bit being set indicates a VM. The BIOS Characteristics table is exposed via the kernel in
+ * /sys/firmware/dmi/entries/0-0. Note that in the general case, this bit being unset should not
+ * imply that the system is running on bare-metal. For example, QEMU 3.1.0 (with or without KVM)
+ * with SeaBIOS does not set this bit. */
+ _cleanup_free_ char *s = NULL;
+ size_t readsize;
+ int r;
+
+ r = read_full_virtual_file("/sys/firmware/dmi/entries/0-0/raw", &s, &readsize);
+ if (r < 0) {
+ log_debug_errno(r, "Unable to read /sys/firmware/dmi/entries/0-0/raw, ignoring: %m");
+ return SMBIOS_VM_BIT_UNKNOWN;
+ }
+ if (readsize < 20 || s[1] < 20) {
+ /* The spec indicates that byte 1 contains the size of the table, 0x12 + the number of
+ * extension bytes. The data we're interested in is in extension byte 2, which would be at
+ * 0x13. If we didn't read that much data, or if the BIOS indicates that we don't have that
+ * much data, we don't infer anything from the SMBIOS. */
+ log_debug("Only read %zu bytes from /sys/firmware/dmi/entries/0-0/raw (expected 20)", readsize);
+ return SMBIOS_VM_BIT_UNKNOWN;
+ }
- log_debug("No virtualization found in DMI");
+ uint8_t byte = (uint8_t) s[19];
+ if (byte & (1U<<4)) {
+ log_debug("DMI BIOS Extension table indicates virtualization");
+ return SMBIOS_VM_BIT_SET;
+ }
+ log_debug("DMI BIOS Extension table does not indicate virtualization");
+ return SMBIOS_VM_BIT_UNSET;
+}
+#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) */
+
+static int detect_vm_dmi(void) {
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+
+ int r;
+ r = detect_vm_dmi_vendor();
+ /* The DMI vendor tables in /sys/class/dmi/id don't help us distinguish between Amazon EC2
+ * virtual machines and bare-metal instances, so we need to look at SMBIOS. */
+ if (r == VIRTUALIZATION_AMAZON && detect_vm_smbios() == SMBIOS_VM_BIT_UNSET)
+ return VIRTUALIZATION_NONE;
+
+ /* If we haven't identified a VM, but the firmware indicates that there is one, indicate as much. We
+ * have no further information about what it is. */
+ if (r == VIRTUALIZATION_NONE && detect_vm_smbios() == SMBIOS_VM_BIT_SET)
+ return VIRTUALIZATION_VM_OTHER;
+ return r;
+#else
return VIRTUALIZATION_NONE;
+#endif
}
static int detect_vm_xen(void) {

View File

@ -0,0 +1,37 @@
From bb9d00035c00b8590c389e66b5d94334bbb7379d Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Mon, 30 Mar 2020 10:49:29 +0200
Subject: [PATCH] device: drop refuse_after
Scheduling devices after a given unit can be useful to start device *jobs* at a
specific time in the transaction, see commit 4195077ab4c823c.
This (hidden) change was introduced by commit eef85c4a3f8054d2.
(cherry picked from commit b862c25716520d9381d5a841dba0f0c14e9c970a)
[dtardon: This picks just the minimal relevant change from
c80a9a33d04fb4381327a69ce929c94a9f1d0e6c and
b862c25716520d9381d5a841dba0f0c14e9c970a]
Resolves: #2043524
---
src/core/unit.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index dfe0c243ef..9be2a0c326 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2841,8 +2841,9 @@ int unit_add_dependency(
return 0;
}
- if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) ||
- (d == UNIT_AFTER && u->type == UNIT_DEVICE)) {
+ /* Note that ordering a device unit after a unit is permitted since it
+ * allows to start its job running timeout at a specific time. */
+ if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
return 0;
}

View File

@ -0,0 +1,44 @@
From 004130ae74688eb321aadc05192bab69fe5cbcbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 22 Jul 2022 11:45:12 +0200
Subject: [PATCH] manager: limit access to private dbus socket
For the system manager, /run/systemd/private is publicly accessible, because
/run/systemd is 0755, and /run/systemd/private is 0777. For the user manager,
/run/user/<uid> is 0700, and /run/user/<uid>/systemd/private is 0777. This
does not directly cause any security issue because we check the sender in
bus_check_peercred (ucred.uid != 0 && ucred.uid != geteuid()).
But it makes sense to limit access to the socket to avoid wasting time in PID1.
Somebody could send messages there that'd we'd reject anyway. It also makes
things more explicit.
(cherry picked from commit df1cbd1adf26071aab41d96e054452a3d66103a4)
Resolves: #2119405
---
src/core/dbus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 66d838cdb4..ec6c52cb85 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -42,6 +42,7 @@
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
+#include "umask-util.h"
#include "user-util.h"
#define CONNECTIONS_MAX 4096
@@ -1019,7 +1020,8 @@ int bus_init_private(Manager *m) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate private socket: %m");
- r = bind(fd, &sa.sa, salen);
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, salen);
if (r < 0)
return log_error_errno(errno, "Failed to bind private socket: %m");

View File

@ -0,0 +1,35 @@
From b0574acc0bddceb0af47f6cce327a87041ab4b52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 11 Nov 2018 12:33:06 +0100
Subject: [PATCH] journalctl: do not treat EINTR as an error when waiting for
events
Fixup for 2a1e0f2228bbdfbc18635e959f47df7da50b62fe. Fixes #10724.
Reproducer: start 'journalctl -f' in a terminal window, change window size.
(cherry picked from commit 8e143a123276a9636987b08f555603927ca9e186)
Resolves: #2161683
---
src/journal/journalctl.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index fa83dce562..228cfe7e49 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2084,8 +2084,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
if (r < 0)
return log_error_errno(r, "Failed to determine journal waiting time: %m");
- if (ppoll(pollfds, ELEMENTSOF(pollfds), timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0)
+ if (ppoll(pollfds, ELEMENTSOF(pollfds),
+ timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) {
+ if (errno == EINTR)
+ return 0;
+
return log_error_errno(errno, "Couldn't wait for journal event: %m");
+ }
if (pollfds[1].revents & (POLLHUP|POLLERR)) { /* STDOUT has been closed? */
log_debug("Standard output has been closed.");

View File

@ -0,0 +1,76 @@
From b9dd7ee5f4d0f6d51899d7e14ac7ef2fd2840b8f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 9 Oct 2018 17:37:57 +0200
Subject: [PATCH] core: bring manager_startup() and manager_reload() more
inline
Both functions do partly the same, let's make sure they do it in the
same order, and that we don't miss some calls.
This makes a number of changes:
1. Moves exec_runtime_vacuum() two calls down in manager_startup(). This
should not have any effect but makes manager_startup() more like
manager_reload().
2. Calls manager_recheck_journal(), manager_recheck_dbus(),
manager_enqueue_sync_bus_names() in manager_startup() too. This is a
good idea since during reeexec we pass through manager_startup() and
hence can't assume dbus and journald weren't up yet, hence let's
check if they are ready to be connected to.
3. Include manager_enumerate_perpetual() in manager_reload(), too. This
is not strictly necessary, since these units are included in the
serialization anyway, but it's still a nice thing, in particular as
theoretically the deserialization could fail.
(cherry picked from commit 3ad2afb6a204513c7834c64ab864e40169874390)
Resolves: #2059633
---
src/core/manager.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index e083596e58..4a9f9bfcf9 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1665,12 +1665,12 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* Release any dynamic users no longer referenced */
dynamic_user_vacuum(m, true);
- exec_runtime_vacuum(m);
-
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
manager_vacuum_uid_refs(m);
manager_vacuum_gid_refs(m);
+ exec_runtime_vacuum(m);
+
if (serialization) {
assert(m->n_reloading > 0);
m->n_reloading--;
@@ -1681,6 +1681,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
+ /* It might be safe to log to the journal now and connect to dbus */
+ manager_recheck_journal(m);
+ manager_recheck_dbus(m);
+
+ /* Sync current state of bus names with our set of listening units */
+ (void) manager_enqueue_sync_bus_names(m);
+
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
@@ -3505,7 +3512,8 @@ int manager_reload(Manager *m) {
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
- /* First, enumerate what we can from all config files */
+ /* First, enumerate what we can from kernel and suchlike */
+ manager_enumerate_perpetual(m);
manager_enumerate(m);
/* Second, deserialize our stored data */

View File

@ -0,0 +1,35 @@
From b1b7aaf83414c5b0bed6e61d38aefe29a21fdbcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 23 Nov 2022 16:09:56 +0100
Subject: [PATCH] pam: add a call to pam_namespace
A call to pam_namespace is required so that children of user@.service end up in
a namespace as expected. pam_namespace gets called as part of the stack that
creates a session (login, sshd, gdm, etc.) and those processes end up in a
namespace, but it also needs to be called from our stack which is parallel and
descends from pid1 itself.
The call to pam_namespace is similar to the call to pam_keyinit that was added
in ab79099d1684457d040ee7c28b2012e8c1ea9a4f. The pam stack for user@.service
creates a new session which is disconnected from the parent environment. Both
calls are not suitable for inclusion in the shared part of the stack (e.g.
@system-auth on Fedora/RHEL systems), because for example su/sudo/runuser
should not include them.
(cherry picked from commit 0ef48896d9f23b9fd547a532a4e6e6b8f8b12901)
Resolves: #1861836
---
src/login/systemd-user.m4 | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4
index 20c8999331..eb291beaed 100644
--- a/src/login/systemd-user.m4
+++ b/src/login/systemd-user.m4
@@ -9,4 +9,5 @@ session required pam_selinux.so nottys open
)m4_dnl
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
+session required pam_namespace.so
session optional pam_systemd.so

View File

@ -0,0 +1,31 @@
From 4b573adbcc040fa50f1130cb8cf1bdb9559565cf Mon Sep 17 00:00:00 2001
From: Boqun Feng <boqun.feng@gmail.com>
Date: Wed, 13 Oct 2021 11:32:09 +0800
Subject: [PATCH] virt: Support detection for ARM64 Hyper-V guests
The detection of Microsoft Hyper-V VMs is done by cpuid currently,
however there is no cpuid on ARM64. And since ARM64 is now a supported
architecture for Microsoft Hyper-V guests[1], then use DMI tables to
detect a Hyper-V guest, which is more generic and works for ARM64.
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7aff79e297ee1aa0126924921fd87a4ae59d2467
(cherry picked from commit 506bbc8569014253ea8614b680ccbc4fc2513a87)
Resolves: #2158307
---
src/basic/virt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 00d1c894e6..cc95097101 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -162,6 +162,7 @@ static int detect_vm_dmi_vendor(void) {
{ "Parallels", VIRTUALIZATION_PARALLELS },
/* https://wiki.freebsd.org/bhyve */
{ "BHYVE", VIRTUALIZATION_BHYVE },
+ { "Microsoft", VIRTUALIZATION_MICROSOFT },
};
unsigned i;
int r;

View File

@ -0,0 +1,41 @@
From e732bc987f2f779e89f30193bf694e0456ab7ce0 Mon Sep 17 00:00:00 2001
From: Boqun Feng <boqun.feng@gmail.com>
Date: Tue, 23 Nov 2021 15:09:26 +0800
Subject: [PATCH] virt: Fix the detection for Hyper-V VMs
Use product_version instead of product_name in DMI table and the string
"Hyper-V" to avoid misdetection.
Fixes: #21468
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
(cherry picked from commit 76eec0649936d9ae2f9087769f463feaf0cf5cb4)
Related: #2158307
---
src/basic/virt.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/basic/virt.c b/src/basic/virt.c
index cc95097101..f750a0463f 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -143,7 +143,8 @@ static int detect_vm_dmi_vendor(void) {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
- "/sys/class/dmi/id/bios_vendor"
+ "/sys/class/dmi/id/bios_vendor",
+ "/sys/class/dmi/id/product_version" /* For Hyper-V VMs test */
};
static const struct {
@@ -162,7 +163,7 @@ static int detect_vm_dmi_vendor(void) {
{ "Parallels", VIRTUALIZATION_PARALLELS },
/* https://wiki.freebsd.org/bhyve */
{ "BHYVE", VIRTUALIZATION_BHYVE },
- { "Microsoft", VIRTUALIZATION_MICROSOFT },
+ { "Hyper-V", VIRTUALIZATION_MICROSOFT },
};
unsigned i;
int r;

View File

@ -0,0 +1,98 @@
From 9c95d8dda42de288a57638a44dd5ea967469063d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 7 Oct 2022 12:28:31 +0200
Subject: [PATCH] basic: add STRERROR() wrapper for strerror_r()
(cherry picked from commit 2c5d05b3cd986568105d67891e4010b868dea24f)
Related: #2155520
---
src/basic/util.h | 10 ++++++++++
src/test/test-util.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/src/basic/util.h b/src/basic/util.h
index 76b76d7e91..195f02cf5f 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -153,6 +153,16 @@ static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno;
}
+/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
+#define ERRNO_BUF_LEN 1024
+
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks
+ *
+ * Note that we use the GNU variant of strerror_r() here. */
+#define STRERROR(errnum) strerror_r(abs(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN)
+
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
#define UNPROTECT_ERRNO \
diff --git a/src/test/test-util.c b/src/test/test-util.c
index df60d89115..c93eaf7fc6 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -12,6 +12,7 @@
#include "process-util.h"
#include "raw-clone.h"
#include "rm-rf.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "util.h"
@@ -321,6 +322,42 @@ static void test_system_tasks_max_scale(void) {
assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
}
+static void test_strerror_not_threadsafe(void) {
+ /* Just check that strerror really is not thread-safe. */
+ log_info("strerror(%d) → %s", 200, strerror(200));
+ log_info("strerror(%d) → %s", 201, strerror(201));
+ log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX));
+
+ log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201));
+
+ /* This call is not allowed, because the first returned string becomes invalid when
+ * we call strerror the second time:
+ *
+ * log_info("strerror(%d), strerror(%d) → %s, %s", 200, 201, strerror(200), strerror(201));
+ */
+}
+
+static void test_STRERROR(void) {
+ /* Just check that STRERROR really is thread-safe. */
+ log_info("STRERROR(%d) → %s", 200, STRERROR(200));
+ log_info("STRERROR(%d) → %s", 201, STRERROR(201));
+ log_info("STRERROR(%d), STRERROR(%d) → %s, %s", 200, 201, STRERROR(200), STRERROR(201));
+
+ const char *a = STRERROR(200), *b = STRERROR(201);
+ assert_se(strstr(a, "200"));
+ assert_se(strstr(b, "201"));
+
+ /* Check with negative values */
+ assert_se(streq(a, STRERROR(-200)));
+ assert_se(streq(b, STRERROR(-201)));
+
+ const char *c = STRERROR(INT_MAX);
+ char buf[DECIMAL_STR_MAX(int)];
+ xsprintf(buf, "%d", INT_MAX); /* INT_MAX is hexadecimal, use printf to convert to decimal */
+ log_info("STRERROR(%d) → %s", INT_MAX, c);
+ assert_se(strstr(c, buf));
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -340,5 +377,8 @@ int main(int argc, char *argv[]) {
test_system_tasks_max();
test_system_tasks_max_scale();
+ test_strerror_not_threadsafe();
+ test_STRERROR();
+
return 0;
}

View File

@ -0,0 +1,529 @@
From f53c6620c55488e2a3bd92957b21b6b95a7a3d35 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Thu, 12 Jan 2023 15:47:09 +0100
Subject: [PATCH] coredump: put context array into a struct
[dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 ,
but does just the minimal change to introduce the Context struct that is
needed by the following commit.]
Related: #2155520
---
src/coredump/coredump.c | 208 +++++++++++++++++++++-------------------
1 file changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index fb3a6ecfe9..ebc56d8342 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -91,6 +91,10 @@ enum {
_CONTEXT_MAX
};
+typedef struct Context {
+ const char *meta[_CONTEXT_MAX];
+} Context;
+
typedef enum CoredumpStorage {
COREDUMP_STORAGE_NONE,
COREDUMP_STORAGE_EXTERNAL,
@@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) {
return 0;
}
-static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
+static int fix_xattr(int fd, const Context *context) {
static const char * const xattrs[_CONTEXT_MAX] = {
[CONTEXT_PID] = "user.coredump.pid",
@@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
for (i = 0; i < _CONTEXT_MAX; i++) {
int k;
- if (isempty(context[i]) || !xattrs[i])
+ if (isempty(context->meta[i]) || !xattrs[i])
continue;
- k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE);
+ k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE);
if (k < 0 && r == 0)
r = -errno;
}
@@ -230,7 +234,7 @@ static int fix_permissions(
int fd,
const char *filename,
const char *target,
- const char *context[_CONTEXT_MAX],
+ const Context *context,
uid_t uid) {
int r;
@@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) {
return 1;
}
-static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
+static int make_filename(const Context *context, char **ret) {
_cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
sd_id128_t boot = {};
int r;
assert(context);
- c = filename_escape(context[CONTEXT_COMM]);
+ c = filename_escape(context->meta[CONTEXT_COMM]);
if (!c)
return -ENOMEM;
- u = filename_escape(context[CONTEXT_UID]);
+ u = filename_escape(context->meta[CONTEXT_UID]);
if (!u)
return -ENOMEM;
@@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
if (r < 0)
return r;
- p = filename_escape(context[CONTEXT_PID]);
+ p = filename_escape(context->meta[CONTEXT_PID]);
if (!p)
return -ENOMEM;
- t = filename_escape(context[CONTEXT_TIMESTAMP]);
+ t = filename_escape(context->meta[CONTEXT_TIMESTAMP]);
if (!t)
return -ENOMEM;
@@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
}
static int save_external_coredump(
- const char *context[_CONTEXT_MAX],
+ const Context *context,
int input_fd,
char **ret_filename,
int *ret_node_fd,
@@ -334,19 +338,19 @@ static int save_external_coredump(
assert(ret_data_fd);
assert(ret_size);
- r = parse_uid(context[CONTEXT_UID], &uid);
+ r = parse_uid(context->meta[CONTEXT_UID], &uid);
if (r < 0)
return log_error_errno(r, "Failed to parse UID: %m");
- r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
+ r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit);
if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
+ return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]);
if (rlimit < page_size()) {
/* Is coredumping disabled? Then don't bother saving/processing the coredump.
* Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
* ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
log_info("Resource limits disable core dumping for process %s (%s).",
- context[CONTEXT_PID], context[CONTEXT_COMM]);
+ context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
return -EBADSLT;
}
@@ -371,7 +375,7 @@ static int save_external_coredump(
r = copy_bytes(input_fd, fd, max_size, 0);
if (r < 0) {
- log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
+ log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
goto fail;
}
*ret_truncated = r == 1;
@@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
return 1;
}
-static int change_uid_gid(const char *context[]) {
+static int change_uid_gid(const Context *context) {
uid_t uid;
gid_t gid;
int r;
- r = parse_uid(context[CONTEXT_UID], &uid);
+ r = parse_uid(context->meta[CONTEXT_UID], &uid);
if (r < 0)
return r;
@@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) {
uid = gid = 0;
}
} else {
- r = parse_gid(context[CONTEXT_GID], &gid);
+ r = parse_gid(context->meta[CONTEXT_GID], &gid);
if (r < 0)
return r;
}
@@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) {
return drop_privileges(uid, gid, 0);
}
-static bool is_journald_crash(const char *context[_CONTEXT_MAX]) {
+static bool is_journald_crash(const Context *context) {
assert(context);
- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
}
-static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) {
+static bool is_pid1_crash(const Context *context) {
assert(context);
- return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
- streq_ptr(context[CONTEXT_PID], "1");
+ return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
+ streq_ptr(context->meta[CONTEXT_PID], "1");
}
#define SUBMIT_COREDUMP_FIELDS 4
static int submit_coredump(
- const char *context[_CONTEXT_MAX],
+ Context *context,
struct iovec *iovec,
size_t n_iovec_allocated,
size_t n_iovec,
@@ -760,11 +764,11 @@ static int submit_coredump(
if (coredump_size <= arg_process_size_max) {
_cleanup_free_ char *stacktrace = NULL;
- r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace);
+ r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace);
if (r >= 0)
- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ") of user ",
- context[CONTEXT_UID], " dumped core.",
+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
+ " (", context->meta[CONTEXT_COMM], ") of user ",
+ context->meta[CONTEXT_UID], " dumped core.",
journald_crash ? "\nCoredump diverted to " : "",
journald_crash ? filename : "",
"\n\n", stacktrace);
@@ -779,9 +783,9 @@ static int submit_coredump(
if (!core_message)
#endif
log:
- core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ") of user ",
- context[CONTEXT_UID], " dumped core.",
+ core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
+ " (", context->meta[CONTEXT_COMM], ") of user ",
+ context->meta[CONTEXT_UID], " dumped core.",
journald_crash && filename ? "\nCoredump diverted to " : NULL,
journald_crash && filename ? filename : NULL);
if (!core_message)
@@ -826,7 +830,7 @@ log:
return 0;
}
-static void map_context_fields(const struct iovec *iovec, const char* context[]) {
+static void map_context_fields(const struct iovec *iovec, Context *context) {
static const char * const context_field_names[] = {
[CONTEXT_PID] = "COREDUMP_PID=",
@@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[])
/* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
* buffer, though not included in the iov_len count. (see below) */
- context[i] = p;
+ context->meta[i] = p;
break;
}
}
@@ -866,7 +870,7 @@ static int process_socket(int fd) {
_cleanup_close_ int coredump_fd = -1;
struct iovec *iovec = NULL;
size_t n_iovec = 0, n_allocated = 0, i, k;
- const char *context[_CONTEXT_MAX] = {};
+ Context context = {};
int r;
assert(fd >= 0);
@@ -950,7 +954,7 @@ static int process_socket(int fd) {
iovec[n_iovec].iov_len = (size_t) n;
cmsg_close_all(&mh);
- map_context_fields(iovec + n_iovec, context);
+ map_context_fields(iovec + n_iovec, &context);
n_iovec++;
}
@@ -960,24 +964,24 @@ static int process_socket(int fd) {
}
/* Make sure we got all data we really need */
- assert(context[CONTEXT_PID]);
- assert(context[CONTEXT_UID]);
- assert(context[CONTEXT_GID]);
- assert(context[CONTEXT_SIGNAL]);
- assert(context[CONTEXT_TIMESTAMP]);
- assert(context[CONTEXT_RLIMIT]);
- assert(context[CONTEXT_HOSTNAME]);
- assert(context[CONTEXT_COMM]);
+ assert(context.meta[CONTEXT_PID]);
+ assert(context.meta[CONTEXT_UID]);
+ assert(context.meta[CONTEXT_GID]);
+ assert(context.meta[CONTEXT_SIGNAL]);
+ assert(context.meta[CONTEXT_TIMESTAMP]);
+ assert(context.meta[CONTEXT_RLIMIT]);
+ assert(context.meta[CONTEXT_HOSTNAME]);
+ assert(context.meta[CONTEXT_COMM]);
assert(coredump_fd >= 0);
/* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s
* granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we
* are reconstructing the original kernel context, we chop this off again, here. */
- k = strlen(context[CONTEXT_TIMESTAMP]);
+ k = strlen(context.meta[CONTEXT_TIMESTAMP]);
if (k > 6)
- context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6);
+ context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6);
- r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);
+ r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd);
finish:
for (i = 0; i < n_iovec; i++)
@@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch
}
static int gather_pid_metadata(
- char* context[_CONTEXT_MAX],
+ Context *context,
char **comm_fallback,
struct iovec *iovec, size_t *n_iovec) {
@@ -1077,65 +1081,69 @@ static int gather_pid_metadata(
const char *p;
int r, signo;
- r = parse_pid(context[CONTEXT_PID], &pid);
+ r = parse_pid(context->meta[CONTEXT_PID], &pid);
if (r < 0)
- return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]);
+ return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]);
- r = get_process_comm(pid, &context[CONTEXT_COMM]);
+ r = get_process_comm(pid, &t);
if (r < 0) {
log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m");
- context[CONTEXT_COMM] = strv_join(comm_fallback, " ");
- if (!context[CONTEXT_COMM])
+ context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " ");
+ if (!context->meta[CONTEXT_COMM])
return log_oom();
- }
+ } else
+ context->meta[CONTEXT_COMM] = t;
- r = get_process_exe(pid, &context[CONTEXT_EXE]);
+ r = get_process_exe(pid, &t);
if (r < 0)
log_warning_errno(r, "Failed to get EXE, ignoring: %m");
+ else
+ context->meta[CONTEXT_EXE] = t;
- if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) {
- if (!is_journald_crash((const char**) context)) {
+ if (cg_pid_get_unit(pid, &t) >= 0) {
+ if (!is_journald_crash(context)) {
/* OK, now we know it's not the journal, hence we can make use of it now. */
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_open();
}
/* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
- if (is_pid1_crash((const char**) context)) {
+ if (is_pid1_crash(context)) {
log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
disable_coredumps();
}
- set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
- }
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]);
+ } else
+ context->meta[CONTEXT_UNIT] = t;
if (cg_pid_get_user_unit(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
/* The next few are mandatory */
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME]))
return log_oom();
- if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM]))
return log_oom();
- if (context[CONTEXT_EXE] &&
- !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
+ if (context->meta[CONTEXT_EXE] &&
+ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE]))
return log_oom();
if (sd_pid_get_session(pid, &t) >= 0)
@@ -1198,11 +1206,11 @@ static int gather_pid_metadata(
if (get_process_environ(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t);
- t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
+ t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000");
if (t)
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
- if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
+ if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
return 0; /* we successfully acquired all metadata */
@@ -1210,7 +1218,7 @@ static int gather_pid_metadata(
static int process_kernel(int argc, char* argv[]) {
- char* context[_CONTEXT_MAX] = {};
+ Context context = {};
struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
size_t i, n_iovec, n_to_free = 0;
int r;
@@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) {
return -EINVAL;
}
- context[CONTEXT_PID] = argv[1 + CONTEXT_PID];
- context[CONTEXT_UID] = argv[1 + CONTEXT_UID];
- context[CONTEXT_GID] = argv[1 + CONTEXT_GID];
- context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
- context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
- context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
- context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME];
+ context.meta[CONTEXT_PID] = argv[1 + CONTEXT_PID];
+ context.meta[CONTEXT_UID] = argv[1 + CONTEXT_UID];
+ context.meta[CONTEXT_GID] = argv[1 + CONTEXT_GID];
+ context.meta[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
+ context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
+ context.meta[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
+ context.meta[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME];
- r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
+ r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
if (r < 0)
goto finish;
@@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) {
assert(n_iovec <= ELEMENTSOF(iovec));
- if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context))
- r = submit_coredump((const char**) context,
+ if (is_journald_crash(&context) || is_pid1_crash(&context))
+ r = submit_coredump(&context,
iovec, ELEMENTSOF(iovec), n_iovec,
STDIN_FILENO);
else
@@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) {
free(iovec[i].iov_base);
/* Those fields are allocated by gather_pid_metadata */
- free(context[CONTEXT_COMM]);
- free(context[CONTEXT_EXE]);
- free(context[CONTEXT_UNIT]);
+ free((char *) context.meta[CONTEXT_COMM]);
+ free((char *) context.meta[CONTEXT_EXE]);
+ free((char *) context.meta[CONTEXT_UNIT]);
return r;
}
static int process_backtrace(int argc, char *argv[]) {
- char *context[_CONTEXT_MAX] = {};
+ Context context = {};
_cleanup_free_ char *message = NULL;
_cleanup_free_ struct iovec *iovec = NULL;
size_t n_iovec, n_allocated, n_to_free = 0, i;
@@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) {
return -EINVAL;
}
- context[CONTEXT_PID] = argv[2 + CONTEXT_PID];
- context[CONTEXT_UID] = argv[2 + CONTEXT_UID];
- context[CONTEXT_GID] = argv[2 + CONTEXT_GID];
- context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
- context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
- context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
- context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME];
+ context.meta[CONTEXT_PID] = argv[2 + CONTEXT_PID];
+ context.meta[CONTEXT_UID] = argv[2 + CONTEXT_UID];
+ context.meta[CONTEXT_GID] = argv[2 + CONTEXT_GID];
+ context.meta[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
+ context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
+ context.meta[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
+ context.meta[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME];
n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL;
/* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */
@@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) {
if (!iovec)
return log_oom();
- r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
+ r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
if (r < 0)
goto finish;
if (r > 0) {
@@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) {
if (journal_importer_eof(&importer)) {
log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
- message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
- " (", context[CONTEXT_COMM], ")"
- " of user ", context[CONTEXT_UID],
- " failed with ", context[CONTEXT_SIGNAL]);
+ message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID],
+ " (", context.meta[CONTEXT_COMM], ")"
+ " of user ", context.meta[CONTEXT_UID],
+ " failed with ", context.meta[CONTEXT_SIGNAL]);
if (!message) {
r = log_oom();
goto finish;
@@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) {
free(iovec[i].iov_base);
/* Those fields are allocated by gather_pid_metadata */
- free(context[CONTEXT_COMM]);
- free(context[CONTEXT_EXE]);
- free(context[CONTEXT_UNIT]);
+ free((char *) context.meta[CONTEXT_COMM]);
+ free((char *) context.meta[CONTEXT_EXE]);
+ free((char *) context.meta[CONTEXT_UNIT]);
return r;
}

View File

@ -0,0 +1,354 @@
From d178865d3d9940423f4d99360e3dc2fcaf0b2c96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 28 Nov 2022 12:12:55 +0100
Subject: [PATCH] coredump: do not allow user to access coredumps with changed
uid/gid/capabilities
When the user starts a program which elevates its permissions via setuid,
setgid, or capabilities set on the file, it may access additional information
which would then be visible in the coredump. We shouldn't make the the coredump
visible to the user in such cases.
Reported-by: Matthias Gerstner <mgerstner@suse.de>
This reads the /proc/<pid>/auxv file and attaches it to the process metadata as
PROC_AUXV. Before the coredump is submitted, it is parsed and if either
at_secure was set (which the kernel will do for processes that are setuid,
setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file
is not made accessible to the user. If we can't access this data, we assume the
file should not be made accessible either. In principle we could also access
the auxv data from a note in the core file, but that is much more complex and
it seems better to use the stand-alone file that is provided by the kernel.
Attaching auxv is both convient for this patch (because this way it's passed
between the stages along with other fields), but I think it makes sense to save
it in general.
We use the information early in the core file to figure out if the program was
32-bit or 64-bit and its endianness. This way we don't need heuristics to guess
whether the format of the auxv structure. This test might reject some cases on
fringe architecutes. But the impact would be limited: we just won't grant the
user permissions to view the coredump file. If people report that we're missing
some cases, we can always enhance this to support more architectures.
I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and
ppc64el, but not the whole coredump handling.
(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03)
Resolves: #2155520
---
src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 182 insertions(+), 8 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index ebc56d8342..d8acd2d3a7 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdio_ext.h>
#include <sys/prctl.h>
+#include <sys/auxv.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -88,11 +89,13 @@ enum {
CONTEXT_COMM,
CONTEXT_EXE,
CONTEXT_UNIT,
+ CONTEXT_PROC_AUXV,
_CONTEXT_MAX
};
typedef struct Context {
const char *meta[_CONTEXT_MAX];
+ size_t meta_size[_CONTEXT_MAX];
} Context;
typedef enum CoredumpStorage {
@@ -148,8 +151,7 @@ static inline uint64_t storage_size_max(void) {
return 0;
}
-static int fix_acl(int fd, uid_t uid) {
-
+static int fix_acl(int fd, uid_t uid, bool allow_user) {
#if HAVE_ACL
_cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
@@ -157,6 +159,11 @@ static int fix_acl(int fd, uid_t uid) {
int r;
assert(fd >= 0);
+ assert(uid_is_valid(uid));
+
+ /* We don't allow users to read coredumps if the uid or capabilities were changed. */
+ if (!allow_user)
+ return 0;
if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
return 0;
@@ -235,7 +242,8 @@ static int fix_permissions(
const char *filename,
const char *target,
const Context *context,
- uid_t uid) {
+ uid_t uid,
+ bool allow_user) {
int r;
@@ -245,7 +253,7 @@ static int fix_permissions(
/* Ignore errors on these */
(void) fchmod(fd, 0640);
- (void) fix_acl(fd, uid);
+ (void) fix_acl(fd, uid, allow_user);
(void) fix_xattr(fd, context);
if (fsync(fd) < 0)
@@ -316,6 +324,154 @@ static int make_filename(const Context *context, char **ret) {
return 0;
}
+static int parse_auxv64(
+ const uint64_t *auxv,
+ size_t size_bytes,
+ int *at_secure,
+ uid_t *uid,
+ uid_t *euid,
+ gid_t *gid,
+ gid_t *egid) {
+
+ assert(auxv || size_bytes == 0);
+
+ if (size_bytes % (2 * sizeof(uint64_t)) != 0)
+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
+
+ size_t words = size_bytes / sizeof(uint64_t);
+
+ /* Note that we set output variables even on error. */
+
+ for (size_t i = 0; i + 1 < words; i += 2)
+ switch (auxv[i]) {
+ case AT_SECURE:
+ *at_secure = auxv[i + 1] != 0;
+ break;
+ case AT_UID:
+ *uid = auxv[i + 1];
+ break;
+ case AT_EUID:
+ *euid = auxv[i + 1];
+ break;
+ case AT_GID:
+ *gid = auxv[i + 1];
+ break;
+ case AT_EGID:
+ *egid = auxv[i + 1];
+ break;
+ case AT_NULL:
+ if (auxv[i + 1] != 0)
+ goto error;
+ return 0;
+ }
+ error:
+ return log_warning_errno(-ENODATA,
+ "AT_NULL terminator not found, cannot parse auxv structure.");
+}
+
+static int parse_auxv32(
+ const uint32_t *auxv,
+ size_t size_bytes,
+ int *at_secure,
+ uid_t *uid,
+ uid_t *euid,
+ gid_t *gid,
+ gid_t *egid) {
+
+ assert(auxv || size_bytes == 0);
+
+ size_t words = size_bytes / sizeof(uint32_t);
+
+ if (size_bytes % (2 * sizeof(uint32_t)) != 0)
+ return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
+
+ /* Note that we set output variables even on error. */
+
+ for (size_t i = 0; i + 1 < words; i += 2)
+ switch (auxv[i]) {
+ case AT_SECURE:
+ *at_secure = auxv[i + 1] != 0;
+ break;
+ case AT_UID:
+ *uid = auxv[i + 1];
+ break;
+ case AT_EUID:
+ *euid = auxv[i + 1];
+ break;
+ case AT_GID:
+ *gid = auxv[i + 1];
+ break;
+ case AT_EGID:
+ *egid = auxv[i + 1];
+ break;
+ case AT_NULL:
+ if (auxv[i + 1] != 0)
+ goto error;
+ return 0;
+ }
+ error:
+ return log_warning_errno(-ENODATA,
+ "AT_NULL terminator not found, cannot parse auxv structure.");
+}
+
+static int grant_user_access(int core_fd, const Context *context) {
+ int at_secure = -1;
+ uid_t uid = UID_INVALID, euid = UID_INVALID;
+ uid_t gid = GID_INVALID, egid = GID_INVALID;
+ int r;
+
+ assert(core_fd >= 0);
+ assert(context);
+
+ if (!context->meta[CONTEXT_PROC_AUXV])
+ return log_warning_errno(-ENODATA, "No auxv data, not adjusting permissions.");
+
+ uint8_t elf[EI_NIDENT];
+ errno = 0;
+ if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf))
+ return log_warning_errno(errno > 0 ? -errno : -EIO,
+ "Failed to pread from coredump fd: %s",
+ errno > 0 ? STRERROR(errno) : "Unexpected EOF");
+
+ if (elf[EI_MAG0] != ELFMAG0 ||
+ elf[EI_MAG1] != ELFMAG1 ||
+ elf[EI_MAG2] != ELFMAG2 ||
+ elf[EI_MAG3] != ELFMAG3 ||
+ elf[EI_VERSION] != EV_CURRENT)
+ return log_info_errno(-EUCLEAN,
+ "Core file does not have ELF header, not adjusting permissions.");
+ if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) ||
+ !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB))
+ return log_info_errno(-EUCLEAN,
+ "Core file has strange ELF class, not adjusting permissions.");
+
+ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
+ return log_info_errno(-EUCLEAN,
+ "Core file has non-native endianness, not adjusting permissions.");
+
+ if (elf[EI_CLASS] == ELFCLASS64)
+ r = parse_auxv64((const uint64_t*) context->meta[CONTEXT_PROC_AUXV],
+ context->meta_size[CONTEXT_PROC_AUXV],
+ &at_secure, &uid, &euid, &gid, &egid);
+ else
+ r = parse_auxv32((const uint32_t*) context->meta[CONTEXT_PROC_AUXV],
+ context->meta_size[CONTEXT_PROC_AUXV],
+ &at_secure, &uid, &euid, &gid, &egid);
+ if (r < 0)
+ return r;
+
+ /* We allow access if we got all the data and at_secure is not set and
+ * the uid/gid matches euid/egid. */
+ bool ret =
+ at_secure == 0 &&
+ uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
+ gid != GID_INVALID && egid != GID_INVALID && gid == egid;
+ log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
+ ret ? "permit" : "restrict",
+ uid, euid, gid, egid, yes_no(at_secure));
+ return ret;
+}
+
static int save_external_coredump(
const Context *context,
int input_fd,
@@ -395,6 +551,8 @@ static int save_external_coredump(
goto fail;
}
+ bool allow_user = grant_user_access(fd, context) > 0;
+
#if HAVE_XZ || HAVE_LZ4
/* If we will remove the coredump anyway, do not compress. */
if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
@@ -420,7 +578,7 @@ static int save_external_coredump(
goto fail_compressed;
}
- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
+ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user);
if (r < 0)
goto fail_compressed;
@@ -443,7 +601,7 @@ static int save_external_coredump(
uncompressed:
#endif
- r = fix_permissions(fd, tmp, fn, context, uid);
+ r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
if (r < 0)
goto fail;
@@ -842,6 +1000,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
[CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=",
[CONTEXT_COMM] = "COREDUMP_COMM=",
[CONTEXT_EXE] = "COREDUMP_EXE=",
+ [CONTEXT_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
};
unsigned i;
@@ -862,6 +1021,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
/* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
* buffer, though not included in the iov_len count. (see below) */
context->meta[i] = p;
+ context->meta_size[i] = iovec->iov_len - strlen(context_field_names[i]);
break;
}
}
@@ -1070,7 +1230,7 @@ static int gather_pid_metadata(
char **comm_fallback,
struct iovec *iovec, size_t *n_iovec) {
- /* We need 27 empty slots in iovec!
+ /* We need 28 empty slots in iovec!
*
* Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid,
* with the first n_iovec fields initialized.) */
@@ -1078,6 +1238,7 @@ static int gather_pid_metadata(
uid_t owner_uid;
pid_t pid;
char *t;
+ size_t size;
const char *p;
int r, signo;
@@ -1187,6 +1348,19 @@ static int gather_pid_metadata(
if (read_full_file(p, &t, NULL) >=0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t);
+ /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
+ p = procfs_file_alloca(pid, "auxv");
+ if (read_full_file(p, &t, &size) >= 0) {
+ char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
+ if (buf) {
+ /* Add a dummy terminator to make save_context() happy. */
+ *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0';
+ iovec[(*n_iovec)++] = IOVEC_MAKE(buf, size + strlen("COREDUMP_PROC_AUXV="));
+ }
+
+ free(t);
+ }
+
if (get_process_cwd(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t);
@@ -1219,7 +1393,7 @@ static int gather_pid_metadata(
static int process_kernel(int argc, char* argv[]) {
Context context = {};
- struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
+ struct iovec iovec[30 + SUBMIT_COREDUMP_FIELDS];
size_t i, n_iovec, n_to_free = 0;
int r;

View File

@ -0,0 +1,70 @@
From a55bdb007ca24900a704f72359305b04125d9e05 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 20 Apr 2022 10:13:43 +0200
Subject: [PATCH] logind: remember our idle state and use it to detect idle
level transitions
Fixes #16391
(cherry picked from commit 4e2cfb778b9ed7f22ee98f48f28cf8678d25ad32)
Resolved: #1866955
---
src/login/logind.c | 23 +++++++++++++++++++----
src/login/logind.h | 1 +
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/login/logind.c b/src/login/logind.c
index 6b576dad0d..bb1d3f3523 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1027,18 +1027,33 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
n = now(CLOCK_MONOTONIC);
r = manager_get_idle_hint(m, &since);
- if (r <= 0)
+ if (r <= 0) {
/* Not idle. Let's check if after a timeout it might be idle then. */
elapse = n + m->idle_action_usec;
- else {
+ m->was_idle = false;
+ } else {
+
/* Idle! Let's see if it's time to do something, or if
* we shall sleep for longer. */
if (n >= since.monotonic + m->idle_action_usec &&
(m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
- log_info("System idle. Taking action.");
+ bool is_edge = false;
+
+ /* We weren't idle previously or some activity happened while we were sleeping, and now we are
+ * idle. Let's remember that for the next time and make this an edge transition. */
+ if (!m->was_idle || since.monotonic >= m->idle_action_not_before_usec) {
+ is_edge = true;
+ m->was_idle = true;
+ }
+
+ if (m->idle_action == HANDLE_LOCK && !is_edge)
+ /* We are idle and we were before so we are actually not taking any action. */
+ log_debug("System idle.");
+ else
+ log_info("System idle. Doing %s operation.", handle_action_to_string(m->idle_action));
- manager_handle_action(m, 0, m->idle_action, false, false);
+ manager_handle_action(m, 0, m->idle_action, false, is_edge);
m->idle_action_not_before_usec = n;
}
diff --git a/src/login/logind.h b/src/login/logind.h
index 606adf4fe6..b9b4a5113f 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -101,6 +101,7 @@ struct Manager {
usec_t idle_action_usec;
usec_t idle_action_not_before_usec;
HandleAction idle_action;
+ bool was_idle;
usec_t stop_idle_session_usec;

View File

@ -0,0 +1,103 @@
From 1925845dc10330e4b48fec68333fac6ef2b7bf5c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 1 Jun 2022 08:56:08 +0900
Subject: [PATCH] test: import logind test from debian/ubuntu test suite
[dtardon: Picked just the scaffolding, not the tests themselves.]
(cherry picked from commit 9c94ab0f6ff22da4278a6e9a93ddc480607c55ac)
Related: #1866955
---
test/TEST-35-LOGIN/Makefile | 1 +
test/TEST-35-LOGIN/test.sh | 55 +++++++++++++++++++++++++++++++++
test/TEST-35-LOGIN/testsuite.sh | 9 ++++++
3 files changed, 65 insertions(+)
create mode 120000 test/TEST-35-LOGIN/Makefile
create mode 100755 test/TEST-35-LOGIN/test.sh
create mode 100755 test/TEST-35-LOGIN/testsuite.sh
diff --git a/test/TEST-35-LOGIN/Makefile b/test/TEST-35-LOGIN/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-35-LOGIN/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh
new file mode 100755
index 0000000000..32410c8149
--- /dev/null
+++ b/test/TEST-35-LOGIN/test.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+TEST_DESCRIPTION="LOGIN"
+
+# shellcheck source=test/test-functions
+. "${TEST_BASE_DIR:?}/test-functions"
+
+test_setup() {
+ create_empty_image
+ mkdir -p "$TESTDIR"/root
+ mount "${LOOPDEV}p1" "$TESTDIR"/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name="${LOOPDEV}p2")
+
+ setup_basic_environment
+
+ inst_binary pkill
+ inst_binary useradd
+ inst_binary userdel
+
+ # mask some services that we do not want to run in these tests
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-hwdb-update.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-networkd.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-networkd.socket
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-resolved.service
+ ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-machined.service
+
+ # setup the testsuite service
+ cat >"$initdir"/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite.sh "$initdir"/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount "$TESTDIR"/root
+}
+
+do_test "$@"
diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh
new file mode 100755
index 0000000000..9855b4bc80
--- /dev/null
+++ b/test/TEST-35-LOGIN/testsuite.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+: >/failed
+
+touch /testok
+rm /failed

View File

@ -0,0 +1,37 @@
From 21c281585983fe2efc2b74d712d98ff7e6c013b1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 14 Jun 2022 09:11:00 +0900
Subject: [PATCH] test: introduce inst_recursive() helper function
(cherry picked from commit da0465dc95388afc15598357452afef85035c639)
Related: #1866955
---
test/test-functions | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/test/test-functions b/test/test-functions
index 19363be858..9606a1b085 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -1224,6 +1224,20 @@ inst_any() {
return 1
}
+inst_recursive() {
+ local p item
+
+ for p in "$@"; do
+ while read -r item; do
+ if [[ -d "$item" ]]; then
+ inst_dir "$item"
+ elif [[ -f "$item" ]]; then
+ inst_simple "$item"
+ fi
+ done < <(find "$p" 2>/dev/null)
+ done
+}
+
# dracut_install [-o ] <file> [<file> ... ]
# Install <file> to the initramfs image
# -o optionally install the <file> and don't fail, if it is not there

View File

@ -0,0 +1,148 @@
From 638c2418e705410344e07e77f944530df0f4608f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 1 Jul 2022 12:59:57 +0200
Subject: [PATCH] tests: verify that Lock D-Bus signal is sent when
IdleAction=lock
(cherry picked from commit 181656fc0faa885d69bc34822b8e9b5de3fdf6bf)
Related: #1866955
---
test/TEST-35-LOGIN/test.sh | 11 +++-
test/TEST-35-LOGIN/testsuite.sh | 93 +++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
diff --git a/test/TEST-35-LOGIN/test.sh b/test/TEST-35-LOGIN/test.sh
index 32410c8149..f83afcff49 100755
--- a/test/TEST-35-LOGIN/test.sh
+++ b/test/TEST-35-LOGIN/test.sh
@@ -14,14 +14,23 @@ test_setup() {
(
LOG_LEVEL=5
- eval $(udevadm info --export --query=env --name="${LOOPDEV}p2")
+ eval "$(udevadm info --export --query=env --name="${LOOPDEV}p2")"
setup_basic_environment
+ inst_binary awk
inst_binary pkill
inst_binary useradd
inst_binary userdel
+ if command -v expect >/dev/null && command -v tclsh >/dev/null ; then
+ # shellcheck disable=SC2016
+ version="$(tclsh <<< 'puts $tcl_version')"
+
+ dracut_install expect
+ inst_recursive /usr/lib64/tcl"$version" /usr/share/tcl"$version"
+ fi
+
# mask some services that we do not want to run in these tests
ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-hwdb-update.service
ln -fs /dev/null "$initdir"/etc/systemd/system/systemd-journal-catalog-update.service
diff --git a/test/TEST-35-LOGIN/testsuite.sh b/test/TEST-35-LOGIN/testsuite.sh
index 9855b4bc80..e4d72beb74 100755
--- a/test/TEST-35-LOGIN/testsuite.sh
+++ b/test/TEST-35-LOGIN/testsuite.sh
@@ -3,7 +3,100 @@
set -eux
set -o pipefail
+setup_idle_action_lock() {
+ useradd testuser ||:
+
+ mkdir -p /run/systemd/logind.conf.d/
+ cat >/run/systemd/logind.conf.d/idle-action-lock.conf <<EOF
+[Login]
+IdleAction=lock
+IdleActionSec=1s
+EOF
+
+ mkdir -p /run/systemd/systemd-logind.service.d/
+ cat >/run/systemd/systemd-logind.service.d/debug.conf <<EOF
+[Service]
+Environment=SYSTEMD_LOG_LEVEL=debug
+EOF
+
+ systemctl restart systemd-logind.service
+}
+
+teardown_idle_action_lock() {(
+ set +ex
+ rm -f /run/systemd/logind.conf.d/idle-action-lock.conf
+ rm -f /run/systemd/systemd-logind.service.d/debug.conf
+ pkill -9 -u "$(id -u testuser)"
+ userdel -r testuser
+ systemctl restart systemd-logind.service
+)}
+
+test_lock_idle_action() {
+ if ! command -v expect >/dev/null ; then
+ echo >&2 "expect not installed, skiping test ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ setup_idle_action_lock
+ trap teardown_idle_action_lock RETURN
+
+ if loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -q testuser ; then
+ echo >&2 "Session of the \'testuser\' is already present."
+ return 1
+ fi
+
+ # IdleActionSec is set 1s but the accuracy of associated timer is 30s so we
+ # need to sleep in worst case for 31s to make sure timer elapsed. We sleep
+ # here for 35s to accomodate for any possible scheudling delays.
+ cat > /tmp/test.exp <<EOF
+spawn systemd-run -G -t -p PAMName=login -p User=testuser bash
+send "sleep 35\r"
+send "echo foobar\r"
+send "sleep 35\r"
+send "exit\r"
+interact
+wait
+EOF
+
+ ts="$(date '+%H:%M:%S')"
+ busctl --match "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Session',member='Lock'" monitor > dbus.log &
+
+ expect /tmp/test.exp &
+
+ # Sleep a bit to give expect time to spawn systemd-run before we check for
+ # the presence of resulting session.
+ sleep 2
+ if [ "$(loginctl --no-legend | awk '{ print $3; }' | sort -u | grep -c testuser)" != 1 ] ; then
+ echo >&2 "\'testuser\' is expected to have exactly one session running."
+ return 1
+ fi
+
+ wait %2
+ sleep 20
+ kill %1
+
+ # We slept for 35s , in that interval all sessions should have become idle
+ # and "Lock" signal should have been sent out. Then we wrote to tty to make
+ # session active again and next we slept for another 35s so sessions have
+ # become idle again. 'Lock' signal is sent out for each session, we have at
+ # least one session, so minimum of 2 "Lock" signals must have been sent.
+ if [ "$(grep -c Member=Lock dbus.log)" -lt 2 ]; then
+ echo >&2 "Too few 'Lock' D-Bus signal sent, expected at least 2."
+ return 1
+ fi
+
+ journalctl -b -u systemd-logind.service --since="$ts" > logind.log
+ if [ "$(grep -c 'System idle. Doing lock operation.' logind.log)" -lt 2 ]; then
+ echo >&2 "System haven't entered idle state at least 2 times."
+ return 1
+ fi
+
+ rm -f dbus.log logind.log
+}
+
: >/failed
+test_lock_idle_action
+
touch /testok
rm /failed

View File

@ -0,0 +1,86 @@
From 797b00e6a6f33d2b74beba02f678bf4d12e2146b Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Tue, 14 Dec 2021 17:27:05 +0100
Subject: [PATCH] systemctl: simplify halt_main()
The code at this point is not able to tell whether it was called as
halt/poweroff/reboot or shutdown with time "now".
The code also takes a shortcut to skip logind if called as root.
That however means asking shutdown for immediate action won't trigger a
wall message.
As per https://github.com/systemd/systemd/issues/8424#issuecomment-374677315
all commands should trigger a wall message.
That simplifies the code as we can try logind first always.
(cherry picked from commit adefc8789b63225662e50ceaa282f9553b5c64eb)
Resolves: #2053273
---
src/systemctl/systemctl.c | 44 ++++++++++++++++-----------------------
1 file changed, 18 insertions(+), 26 deletions(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index b967550b97..4bedb52f2a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8658,34 +8658,23 @@ static int logind_schedule_shutdown(void) {
static int halt_main(void) {
int r;
- r = logind_check_inhibitors(arg_action);
- if (r < 0)
- return r;
-
+ /* always try logind first */
if (arg_when > 0)
- return logind_schedule_shutdown();
-
- if (geteuid() != 0) {
- if (arg_dry_run || arg_force > 0) {
- (void) must_be_root();
- return -EPERM;
- }
+ r = logind_schedule_shutdown();
+ else {
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
- /* Try logind if we are a normal user and no special
- * mode applies. Maybe PolicyKit allows us to shutdown
- * the machine. */
- if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
- r = logind_reboot(arg_action);
- if (r >= 0)
- return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not
- * supported on the local system or
- * already in progress */
- return r;
- /* on all other errors, try low-level operation */
- }
+ r = logind_reboot(arg_action);
}
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation is not supported on the local system or already in
+ * progress */
+ return r;
+ /* on all other errors, try low-level operation */
/* In order to minimize the difference between operation with and
* without logind, we explicitly enable non-blocking mode for this,
@@ -8695,7 +8684,10 @@ static int halt_main(void) {
if (!arg_dry_run && !arg_force)
return start_with_fallback();
- assert(geteuid() == 0);
+ if (geteuid() != 0) {
+ (void) must_be_root();
+ return -EPERM;
+ }
if (!arg_no_wtmp) {
if (sd_booted() > 0)

View File

@ -0,0 +1,51 @@
From 1d63577410cde215c04921d62f435259a6b258d7 Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Mon, 20 Dec 2021 18:05:50 +0100
Subject: [PATCH] systemctl: shutdown don't fallback on auth fail
For shutdowns don't fall back to starting the target directly if talking
to logind failed with auth failure. That would just lead to another
polkit auth attempt.
(cherry picked from commit 38d55bf2641f345445cb4e6a5e5e808555591db2)
Related: #2053273
---
src/systemctl/systemctl.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 4bedb52f2a..199f736f7f 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3675,8 +3675,8 @@ static int start_special(int argc, char *argv[], void *userdata) {
r = logind_reboot(a);
if (r >= 0)
return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not supported or already in progress */
+ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation requires auth, is not supported or already in progress */
return r;
/* On all other errors, try low-level operation. In order to minimize the difference between
@@ -8644,7 +8644,7 @@ static int logind_schedule_shutdown(void) {
action,
arg_when);
if (r < 0)
- return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
+ return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r));
if (!arg_quiet)
log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
@@ -8670,8 +8670,8 @@ static int halt_main(void) {
}
if (r >= 0)
return r;
- if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* Requested operation is not supported on the local system or already in
+ if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
+ /* Requested operation requires auth, is not supported on the local system or already in
* progress */
return r;
/* on all other errors, try low-level operation */

View File

@ -0,0 +1,82 @@
From d36295d7c1b110d150b7af6e3354c28af4c4884d Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 30 Jan 2023 14:27:24 +0100
Subject: [PATCH] systemctl: reintroduce the original halt_main()
RHEL-only
Related: #2053273
---
src/systemctl/systemctl.c | 59 +++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 199f736f7f..a26e4a913a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8655,6 +8655,65 @@ static int logind_schedule_shutdown(void) {
#endif
}
+static int halt_main_old(void) {
+ int r;
+
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
+
+ if (arg_when > 0)
+ return logind_schedule_shutdown();
+
+ if (geteuid() != 0) {
+ if (arg_dry_run || arg_force > 0) {
+ (void) must_be_root();
+ return -EPERM;
+ }
+
+ /* Try logind if we are a normal user and no special
+ * mode applies. Maybe PolicyKit allows us to shutdown
+ * the machine. */
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
+ r = logind_reboot(arg_action);
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not
+ * supported on the local system or
+ * already in progress */
+ return r;
+ /* on all other errors, try low-level operation */
+ }
+ }
+
+ /* In order to minimize the difference between operation with and
+ * without logind, we explicitly enable non-blocking mode for this,
+ * as logind's shutdown operations are always non-blocking. */
+ arg_no_block = true;
+
+ if (!arg_dry_run && !arg_force)
+ return start_with_fallback();
+
+ assert(geteuid() == 0);
+
+ if (!arg_no_wtmp) {
+ if (sd_booted() > 0)
+ log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
+ else {
+ r = utmp_put_shutdown();
+ if (r < 0)
+ log_warning_errno(r, "Failed to write utmp record: %m");
+ }
+ }
+
+ if (arg_dry_run)
+ return 0;
+
+ r = halt_now(arg_action);
+ return log_error_errno(r, "Failed to reboot: %m");
+}
+
static int halt_main(void) {
int r;

View File

@ -0,0 +1,44 @@
From 74632586b46c7e88b09c57eec50f9c4aed254b98 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 30 Jan 2023 14:31:23 +0100
Subject: [PATCH] systemctl: preserve old behavior unless requested
Currently, the legacy shutdown commands ignore inhibitors and reboot
immediately if run by root. Let's preserve that behavior in RHEL-8 by
default. The new behavior can be turned on by those who want it by
exporting SYSTEMD_NEW_SHUTDOWN=1 .
RHEL-only
Related: #2053273
---
src/systemctl/systemctl.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index a26e4a913a..1546119ce5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -8714,7 +8714,7 @@ static int halt_main_old(void) {
return log_error_errno(r, "Failed to reboot: %m");
}
-static int halt_main(void) {
+static int halt_main_new(void) {
int r;
/* always try logind first */
@@ -8765,6 +8765,13 @@ static int halt_main(void) {
return log_error_errno(r, "Failed to reboot: %m");
}
+static int halt_main(void) {
+ if (getenv_bool("SYSTEMD_NEW_SHUTDOWN") > 0)
+ return halt_main_new();
+ else
+ return halt_main_old();
+}
+
static int runlevel_main(void) {
int r, runlevel, previous;

View File

@ -0,0 +1,43 @@
From ea3910e561f043f5a131a846862955c77169da1b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 19 Nov 2018 11:39:45 +0100
Subject: [PATCH] pam_systemd: suppress LOG_DEBUG log messages if debugging is
off
In the PAM module we need to suppress LOG_DEBUG messages manually, if
debug logging is not on, as PAM won't do this for us. We did this
correctly for most log messages already, but two were missing. Let's fix
those too.
Fixes: #10822
(cherry picked from commit 2675747f3cdd6f1e6236bbb2f79abfa53fb307f1)
Resolves: #2170084
---
src/login/pam_systemd.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 64e1b4d1bf..c87e980b18 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -476,7 +476,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
- pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
+ if (debug)
+ pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
vtnr = 0;
}
@@ -577,7 +578,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
- pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
+ if (debug)
+ pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));
return PAM_SUCCESS;
} else {
pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));

View File

@ -0,0 +1,50 @@
From 33351e103734188a4a30b88e7f2ea0613d628599 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Thu, 16 Feb 2023 15:56:52 +0100
Subject: [PATCH] udev/net_id: introduce naming scheme for RHEL-8.8
RHEL-only
Resolves: #2170499
---
man/systemd.net-naming-scheme.xml | 6 ++++++
src/udev/udev-builtin-net_id.c | 2 ++
2 files changed, 8 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index a567483995..3cc7719e99 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -328,6 +328,12 @@
for that, the limit is increased to now 65535.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-8.8</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
+ </varlistentry>
+
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known to this
particular version of systemd.</para>
</variablelist>
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index df84acf27c..ef2bb1b08e 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -141,6 +141,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_8_5 = NAMING_RHEL_8_4,
NAMING_RHEL_8_6 = NAMING_RHEL_8_4,
NAMING_RHEL_8_7 = NAMING_RHEL_8_4|NAMING_SLOT_FUNCTION_ID|NAMING_16BIT_INDEX,
+ NAMING_RHEL_8_8 = NAMING_RHEL_8_7,
_NAMING_SCHEME_FLAGS_INVALID = -1,
} NamingSchemeFlags;
@@ -161,6 +162,7 @@ static const NamingScheme naming_schemes[] = {
{ "rhel-8.5", NAMING_RHEL_8_5 },
{ "rhel-8.6", NAMING_RHEL_8_6 },
{ "rhel-8.7", NAMING_RHEL_8_7 },
+ { "rhel-8.8", NAMING_RHEL_8_8 },
/* … add more schemes here, as the logic to name devices is updated … */
};

View File

@ -0,0 +1,176 @@
From 8f0a91b5192b72eb8b0f06e04ef3515d0397fcb8 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:20:25 +0200
Subject: [PATCH] journald: add API to move logging from /var to /run again
We now have this nice little Varlink API, let's beef it up a bit.
[dtardon: This diverges from the upstream commit in two ways: One is
that the new action is bound to a signal, as varlink is not available.
The other is that this introduces a new "flag" file
/run/systemd/journal/relinquished, which is essentially the opposite of
/run/systemd/journal/flushed (hence at most one of them may exist at any
time).]
(cherry picked from commit b4e26d1d8e582d78e67ed766177f10e8e194404c)
Related: #1873540
---
src/journal/journald-server.c | 64 ++++++++++++++++++++++++++++-------
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7632e2d9d0..279a32768c 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -283,13 +283,14 @@ static bool flushed_flag_is_set(void) {
return access("/run/systemd/journal/flushed", F_OK) >= 0;
}
-static int system_journal_open(Server *s, bool flush_requested) {
+static int system_journal_open(Server *s, bool flush_requested, bool relinquish_requested) {
const char *fn;
int r = 0;
if (!s->system_journal &&
IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
- (flush_requested || flushed_flag_is_set())) {
+ (flush_requested || flushed_flag_is_set()) &&
+ !relinquish_requested) {
/* If in auto mode: first try to create the machine
* path, but not the prefix.
@@ -331,7 +332,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
fn = strjoina(s->runtime_storage.path, "/system.journal");
- if (s->system_journal) {
+ if (s->system_journal && !relinquish_requested) {
/* Try to open the runtime journal, but only
* if it already exists, so that we can flush
@@ -386,7 +387,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
* else that's left the journals as NULL).
*
* Fixes https://github.com/systemd/systemd/issues/3968 */
- (void) system_journal_open(s, false);
+ (void) system_journal_open(s, false, false);
/* We split up user logs only on /var, not on /run. If the
* runtime file is open, we write to it exclusively, in order
@@ -964,7 +965,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
char ts[FORMAT_TIMESPAN_MAX];
usec_t start;
unsigned n = 0;
- int r;
+ int r, k;
assert(s);
@@ -977,7 +978,7 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
if (require_flag_file && !flushed_flag_is_set())
return 0;
- (void) system_journal_open(s, true);
+ (void) system_journal_open(s, true, false);
if (!s->system_journal)
return 0;
@@ -1056,6 +1057,13 @@ finish:
n),
NULL);
+ if (unlink("/run/systemd/journal/relinquished") < 0 && errno != ENOENT)
+ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/relinquished, ignoring: %m");
+
+ k = touch("/run/systemd/journal/flushed");
+ if (k < 0)
+ log_warning_errno(k, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
+
return r;
}
@@ -1180,7 +1188,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Server *s = userdata;
- int r;
assert(s);
@@ -1190,10 +1197,6 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
server_sync(s);
server_vacuum(s, false);
- r = touch("/run/systemd/journal/flushed");
- if (r < 0)
- log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
-
server_space_usage_message(s, NULL);
return 0;
}
@@ -1250,12 +1253,43 @@ static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo
return 0;
}
+
+static int dispatch_sigrtmin2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+
+ if (s->storage == STORAGE_NONE)
+ return 0;
+
+ if (s->runtime_journal && !s->system_journal)
+ return 0;
+
+ log_debug("Received request to relinquish /var from PID " PID_FMT, si->ssi_pid);
+
+ (void) system_journal_open(s, false, true);
+
+ s->system_journal = journal_file_close(s->system_journal);
+ ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_close);
+ set_clear_with_destructor(s->deferred_closes, journal_file_close);
+
+ if (unlink("/run/systemd/journal/flushed") < 0 && errno != ENOENT)
+ log_warning_errno(errno, "Failed to unlink /run/systemd/journal/flushed, ignoring: %m") ;
+
+ r = write_timestamp_file_atomic("/run/systemd/journal/relinquished", now(CLOCK_MONOTONIC));
+ if (r < 0)
+ log_warning_errno(r, "Failed to write /run/systemd/journal/relinquished, ignoring: %m");
+
+ return 0;
+}
+
static int setup_signals(Server *s) {
int r;
assert(s);
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+2, -1) >= 0);
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
if (r < 0)
@@ -1294,6 +1328,10 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
+ r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+2, dispatch_sigrtmin2, s);
+ if (r < 0)
+ return r;
+
r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15);
if (r < 0)
return r;
@@ -1876,7 +1914,7 @@ int server_init(Server *s) {
(void) client_context_acquire_default(s);
- return system_journal_open(s, false);
+ return system_journal_open(s, false, false);
}
void server_maybe_append_tags(Server *s) {

View File

@ -0,0 +1,242 @@
From fa93a97bdf18906d9517f4183802456986490c89 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:21:02 +0200
Subject: [PATCH] journalctl: add new --relinquish and --smart-relinquish
options
The latter is identical to the former, but becomes a NOP if
/var/log/journal is on the same mount as /, and thus during shutdown
unmounting /var is not necessary and hence we can keep logging until the
very end.
[dtardon: The only divergence from the upstream commit is the impl. of
relinquish_var().]
(cherry picked from commit c0dfcb318c28d87e1176a8ad87ac7cc4ecc50305)
Related: #1873540
---
src/journal/journalctl.c | 161 +++++++++++++++++++++++++--------------
1 file changed, 103 insertions(+), 58 deletions(-)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 228cfe7e49..6928c79a06 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -47,6 +47,7 @@
#include "log.h"
#include "logs-show.h"
#include "mkdir.h"
+#include "mount-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
@@ -162,6 +163,7 @@ static enum {
ACTION_UPDATE_CATALOG,
ACTION_LIST_BOOTS,
ACTION_FLUSH,
+ ACTION_RELINQUISH_VAR,
ACTION_SYNC,
ACTION_ROTATE,
ACTION_VACUUM,
@@ -358,6 +360,8 @@ static void help(void) {
" --vacuum-time=TIME Remove journal files older than specified time\n"
" --verify Verify journal file consistency\n"
" --sync Synchronize unwritten journal messages to disk\n"
+ " --relinquish-var Stop logging to disk, log to temporary file system\n"
+ " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
" --flush Flush all journal data from /run into /var\n"
" --rotate Request immediate rotation of the journal files\n"
" --header Show journal header information\n"
@@ -402,6 +406,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_UTC,
ARG_SYNC,
ARG_FLUSH,
+ ARG_RELINQUISH_VAR,
+ ARG_SMART_RELINQUISH_VAR,
ARG_ROTATE,
ARG_VACUUM_SIZE,
ARG_VACUUM_FILES,
@@ -411,64 +417,66 @@ static int parse_argv(int argc, char *argv[]) {
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version" , no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "pager-end", no_argument, NULL, 'e' },
- { "follow", no_argument, NULL, 'f' },
- { "force", no_argument, NULL, ARG_FORCE },
- { "output", required_argument, NULL, 'o' },
- { "all", no_argument, NULL, 'a' },
- { "full", no_argument, NULL, 'l' },
- { "no-full", no_argument, NULL, ARG_NO_FULL },
- { "lines", optional_argument, NULL, 'n' },
- { "no-tail", no_argument, NULL, ARG_NO_TAIL },
- { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
- { "quiet", no_argument, NULL, 'q' },
- { "merge", no_argument, NULL, 'm' },
- { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
- { "boot", optional_argument, NULL, 'b' },
- { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
- { "dmesg", no_argument, NULL, 'k' },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "directory", required_argument, NULL, 'D' },
- { "file", required_argument, NULL, ARG_FILE },
- { "root", required_argument, NULL, ARG_ROOT },
- { "header", no_argument, NULL, ARG_HEADER },
- { "identifier", required_argument, NULL, 't' },
- { "priority", required_argument, NULL, 'p' },
- { "grep", required_argument, NULL, 'g' },
- { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
- { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
- { "interval", required_argument, NULL, ARG_INTERVAL },
- { "verify", no_argument, NULL, ARG_VERIFY },
- { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
- { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
- { "cursor", required_argument, NULL, 'c' },
- { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
- { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
- { "since", required_argument, NULL, 'S' },
- { "until", required_argument, NULL, 'U' },
- { "unit", required_argument, NULL, 'u' },
- { "user-unit", required_argument, NULL, ARG_USER_UNIT },
- { "field", required_argument, NULL, 'F' },
- { "fields", no_argument, NULL, 'N' },
- { "catalog", no_argument, NULL, 'x' },
- { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
- { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
- { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
- { "reverse", no_argument, NULL, 'r' },
- { "machine", required_argument, NULL, 'M' },
- { "utc", no_argument, NULL, ARG_UTC },
- { "flush", no_argument, NULL, ARG_FLUSH },
- { "sync", no_argument, NULL, ARG_SYNC },
- { "rotate", no_argument, NULL, ARG_ROTATE },
- { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
- { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
- { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
- { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
- { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
+ { "help", no_argument, NULL, 'h' },
+ { "version" , no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "pager-end", no_argument, NULL, 'e' },
+ { "follow", no_argument, NULL, 'f' },
+ { "force", no_argument, NULL, ARG_FORCE },
+ { "output", required_argument, NULL, 'o' },
+ { "all", no_argument, NULL, 'a' },
+ { "full", no_argument, NULL, 'l' },
+ { "no-full", no_argument, NULL, ARG_NO_FULL },
+ { "lines", optional_argument, NULL, 'n' },
+ { "no-tail", no_argument, NULL, ARG_NO_TAIL },
+ { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */
+ { "quiet", no_argument, NULL, 'q' },
+ { "merge", no_argument, NULL, 'm' },
+ { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
+ { "boot", optional_argument, NULL, 'b' },
+ { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
+ { "dmesg", no_argument, NULL, 'k' },
+ { "system", no_argument, NULL, ARG_SYSTEM },
+ { "user", no_argument, NULL, ARG_USER },
+ { "directory", required_argument, NULL, 'D' },
+ { "file", required_argument, NULL, ARG_FILE },
+ { "root", required_argument, NULL, ARG_ROOT },
+ { "header", no_argument, NULL, ARG_HEADER },
+ { "identifier", required_argument, NULL, 't' },
+ { "priority", required_argument, NULL, 'p' },
+ { "grep", required_argument, NULL, 'g' },
+ { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
+ { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
+ { "interval", required_argument, NULL, ARG_INTERVAL },
+ { "verify", no_argument, NULL, ARG_VERIFY },
+ { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
+ { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
+ { "cursor", required_argument, NULL, 'c' },
+ { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
+ { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
+ { "since", required_argument, NULL, 'S' },
+ { "until", required_argument, NULL, 'U' },
+ { "unit", required_argument, NULL, 'u' },
+ { "user-unit", required_argument, NULL, ARG_USER_UNIT },
+ { "field", required_argument, NULL, 'F' },
+ { "fields", no_argument, NULL, 'N' },
+ { "catalog", no_argument, NULL, 'x' },
+ { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
+ { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
+ { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
+ { "reverse", no_argument, NULL, 'r' },
+ { "machine", required_argument, NULL, 'M' },
+ { "utc", no_argument, NULL, ARG_UTC },
+ { "flush", no_argument, NULL, ARG_FLUSH },
+ { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR },
+ { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR },
+ { "sync", no_argument, NULL, ARG_SYNC },
+ { "rotate", no_argument, NULL, ARG_ROTATE },
+ { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
+ { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
+ { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
+ { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
+ { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
{}
};
@@ -893,6 +901,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_FLUSH;
break;
+ case ARG_SMART_RELINQUISH_VAR: {
+ int root_mnt_id, log_mnt_id;
+
+ /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
+ * if it's on the same mount as the root file system there's no point in
+ * relinquishing access and we can leave journald write to it until the very last
+ * moment. */
+
+ r = path_get_mnt_id("/", &root_mnt_id);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get root mount ID, ignoring: %m");
+ else {
+ r = path_get_mnt_id("/var/log/journal/", &log_mnt_id);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m");
+ else if (root_mnt_id == log_mnt_id) {
+ log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
+ return 0;
+ } else
+ log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
+ }
+
+ _fallthrough_;
+ }
+
+ case ARG_RELINQUISH_VAR:
+ arg_action = ACTION_RELINQUISH_VAR;
+ break;
+
case ARG_ROTATE:
arg_action = ACTION_ROTATE;
break;
@@ -2056,6 +2093,10 @@ static int send_signal_and_wait(int sig, const char *watch_path) {
return 0;
}
+static int relinquish_var(void) {
+ return send_signal_and_wait(SIGRTMIN+2, "/run/systemd/journal/relinquished");
+}
+
static int rotate(void) {
return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
}
@@ -2171,6 +2212,10 @@ int main(int argc, char *argv[]) {
r = flush_to_var();
goto finish;
+ case ACTION_RELINQUISH_VAR:
+ r = relinquish_var();
+ goto finish;
+
case ACTION_SYNC:
r = sync_journal();
goto finish;

View File

@ -0,0 +1,26 @@
From ce6531045b337c3f793d1d74f1e5641e658805bb Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 5 Apr 2019 18:22:31 +0200
Subject: [PATCH] units: automatically revert to /run logging on shutdown if
necessary
Fixes: #867
(cherry picked from commit 1e187d2dd52cbb4f0bb30e4d96acf7f72a145b91)
Resolves: #1873540
---
units/systemd-journal-flush.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in
index 439f5f3f76..653dcebe0e 100644
--- a/units/systemd-journal-flush.service.in
+++ b/units/systemd-journal-flush.service.in
@@ -19,6 +19,7 @@ RequiresMountsFor=/var/log/journal
[Service]
ExecStart=@rootbindir@/journalctl --flush
+ExecStop=@rootbindir@/journalctl --smart-relinquish-var
Type=oneshot
RemainAfterExit=yes
TimeoutSec=90s

View File

@ -0,0 +1,929 @@
From 2f75df5cd6dcd56775fec9e89fc79672e702d826 Mon Sep 17 00:00:00 2001
From: Eric DeVolder <eric.devolder@oracle.com>
Date: Thu, 16 May 2019 08:59:01 -0500
Subject: [PATCH] pstore: Tool to archive contents of pstore
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch introduces the systemd pstore service which will archive the
contents of the Linux persistent storage filesystem, pstore, to other storage,
thus preserving the existing information contained in the pstore, and clearing
pstore storage for future error events.
Linux provides a persistent storage file system, pstore[1], that can store
error records when the kernel dies (or reboots or powers-off). These records in
turn can be referenced to debug kernel problems (currently the kernel stuffs
the tail of the dmesg, which also contains a stack backtrace, into pstore).
The pstore file system supports a variety of backends that map onto persistent
storage, such as the ACPI ERST[2, Section 18.5 Error Serialization] and UEFI
variables[3 Appendix N Common Platform Error Record]. The pstore backends
typically offer a relatively small amount of persistent storage, e.g. 64KiB,
which can quickly fill up and thus prevent subsequent kernel crashes from
recording errors. Thus there is a need to monitor and extract the pstore
contents so that future kernel problems can also record information in the
pstore.
The pstore service is independent of the kdump service. In cloud environments
specifically, host and guest filesystems are on remote filesystems (eg. iSCSI
or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation
of networking software *and* hardware *and* infrastructure. Thus it may not be
possible to capture a kernel coredump to a file since writes over the network
may not be possible.
The pstore backend, on the other hand, is completely local and provides a path
to store error records which will survive a reboot and aid in post-mortem
debugging.
Usage Notes:
This tool moves files from /sys/fs/pstore into /var/lib/systemd/pstore.
To enable kernel recording of error records into pstore, one must either pass
crash_kexec_post_notifiers[4] to the kernel command line or enable via 'echo Y
> /sys/module/kernel/parameters/crash_kexec_post_notifiers'. This option
invokes the recording of errors into pstore *before* an attempt to kexec/kdump
on a kernel crash.
Optionally, to record reboots and shutdowns in the pstore, one can either pass
the printk.always_kmsg_dump[4] to the kernel command line or enable via 'echo Y >
/sys/module/printk/parameters/always_kmsg_dump'. This option enables code on the
shutdown path to record information via pstore.
This pstore service is a oneshot service. When run, the service invokes
systemd-pstore which is a tool that performs the following:
- reads the pstore.conf configuration file
- collects the lists of files in the pstore (eg. /sys/fs/pstore)
- for certain file types (eg. dmesg) a handler is invoked
- for all other files, the file is moved from pstore
- In the case of dmesg handler, final processing occurs as such:
- files processed in reverse lexigraphical order to faciliate
reconstruction of original dmesg
- the filename is examined to determine which dmesg it is a part
- the file is appended to the reconstructed dmesg
For example, the following pstore contents:
root@vm356:~# ls -al /sys/fs/pstore
total 0
drwxr-x--- 2 root root 0 May 9 09:50 .
drwxr-xr-x 7 root root 0 May 9 09:50 ..
-r--r--r-- 1 root root 1610 May 9 09:49 dmesg-efi-155741337601001
-r--r--r-- 1 root root 1778 May 9 09:49 dmesg-efi-155741337602001
-r--r--r-- 1 root root 1726 May 9 09:49 dmesg-efi-155741337603001
-r--r--r-- 1 root root 1746 May 9 09:49 dmesg-efi-155741337604001
-r--r--r-- 1 root root 1686 May 9 09:49 dmesg-efi-155741337605001
-r--r--r-- 1 root root 1690 May 9 09:49 dmesg-efi-155741337606001
-r--r--r-- 1 root root 1775 May 9 09:49 dmesg-efi-155741337607001
-r--r--r-- 1 root root 1811 May 9 09:49 dmesg-efi-155741337608001
-r--r--r-- 1 root root 1817 May 9 09:49 dmesg-efi-155741337609001
-r--r--r-- 1 root root 1795 May 9 09:49 dmesg-efi-155741337710001
-r--r--r-- 1 root root 1770 May 9 09:49 dmesg-efi-155741337711001
-r--r--r-- 1 root root 1796 May 9 09:49 dmesg-efi-155741337712001
-r--r--r-- 1 root root 1787 May 9 09:49 dmesg-efi-155741337713001
-r--r--r-- 1 root root 1808 May 9 09:49 dmesg-efi-155741337714001
-r--r--r-- 1 root root 1754 May 9 09:49 dmesg-efi-155741337715001
results in the following:
root@vm356:~# ls -al /var/lib/systemd/pstore/155741337/
total 92
drwxr-xr-x 2 root root 4096 May 9 09:50 .
drwxr-xr-x 4 root root 40 May 9 09:50 ..
-rw-r--r-- 1 root root 1610 May 9 09:50 dmesg-efi-155741337601001
-rw-r--r-- 1 root root 1778 May 9 09:50 dmesg-efi-155741337602001
-rw-r--r-- 1 root root 1726 May 9 09:50 dmesg-efi-155741337603001
-rw-r--r-- 1 root root 1746 May 9 09:50 dmesg-efi-155741337604001
-rw-r--r-- 1 root root 1686 May 9 09:50 dmesg-efi-155741337605001
-rw-r--r-- 1 root root 1690 May 9 09:50 dmesg-efi-155741337606001
-rw-r--r-- 1 root root 1775 May 9 09:50 dmesg-efi-155741337607001
-rw-r--r-- 1 root root 1811 May 9 09:50 dmesg-efi-155741337608001
-rw-r--r-- 1 root root 1817 May 9 09:50 dmesg-efi-155741337609001
-rw-r--r-- 1 root root 1795 May 9 09:50 dmesg-efi-155741337710001
-rw-r--r-- 1 root root 1770 May 9 09:50 dmesg-efi-155741337711001
-rw-r--r-- 1 root root 1796 May 9 09:50 dmesg-efi-155741337712001
-rw-r--r-- 1 root root 1787 May 9 09:50 dmesg-efi-155741337713001
-rw-r--r-- 1 root root 1808 May 9 09:50 dmesg-efi-155741337714001
-rw-r--r-- 1 root root 1754 May 9 09:50 dmesg-efi-155741337715001
-rw-r--r-- 1 root root 26754 May 9 09:50 dmesg.txt
where dmesg.txt is reconstructed from the group of related
dmesg-efi-155741337* files.
Configuration file:
The pstore.conf configuration file has four settings, described below.
- Storage : one of "none", "external", or "journal". With "none", this
tool leaves the contents of pstore untouched. With "external", the
contents of the pstore are moved into the /var/lib/systemd/pstore,
as well as logged into the journal. With "journal", the contents of
the pstore are recorded only in the systemd journal. The default is
"external".
- Unlink : is a boolean. When "true", the default, then files in the
pstore are removed once processed. When "false", processing of the
pstore occurs normally, but the pstore files remain.
References:
[1] "Persistent storage for a kernel's dying breath",
March 23, 2011.
https://lwn.net/Articles/434821/
[2] "Advanced Configuration and Power Interface Specification",
version 6.2, May 2017.
https://www.uefi.org/sites/default/files/resources/ACPI_6_2.pdf
[3] "Unified Extensible Firmware Interface Specification",
version 2.8, March 2019.
https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf
[4] "The kernels command-line parameters",
https://static.lwn.net/kerneldoc/admin-guide/kernel-parameters.html
(cherry picked from commit 9b4abc69b201e5d7295e1b0762883659f053e747)
Resolves: #2158832
---
man/pstore.conf.xml | 89 +++++++
man/rules/meson.build | 2 +
man/systemd-pstore.xml | 99 ++++++++
meson.build | 20 ++
meson_options.txt | 2 +
src/pstore/meson.build | 10 +
src/pstore/pstore.c | 395 ++++++++++++++++++++++++++++++++
src/pstore/pstore.conf | 16 ++
units/meson.build | 1 +
units/systemd-pstore.service.in | 24 ++
10 files changed, 658 insertions(+)
create mode 100644 man/pstore.conf.xml
create mode 100644 man/systemd-pstore.xml
create mode 100644 src/pstore/meson.build
create mode 100644 src/pstore/pstore.c
create mode 100644 src/pstore/pstore.conf
create mode 100644 units/systemd-pstore.service.in
diff --git a/man/pstore.conf.xml b/man/pstore.conf.xml
new file mode 100644
index 0000000000..b5cda47d02
--- /dev/null
+++ b/man/pstore.conf.xml
@@ -0,0 +1,89 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="pstore.conf" conditional="ENABLE_PSTORE"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>pstore.conf</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>pstore.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>pstore.conf</refname>
+ <refname>pstore.conf.d</refname>
+ <refpurpose>PStore configuration file</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/etc/systemd/pstore.conf</filename>
+ <filename>/etc/systemd/pstore.conf.d/*</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>This file configures the behavior of
+ <citerefentry><refentrytitle>systemd-pstore</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ a tool for archiving the contents of the persistent storage filesystem,
+ <ulink url="https://www.kernel.org/doc/Documentation/ABI/testing/pstore">pstore</ulink>.
+ </para>
+ </refsect1>
+
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>All options are configured in the
+ <literal>[PStore]</literal> section:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><varname>Storage=</varname></term>
+
+ <listitem><para>Controls where to archive (i.e. copy) files from the pstore filesystem. One of <literal>none</literal>,
+ <literal>external</literal>, and <literal>journal</literal>. When
+ <literal>none</literal>, the tool exits without processing files in the pstore filesystem.
+ When <literal>external</literal> (the default), files are archived into <filename>/var/lib/systemd/pstore/</filename>,
+ and logged into the journal.
+ When <literal>journal</literal>, pstore file contents are logged only in the journal.</para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>Unlink=</varname></term>
+
+ <listitem><para>Controls whether or not files are removed from pstore after processing.
+ Takes a boolean value. When true, a pstore file is removed from the pstore once it has been
+ archived (either to disk or into the journal). When false, processing of pstore files occurs
+ normally, but the files remain in the pstore.
+ The default is true in order to maintain the pstore in a nearly empty state, so that the pstore
+ has storage available for the next kernel error event.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The defaults for all values are listed as comments in the
+ template <filename>/etc/systemd/pstore.conf</filename> file that
+ is installed by default.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/rules/meson.build b/man/rules/meson.build
index e6c0a99bbd..6295330c5e 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -44,6 +44,7 @@ manpages = [
['os-release', '5', [], ''],
['pam_systemd', '8', [], 'HAVE_PAM'],
['portablectl', '1', [], 'ENABLE_PORTABLED'],
+ ['pstore.conf', '5', ['pstore.conf.d'], 'ENABLE_PSTORE'],
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
['runlevel', '8', [], 'ENABLE_UTMP'],
@@ -633,6 +634,7 @@ manpages = [
['systemd-nspawn', '1', [], ''],
['systemd-path', '1', [], ''],
['systemd-portabled.service', '8', ['systemd-portabled'], 'ENABLE_PORTABLED'],
+ ['systemd-pstore', '8', ['systemd-pstore.service'], 'ENABLE_PSTORE'],
['systemd-quotacheck.service',
'8',
['systemd-quotacheck'],
diff --git a/man/systemd-pstore.xml b/man/systemd-pstore.xml
new file mode 100644
index 0000000000..dd1aa5e83b
--- /dev/null
+++ b/man/systemd-pstore.xml
@@ -0,0 +1,99 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd-pstore" conditional='ENABLE_PSTORE'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>systemd-pstore</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-pstore</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-pstore</refname>
+ <refname>systemd-pstore.service</refname>
+ <refpurpose>Tool to archive contents of the persistent storage filesytem</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>/usr/lib/systemd/systemd-pstore</filename></para>
+ <para><filename>systemd-pstore.service</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para><filename>systemd-pstore.service</filename> is a system service that archives the
+ contents of the Linux persistent storage filesystem, pstore, to other storage,
+ thus preserving the existing information contained in the pstore, and clearing
+ pstore storage for future error events.</para>
+
+ <para>Linux provides a persistent storage file system, pstore, that can store
+ error records when the kernel dies (or reboots or powers-off). These records in
+ turn can be referenced to debug kernel problems (currently the kernel stuffs
+ the tail of the dmesg, which also contains a stack backtrace, into pstore).</para>
+
+ <para>The pstore file system supports a variety of backends that map onto persistent
+ storage, such as the ACPI ERST and UEFI variables. The pstore backends
+ typically offer a relatively small amount of persistent storage, e.g. 64KiB,
+ which can quickly fill up and thus prevent subsequent kernel crashes from
+ recording errors. Thus there is a need to monitor and extract the pstore
+ contents so that future kernel problems can also record information in the
+ pstore.</para>
+
+ <para>The pstore service is independent of the kdump service. In cloud environments
+ specifically, host and guest filesystems are on remote filesystems (eg. iSCSI
+ or NFS), thus kdump relies [implicitly and/or explicitly] upon proper operation
+ of networking software *and* hardware *and* infrastructure. Thus it may not be
+ possible to capture a kernel coredump to a file since writes over the network
+ may not be possible.</para>
+
+ <para>The pstore backend, on the other hand, is completely local and provides a path
+ to store error records which will survive a reboot and aid in post-mortem
+ debugging.</para>
+
+ <para>The <command>systemd-pstore</command> executable does the actual work. Upon starting,
+ the <filename>pstore.conf</filename> is read to obtain options, then the /sys/fs/pstore
+ directory contents are processed according to the options. Pstore files are written to the
+ journal, and optionally saved into /var/lib/systemd/pstore.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration</title>
+
+ <para>The behavior of <command>systemd-pstore</command> is configured through the configuration file
+ <filename>/etc/systemd/pstore.conf</filename> and corresponding snippets
+ <filename>/etc/systemd/pstore.conf.d/*.conf</filename>, see
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+
+ <refsect2>
+ <title>Disabling pstore processing</title>
+
+ <para>To disable pstore processing by <command>systemd-pstore</command>,
+ set <programlisting>Storage=none</programlisting> in
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>Usage</title>
+ <para>Data stored in the journal can be viewed with
+ <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ as usual.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/meson.build b/meson.build
index af4cf331da..972a8fb6f7 100644
--- a/meson.build
+++ b/meson.build
@@ -1224,6 +1224,7 @@ foreach term : ['utmp',
'environment-d',
'binfmt',
'coredump',
+ 'pstore',
'resolve',
'logind',
'hostnamed',
@@ -1439,6 +1440,7 @@ subdir('src/network')
subdir('src/analyze')
subdir('src/journal-remote')
subdir('src/coredump')
+subdir('src/pstore')
subdir('src/hostname')
subdir('src/import')
subdir('src/kernel-install')
@@ -2151,6 +2153,23 @@ if conf.get('ENABLE_COREDUMP') == 1
public_programs += [exe]
endif
+if conf.get('ENABLE_PSTORE') == 1
+ executable('systemd-pstore',
+ systemd_pstore_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libacl,
+ libdw,
+ libxz,
+ liblz4],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += exe
+endif
+
if conf.get('ENABLE_BINFMT') == 1
exe = executable('systemd-binfmt',
'src/binfmt/binfmt.c',
@@ -3014,6 +3033,7 @@ foreach tuple : [
['resolve'],
['DNS-over-TLS'],
['coredump'],
+ ['pstore'],
['polkit'],
['legacy pkla', install_polkit_pkla],
['efi'],
diff --git a/meson_options.txt b/meson_options.txt
index 213079ac15..5624304bf4 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -76,6 +76,8 @@ option('binfmt', type : 'boolean',
description : 'support for custom binary formats')
option('coredump', type : 'boolean',
description : 'install the coredump handler')
+option('pstore', type : 'boolean',
+ description : 'install the pstore archival tool')
option('logind', type : 'boolean',
description : 'install the systemd-logind stack')
option('hostnamed', type : 'boolean',
diff --git a/src/pstore/meson.build b/src/pstore/meson.build
new file mode 100644
index 0000000000..adbac24b54
--- /dev/null
+++ b/src/pstore/meson.build
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
+systemd_pstore_sources = files('''
+ pstore.c
+'''.split())
+
+if conf.get('ENABLE_PSTORE') == 1
+ install_data('pstore.conf',
+ install_dir : pkgsysconfdir)
+endif
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
new file mode 100644
index 0000000000..f95e016eb6
--- /dev/null
+++ b/src/pstore/pstore.c
@@ -0,0 +1,395 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+/* Copyright © 2019 Oracle and/or its affiliates. */
+
+/* Generally speaking, the pstore contains a small number of files
+ * that in turn contain a small amount of data. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <sys/prctl.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "sd-daemon.h"
+#include "sd-journal.h"
+#include "sd-login.h"
+#include "sd-messages.h"
+
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "capability-util.h"
+#include "cgroup-util.h"
+#include "compress.h"
+#include "conf-parser.h"
+#include "copy.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "journal-importer.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+
+/* Command line argument handling */
+typedef enum PStoreStorage {
+ PSTORE_STORAGE_NONE,
+ PSTORE_STORAGE_EXTERNAL,
+ PSTORE_STORAGE_JOURNAL,
+ _PSTORE_STORAGE_MAX,
+ _PSTORE_STORAGE_INVALID = -1
+} PStoreStorage;
+
+static const char* const pstore_storage_table[_PSTORE_STORAGE_MAX] = {
+ [PSTORE_STORAGE_NONE] = "none",
+ [PSTORE_STORAGE_EXTERNAL] = "external",
+ [PSTORE_STORAGE_JOURNAL] = "journal",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(pstore_storage, PStoreStorage);
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_pstore_storage, pstore_storage, PStoreStorage, "Failed to parse storage setting");
+
+static PStoreStorage arg_storage = PSTORE_STORAGE_EXTERNAL;
+
+static bool arg_unlink = true;
+static const char *arg_sourcedir = "/sys/fs/pstore";
+static const char *arg_archivedir = "/var/lib/systemd/pstore";
+
+static int parse_config(void) {
+ static const ConfigTableItem items[] = {
+ { "PStore", "Unlink", config_parse_bool, 0, &arg_unlink },
+ { "PStore", "Storage", config_parse_pstore_storage, 0, &arg_storage },
+ {}
+ };
+
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf",
+ CONF_PATHS_NULSTR("systemd/pstore.conf.d"),
+ "PStore\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN, NULL);
+}
+
+/* File list handling - PStoreEntry is the struct and
+ * and PStoreEntry is the type that contains all info
+ * about a pstore entry. */
+typedef struct PStoreEntry {
+ struct dirent dirent;
+ bool is_binary;
+ bool handled;
+ char *content;
+ size_t content_size;
+} PStoreEntry;
+
+typedef struct PStoreList {
+ PStoreEntry *entries;
+ size_t n_entries;
+ size_t n_entries_allocated;
+} PStoreList;
+
+static void pstore_entries_reset(PStoreList *list) {
+ for (size_t i = 0; i < list->n_entries; i++)
+ free(list->entries[i].content);
+ free(list->entries);
+ list->n_entries = 0;
+}
+
+static int compare_pstore_entries(const void *_a, const void *_b) {
+ PStoreEntry *a = (PStoreEntry *)_a, *b = (PStoreEntry *)_b;
+ return strcmp(a->dirent.d_name, b->dirent.d_name);
+}
+
+static int move_file(PStoreEntry *pe, const char *subdir) {
+ _cleanup_free_ char *ifd_path = NULL;
+ _cleanup_free_ char *ofd_path = NULL;
+ int r = 0;
+ struct iovec iovec[2] = {};
+ int n_iovec = 0;
+ _cleanup_free_ void *field = NULL;
+ const char *suffix = NULL;
+ size_t field_size;
+
+ if (pe->handled)
+ return 0;
+
+ ifd_path = path_join(NULL, arg_sourcedir, pe->dirent.d_name);
+ if (!ifd_path)
+ return log_oom();
+
+ ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name);
+ if (!ofd_path)
+ return log_oom();
+
+ /* Always log to the journal */
+ suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)".";
+ field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(field);
+
+ field_size = strlen("FILE=") + pe->content_size;
+ field = malloc(field_size);
+ if (!field)
+ return log_oom();
+ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
+ iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+
+ r = sd_journal_sendv(iovec, n_iovec);
+ if (r < 0)
+ return log_error_errno(r, "Failed to log pstore entry: %m");
+
+ if (arg_storage == PSTORE_STORAGE_EXTERNAL) {
+ /* Move file from pstore to external storage */
+ r = mkdir_parents(ofd_path, 0755);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directoy %s: %m", ofd_path);
+ r = copy_file_atomic(ifd_path, ofd_path, 0600, 0, COPY_REPLACE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy_file_atomic: %s to %s", ifd_path, ofd_path);
+ }
+
+ /* If file copied properly, remove it from pstore */
+ if (arg_unlink)
+ (void) unlink(ifd_path);
+
+ pe->handled = true;
+
+ return 0;
+}
+
+static int write_dmesg(const char *dmesg, size_t size, const char *id) {
+ _cleanup_(unlink_and_freep) char *ofd_path = NULL;
+ _cleanup_free_ char *tmp_path = NULL;
+ _cleanup_close_ int ofd = -1;
+ ssize_t wr;
+ int r;
+
+ if (isempty(dmesg) || size == 0)
+ return 0;
+
+ /* log_info("Record ID %s", id); */
+
+ ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
+ if (!ofd_path)
+ return log_oom();
+
+ ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path);
+ if (ofd < 0)
+ return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path);
+ wr = write(ofd, dmesg, size);
+ if (wr < 0)
+ return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path);
+ if (wr != (ssize_t)size)
+ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr);
+ r = link_tmpfile(ofd, tmp_path, ofd_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
+ ofd_path = mfree(ofd_path);
+
+ return 0;
+}
+
+static void process_dmesg_files(PStoreList *list) {
+ /* Move files, reconstruct dmesg.txt */
+ PStoreEntry *pe;
+ _cleanup_free_ char *dmesg = NULL;
+ size_t dmesg_size = 0;
+ _cleanup_free_ char *dmesg_id = NULL;
+
+ /* Handle each dmesg file: files processed in reverse
+ * order so as to properly reconstruct original dmesg */
+ for (size_t n = list->n_entries; n > 0; n--) {
+ bool move_file_and_continue = false;
+ _cleanup_free_ char *pe_id = NULL;
+ char *p;
+ size_t plen;
+
+ pe = &list->entries[n-1];
+
+ if (pe->handled)
+ continue;
+ if (!startswith(pe->dirent.d_name, "dmesg-"))
+ continue;
+
+ if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */
+ move_file_and_continue = true;
+ p = strrchr(pe->dirent.d_name, '-');
+ if (!p)
+ move_file_and_continue = true;
+
+ if (move_file_and_continue) {
+ /* A dmesg file on which we do NO additional processing */
+ (void) move_file(pe, NULL);
+ continue;
+ }
+
+ /* See if this file is one of a related group of files
+ * in order to reconstruct dmesg */
+
+ /* When dmesg is written into pstore, it is done so in
+ * small chunks, whatever the exchange buffer size is
+ * with the underlying pstore backend (ie. EFI may be
+ * ~2KiB), which means an example pstore with approximately
+ * 64KB of storage may have up to roughly 32 dmesg files
+ * that could be related, depending upon the size of the
+ * original dmesg.
+ *
+ * Here we look at the dmesg filename and try to discern
+ * if files are part of a related group, meaning the same
+ * original dmesg.
+ *
+ * The two known pstore backends are EFI and ERST. These
+ * backends store data in the Common Platform Error
+ * Record, CPER, format. The dmesg- filename contains the
+ * CPER record id, a 64bit number (in decimal notation).
+ * In Linux, the record id is encoded with two digits for
+ * the dmesg part (chunk) number and 3 digits for the
+ * count number. So allowing an additional digit to
+ * compensate for advancing time, this code ignores the
+ * last six digits of the filename in determining the
+ * record id.
+ *
+ * For the EFI backend, the record id encodes an id in the
+ * upper 32 bits, and a timestamp in the lower 32-bits.
+ * So ignoring the least significant 6 digits has proven
+ * to generally identify related dmesg entries. */
+#define PSTORE_FILENAME_IGNORE 6
+
+ /* determine common portion of record id */
+ ++p; /* move beyond dmesg- */
+ plen = strlen(p);
+ if (plen > PSTORE_FILENAME_IGNORE) {
+ pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE);
+ if (!pe_id) {
+ log_oom();
+ return;
+ }
+ } else
+ pe_id = mfree(pe_id);
+
+ /* Now move file from pstore to archive storage */
+ move_file(pe, pe_id);
+
+ /* If the current record id is NOT the same as the
+ * previous record id, then start a new dmesg.txt file */
+ if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) {
+ /* Encountered a new dmesg group, close out old one, open new one */
+ if (dmesg) {
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ dmesg = mfree(dmesg);
+ dmesg_size = 0;
+ }
+
+ /* now point dmesg_id to storage of pe_id */
+ free_and_replace(dmesg_id, pe_id);
+ }
+
+ /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */
+ dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1);
+ if (dmesg) {
+ dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name);
+ if (pe->content) {
+ memcpy(&dmesg[dmesg_size], pe->content, pe->content_size);
+ dmesg_size += pe->content_size;
+ }
+ }
+
+ pe_id = mfree(pe_id);
+ }
+ if (dmesg)
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+}
+
+static int list_files(PStoreList *list, const char *sourcepath) {
+ _cleanup_(closedirp) DIR *dirp = NULL;
+ struct dirent *de;
+ int r = 0;
+
+ dirp = opendir(sourcepath);
+ if (!dirp)
+ return log_error_errno(errno, "Failed to opendir %s: %m", sourcepath);
+
+ FOREACH_DIRENT(de, dirp, return log_error_errno(errno, "Failed to iterate through %s: %m", sourcepath)) {
+ _cleanup_free_ char *ifd_path = NULL;
+
+ ifd_path = path_join(NULL, sourcepath, de->d_name);
+ if (!ifd_path)
+ return log_oom();
+
+ _cleanup_free_ char *buf = NULL;
+ size_t buf_size;
+
+ /* Now read contents of pstore file */
+ r = read_full_file(ifd_path, &buf, &buf_size);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read file %s: %m", ifd_path);
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(list->entries, list->n_entries_allocated, list->n_entries + 1))
+ return log_oom();
+
+ list->entries[list->n_entries++] = (PStoreEntry) {
+ .dirent = *de,
+ .content = TAKE_PTR(buf),
+ .content_size = buf_size,
+ .is_binary = true,
+ .handled = false,
+ };
+ }
+
+ return r;
+}
+
+static int run(int argc, char *argv[]) {
+ _cleanup_(pstore_entries_reset) PStoreList list = {};
+ int r;
+
+ log_open();
+
+ /* Ignore all parse errors */
+ (void) parse_config();
+
+ log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage));
+ log_debug("Selected Unlink '%d'.", arg_unlink);
+
+ if (arg_storage == PSTORE_STORAGE_NONE)
+ /* Do nothing, intentionally, leaving pstore untouched */
+ return 0;
+
+ /* Obtain list of files in pstore */
+ r = list_files(&list, arg_sourcedir);
+ if (r < 0)
+ return r;
+
+ /* Handle each pstore file */
+ /* Sort files lexigraphically ascending, generally needed by all */
+ qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries);
+
+ /* Process known file types */
+ process_dmesg_files(&list);
+
+ /* Move left over files out of pstore */
+ for (size_t n = 0; n < list.n_entries; n++)
+ move_file(&list.entries[n], NULL);
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ r = run(argc, argv);
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/pstore/pstore.conf b/src/pstore/pstore.conf
new file mode 100644
index 0000000000..93a8b6707c
--- /dev/null
+++ b/src/pstore/pstore.conf
@@ -0,0 +1,16 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See pstore.conf(5) for details.
+
+[PStore]
+#Storage=external
+#Unlink=yes
diff --git a/units/meson.build b/units/meson.build
index a74fa95195..e8e64eb30a 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -136,6 +136,7 @@ in_units = [
['systemd-binfmt.service', 'ENABLE_BINFMT',
'sysinit.target.wants/'],
['systemd-coredump@.service', 'ENABLE_COREDUMP'],
+ ['systemd-pstore.service', 'ENABLE_PSTORE'],
['systemd-firstboot.service', 'ENABLE_FIRSTBOOT',
'sysinit.target.wants/'],
['systemd-fsck-root.service', ''],
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
new file mode 100644
index 0000000000..fec2b1aebf
--- /dev/null
+++ b/units/systemd-pstore.service.in
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Platform Persistent Storage Archival
+Documentation=man:systemd-pstore(8)
+DefaultDependencies=no
+Wants=systemd-remount-fs.service
+After=systemd-remount-fs.service
+
+[Service]
+Type=oneshot
+ExecStart=@rootlibexecdir@/systemd-pstore
+RemainAfterExit=yes
+StateDirectory=systemd/pstore
+
+[Install]
+WantedBy=systemd-remount-fs.service

View File

@ -0,0 +1,27 @@
From c95ba53ab720dfbd7f692e0a87d7f5d4f89ea36b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:46:53 +0900
Subject: [PATCH] meson: drop redundant line
Found by @mattiasb.
(cherry picked from commit 3f708e7f6909faad307bdb60ed0f8d68e84f6584)
Related: #2158832
---
meson.build | 2 --
1 file changed, 2 deletions(-)
diff --git a/meson.build b/meson.build
index 972a8fb6f7..673800a1a7 100644
--- a/meson.build
+++ b/meson.build
@@ -2166,8 +2166,6 @@ if conf.get('ENABLE_PSTORE') == 1
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
-
- public_programs += exe
endif
if conf.get('ENABLE_BINFMT') == 1

View File

@ -0,0 +1,48 @@
From 7e4b7cc35af0e3b3afbf32fa0fd9961cd01ad9a9 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:52:12 +0900
Subject: [PATCH] pstore: drop unnecessary initializations
(cherry picked from commit 2e4effd129343d22bfed34e94810d3f87c8f0e85)
Related: #2158832
---
src/pstore/pstore.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index f95e016eb6..e6a342fc50 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -113,14 +113,12 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
}
static int move_file(PStoreEntry *pe, const char *subdir) {
- _cleanup_free_ char *ifd_path = NULL;
- _cleanup_free_ char *ofd_path = NULL;
- int r = 0;
- struct iovec iovec[2] = {};
- int n_iovec = 0;
+ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
_cleanup_free_ void *field = NULL;
- const char *suffix = NULL;
+ struct iovec iovec[2];
+ const char *suffix;
size_t field_size;
+ int n_iovec = 0, r;
if (pe->handled)
return 0;
@@ -202,10 +200,9 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
static void process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
- PStoreEntry *pe;
- _cleanup_free_ char *dmesg = NULL;
+ _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
size_t dmesg_size = 0;
- _cleanup_free_ char *dmesg_id = NULL;
+ PStoreEntry *pe;
/* Handle each dmesg file: files processed in reverse
* order so as to properly reconstruct original dmesg */

View File

@ -0,0 +1,46 @@
From a0485b96118d3d2ac439f510e404ffb3db03e23f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 10:55:10 +0900
Subject: [PATCH] pstopre: fix return value of list_files()
Previously, the return value of the last read_full_file() is returned.
This makes the error in read_full_file() is always ignored.
(cherry picked from commit 337874a45fff46a80e4974c681a5e651f3a0fac9)
Related: #2158832
---
src/pstore/pstore.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index e6a342fc50..2fbef48543 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -311,7 +311,7 @@ static void process_dmesg_files(PStoreList *list) {
static int list_files(PStoreList *list, const char *sourcepath) {
_cleanup_(closedirp) DIR *dirp = NULL;
struct dirent *de;
- int r = 0;
+ int r;
dirp = opendir(sourcepath);
if (!dirp)
@@ -330,7 +330,7 @@ static int list_files(PStoreList *list, const char *sourcepath) {
/* Now read contents of pstore file */
r = read_full_file(ifd_path, &buf, &buf_size);
if (r < 0) {
- log_warning_errno(r, "Failed to read file %s: %m", ifd_path);
+ log_warning_errno(r, "Failed to read file %s, skipping: %m", ifd_path);
continue;
}
@@ -346,7 +346,7 @@ static int list_files(PStoreList *list, const char *sourcepath) {
};
}
- return r;
+ return 0;
}
static int run(int argc, char *argv[]) {

View File

@ -0,0 +1,36 @@
From 58000dc7dd93ff6e8357de64154b0849d3c17c5d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 11:01:43 +0900
Subject: [PATCH] pstore: remove temporary file on failure
(cherry picked from commit 03c5f6cc02648eeff3179b2b762d46b9e1889bb1)
Related: #2158832
---
src/pstore/pstore.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 2fbef48543..ce8080ceed 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -167,8 +167,8 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
}
static int write_dmesg(const char *dmesg, size_t size, const char *id) {
- _cleanup_(unlink_and_freep) char *ofd_path = NULL;
- _cleanup_free_ char *tmp_path = NULL;
+ _cleanup_(unlink_and_freep) char *tmp_path = NULL;
+ _cleanup_free_ char *ofd_path = NULL;
_cleanup_close_ int ofd = -1;
ssize_t wr;
int r;
@@ -193,7 +193,7 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
r = link_tmpfile(ofd, tmp_path, ofd_path);
if (r < 0)
return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
- ofd_path = mfree(ofd_path);
+ tmp_path = mfree(tmp_path);
return 0;
}

View File

@ -0,0 +1,57 @@
From 5006e4bd9aecea40ca3d907adc692c4c8001a6c1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 11:08:06 +0900
Subject: [PATCH] pstore: do not add FILE= journal entry if content_size == 0
(cherry picked from commit 6bf18debddbe1b231f783617e054cc194bb36d1e)
Related: #2158832
---
src/pstore/pstore.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index ce8080ceed..eb251d61c8 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -114,10 +114,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
static int move_file(PStoreEntry *pe, const char *subdir) {
_cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
- _cleanup_free_ void *field = NULL;
+ const char *suffix, *message;
struct iovec iovec[2];
- const char *suffix;
- size_t field_size;
int n_iovec = 0, r;
if (pe->handled)
@@ -133,15 +131,20 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
/* Always log to the journal */
suffix = arg_storage == PSTORE_STORAGE_EXTERNAL ? strjoina(" moved to ", ofd_path) : (char *)".";
- field = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
- iovec[n_iovec++] = IOVEC_MAKE_STRING(field);
+ message = strjoina("MESSAGE=PStore ", pe->dirent.d_name, suffix);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
- field_size = strlen("FILE=") + pe->content_size;
- field = malloc(field_size);
- if (!field)
- return log_oom();
- memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
- iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+ if (pe->content_size > 0) {
+ _cleanup_free_ void *field = NULL;
+ size_t field_size;
+
+ field_size = strlen("FILE=") + pe->content_size;
+ field = malloc(field_size);
+ if (!field)
+ return log_oom();
+ memcpy(stpcpy(field, "FILE="), pe->content, pe->content_size);
+ iovec[n_iovec++] = IOVEC_MAKE(field, field_size);
+ }
r = sd_journal_sendv(iovec, n_iovec);
if (r < 0)

View File

@ -0,0 +1,24 @@
From a7247899f156761934bcb4b380861b3d3ec5449f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Jul 2019 14:09:12 +0900
Subject: [PATCH] pstore: run only when /sys/fs/pstore is not empty
(cherry picked from commit 6d4f213b1f6afb2901f0d97cec0e28e20809b713)
Related: #2158832
---
units/systemd-pstore.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index fec2b1aebf..dde21bc33e 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -10,6 +10,7 @@
[Unit]
Description=Platform Persistent Storage Archival
Documentation=man:systemd-pstore(8)
+ConditionDirectoryNotEmpty=/sys/fs/pstore
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service

View File

@ -0,0 +1,34 @@
From 7f5bfbd5485e1cb779d7568cabb5783651fd9da3 Mon Sep 17 00:00:00 2001
From: Michael Olbrich <m.olbrich@pengutronix.de>
Date: Fri, 6 Sep 2019 15:04:01 +0200
Subject: [PATCH] pstore: fix use after free
The memory is still needed in the sd_journal_sendv() after the 'if' block.
(cherry picked from commit 1e19f5ac0d680a63eccae7ef1fc6ce225dca0bbf)
Related: #2158832
---
src/pstore/pstore.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index eb251d61c8..cafb1804c6 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -114,6 +114,7 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
static int move_file(PStoreEntry *pe, const char *subdir) {
_cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
+ _cleanup_free_ void *field = NULL;
const char *suffix, *message;
struct iovec iovec[2];
int n_iovec = 0, r;
@@ -135,7 +136,6 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
if (pe->content_size > 0) {
- _cleanup_free_ void *field = NULL;
size_t field_size;
field_size = strlen("FILE=") + pe->content_size;

View File

@ -0,0 +1,29 @@
From a35a90322f8587f650aeb72bfbe1ebcc93e503aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 22 Jul 2019 10:43:19 +0200
Subject: [PATCH] pstore: refuse to run if arguments are specified
(This is why the --help chech passed.)
(cherry picked from commit 22d6bea8820612e6a1483d8b6cfd820f1417ae6b)
Related: #2158832
---
src/pstore/pstore.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index cafb1804c6..b0b21dedd4 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -358,6 +358,10 @@ static int run(int argc, char *argv[]) {
log_open();
+ if (argc > 1)
+ return log_error_errno(-EINVAL,
+ "This program takes no arguments.");
+
/* Ignore all parse errors */
(void) parse_config();

View File

@ -0,0 +1,44 @@
From 76fe0974f62f0a2beb2d3d8e224e80a57c0ebd09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 4 Oct 2019 16:14:47 +0200
Subject: [PATCH] pstore: allow specifying src and dst dirs are arguments
This makes it much easier to debug the program as a normal user, since we
don't need to set up fake input under /sys/fs/pstore/.
Also, let's make the debug output a bit nicer.
(cherry picked from commit e05a72d7587ff916a983588f8393af624d330dd0)
Related: #2158832
---
src/pstore/pstore.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index b0b21dedd4..7353e83a81 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -358,15 +358,18 @@ static int run(int argc, char *argv[]) {
log_open();
- if (argc > 1)
+ if (argc == 3) {
+ arg_sourcedir = argv[1];
+ arg_archivedir = argv[2];
+ } else if (argc > 1)
return log_error_errno(-EINVAL,
- "This program takes no arguments.");
+ "This program takes zero or two arguments.");
/* Ignore all parse errors */
(void) parse_config();
- log_debug("Selected storage '%s'.", pstore_storage_to_string(arg_storage));
- log_debug("Selected Unlink '%d'.", arg_unlink);
+ log_debug("Selected storage: %s.", pstore_storage_to_string(arg_storage));
+ log_debug("Selected unlink: %s.", yes_no(arg_unlink));
if (arg_storage == PSTORE_STORAGE_NONE)
/* Do nothing, intentionally, leaving pstore untouched */

View File

@ -0,0 +1,133 @@
From a2ba34a79de3748f51d57541c54dbe22e1d03a9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 4 Oct 2019 16:17:27 +0200
Subject: [PATCH] pstore: rework memory handling for dmesg
Semmle Security Reports report:
> The problem occurs on the way realloc is being used. When a size
> bigger than the chunk that wants to be reallocated is passed, realloc
> try to malloc a bigger size, however in the case that malloc fails
> (for example, by forcing a big allocation) realloc will return NULL.
>
> According to the man page:
> "The realloc() function returns a pointer to the newly allocated
> memory, which is suitably aligned for any built-in type and may be
> different from ptr, or NULL if the request fails. If size was
> equal to 0, either NULL or a pointer suitable to be passed to free()
> is returned. If realloc() fails, the original block is left
> untouched; it is not freed or moved."
>
> The problem occurs when the memory ptr passed to the first argument of
> realloc is the same as the one used for the result, for example in
> this case:
>
> dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) +
> strlen(":\n") + pe->content_size + 1);
>
> https://lgtm.com/projects/g/systemd/systemd/snapshot/f8bcb81955f9e93a4787627e28f43fffb2a84836/files/src/pstore/pstore.c?sort=name&dir=A
> SC&mode=heatmap#L300
>
> If the malloc inside that realloc fails, then the original memory
> chunk will never be free but since realloc will return NULL, the
> pointer to that memory chunk will be lost and a memory leak will
> occur.
>
> In case you are curious, this is the query we used to find this problem:
> https://lgtm.com/query/8650323308193591473/
Let's use a more standard pattern: allocate memory using greedy_realloc, and
instead of freeing it when we wrote out a chunk, let's just move the cursor
back to the beginning and reuse the memory we allocated previously.
If we fail to allocate the memory for dmesg contents, don't write the dmesg
entry, but let's still process the files to move them out of pstore.
(cherry picked from commit 8198c3e42b0614b6bd1db6f38813b842c8577304)
Related: #2158832
---
src/pstore/pstore.c | 43 ++++++++++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index 7353e83a81..d70e142b4d 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -176,9 +176,11 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
ssize_t wr;
int r;
- if (isempty(dmesg) || size == 0)
+ if (size == 0)
return 0;
+ assert(dmesg);
+
/* log_info("Record ID %s", id); */
ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
@@ -204,7 +206,8 @@ static int write_dmesg(const char *dmesg, size_t size, const char *id) {
static void process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
_cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
- size_t dmesg_size = 0;
+ size_t dmesg_size = 0, dmesg_allocated = 0;
+ bool dmesg_bad = false;
PStoreEntry *pe;
/* Handle each dmesg file: files processed in reverse
@@ -281,33 +284,39 @@ static void process_dmesg_files(PStoreList *list) {
/* Now move file from pstore to archive storage */
move_file(pe, pe_id);
+ if (dmesg_bad)
+ continue;
+
/* If the current record id is NOT the same as the
* previous record id, then start a new dmesg.txt file */
- if (!pe_id || !dmesg_id || !streq(pe_id, dmesg_id)) {
+ if (!streq_ptr(pe_id, dmesg_id)) {
/* Encountered a new dmesg group, close out old one, open new one */
- if (dmesg) {
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
- dmesg = mfree(dmesg);
- dmesg_size = 0;
- }
+ (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ dmesg_size = 0;
/* now point dmesg_id to storage of pe_id */
free_and_replace(dmesg_id, pe_id);
}
- /* Reconstruction of dmesg is done as a useful courtesy, do not log errors */
- dmesg = realloc(dmesg, dmesg_size + strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1);
- if (dmesg) {
- dmesg_size += sprintf(&dmesg[dmesg_size], "%s:\n", pe->dirent.d_name);
- if (pe->content) {
- memcpy(&dmesg[dmesg_size], pe->content, pe->content_size);
- dmesg_size += pe->content_size;
- }
+ /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled
+ * output either. */
+ size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1;
+ if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) {
+ log_warning_errno(ENOMEM, "Failed to write dmesg file: %m");
+ dmesg_bad = true;
+ continue;
+ }
+
+ dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name);
+ if (pe->content) {
+ memcpy(dmesg + dmesg_size, pe->content, pe->content_size);
+ dmesg_size += pe->content_size;
}
pe_id = mfree(pe_id);
}
- if (dmesg)
+
+ if (!dmesg_bad)
(void) write_dmesg(dmesg, dmesg_size, dmesg_id);
}

View File

@ -0,0 +1,504 @@
From 5ac15c7dc49476e7cd7cc3a4b507282c9f78d528 Mon Sep 17 00:00:00 2001
From: Eric DeVolder <eric.devolder@oracle.com>
Date: Mon, 21 Nov 2022 11:27:27 -0500
Subject: [PATCH] pstore: fixes for dmesg.txt reconstruction
This patch fixes problems with the re-assembly of the dmesg
from the records stored in pstore.
The current code simply ignores the last 6 characters of the
file name to form a base record id, which then groups any
pstore files with this base id into the reconstructed dmesg.txt.
This approach fails when the following oops generated the
following in pstore:
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001
-rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002
-rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002
-rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001
-rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001
-rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002
-rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001
-rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002
-rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001
-rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002
-rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002
-rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001
-rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002
-rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002
-rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001
-rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001
-rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002
-rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001
-rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002
-rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001
-rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001
-rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002
-rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001
-rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002
-rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003
-rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003
-rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003
-rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003
-rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003
-rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003
-rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003
-rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003
-rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003
-rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003
The "reconstructed" dmesg.txt that resulted from the above contained
the following (ignoring actual contents, just providing the Part info):
Emergency#3 Part17
Emergency#3 Part16
Emergency#3 Part15
Emergency#3 Part14
Emergency#3 Part13
Emergency#3 Part12
Emergency#3 Part11
Emergency#3 Part10
Emergency#3 Part9
Emergency#3 Part8
Emergency#3 Part7
Emergency#3 Part6
Emergency#3 Part5
Emergency#3 Part4
Emergency#3 Part3
Emergency#3 Part2
Emergency#3 Part1
Panic#2 Part17
Panic#2 Part16
Oops#1 Part16
Panic#2 Part15
Oops#1 Part15
Panic#2 Part14
Oops#1 Part14
Panic#2 Part13
Oops#1 Part13
Panic#2 Part12
Oops#1 Part12
Panic#2 Part11
Oops#1 Part11
Panic#2 Part10
Oops#1 Part10
Panic#2 Part9
Oops#1 Part9
Panic#2 Part8
Oops#1 Part8
Panic#2 Part7
Oops#1 Part7
Panic#2 Part6
Oops#1 Part6
Panic#2 Part5
Oops#1 Part5
Panic#2 Part4
Oops#1 Part4
Panic#2 Part3
Oops#1 Part3
Panic#2 Part2
Oops#1 Part2
Panic#2 Part1
Oops#1 Part1
The above is a interleaved mess of three dmesg dumps.
This patch fixes the above problems, and simplifies the dmesg
reconstruction process. The code now distinguishes between
records on EFI vs ERST, which have differently formatted
record identifiers. Using knowledge of the format of the
record ids allows vastly improved reconstruction process.
With this change in place, the above pstore records now
result in the following:
# ls -alR /var/lib/systemd/pstore
1666922861:
total 8
drwxr-xr-x. 4 root root 28 Nov 18 14:58 .
drwxr-xr-x. 7 root root 144 Nov 18 14:58 ..
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 001
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 002
1666922861/001:
total 100
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 4 root root 28 Nov 18 14:58 ..
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286101001
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286102001
-rw-------. 1 root root 1807 Oct 27 22:07 dmesg-efi-166692286103001
-rw-------. 1 root root 1773 Oct 27 22:07 dmesg-efi-166692286104001
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286105001
-rw-------. 1 root root 1804 Oct 27 22:07 dmesg-efi-166692286106001
-rw-------. 1 root root 1792 Oct 27 22:07 dmesg-efi-166692286107001
-rw-------. 1 root root 1717 Oct 27 22:07 dmesg-efi-166692286108001
-rw-------. 1 root root 1764 Oct 27 22:07 dmesg-efi-166692286109001
-rw-------. 1 root root 1796 Oct 27 22:07 dmesg-efi-166692286110001
-rw-------. 1 root root 1793 Oct 27 22:07 dmesg-efi-166692286111001
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286112001
-rw-------. 1 root root 1754 Oct 27 22:07 dmesg-efi-166692286113001
-rw-------. 1 root root 1803 Oct 27 22:07 dmesg-efi-166692286114001
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286115001
-rw-------. 1 root root 1815 Oct 27 22:07 dmesg-efi-166692286116001
-rw-r-----. 1 root root 28677 Nov 18 14:58 dmesg.txt
1666922861/002:
total 104
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 4 root root 28 Nov 18 14:58 ..
-rw-------. 1 root root 1341 Oct 27 22:07 dmesg-efi-166692286101002
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286102002
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286103002
-rw-------. 1 root root 1801 Oct 27 22:07 dmesg-efi-166692286104002
-rw-------. 1 root root 1809 Oct 27 22:07 dmesg-efi-166692286105002
-rw-------. 1 root root 1817 Oct 27 22:07 dmesg-efi-166692286106002
-rw-------. 1 root root 1810 Oct 27 22:07 dmesg-efi-166692286107002
-rw-------. 1 root root 1808 Oct 27 22:07 dmesg-efi-166692286108002
-rw-------. 1 root root 1765 Oct 27 22:07 dmesg-efi-166692286109002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286110002
-rw-------. 1 root root 1751 Oct 27 22:07 dmesg-efi-166692286111002
-rw-------. 1 root root 1786 Oct 27 22:07 dmesg-efi-166692286112002
-rw-------. 1 root root 1752 Oct 27 22:07 dmesg-efi-166692286113002
-rw-------. 1 root root 1759 Oct 27 22:07 dmesg-efi-166692286114002
-rw-------. 1 root root 1787 Oct 27 22:07 dmesg-efi-166692286115002
-rw-------. 1 root root 1771 Oct 27 22:07 dmesg-efi-166692286116002
-rw-------. 1 root root 1816 Oct 27 22:07 dmesg-efi-166692286117002
-rw-r-----. 1 root root 30000 Nov 18 14:58 dmesg.txt
1666922867:
total 4
drwxr-xr-x. 3 root root 17 Nov 18 14:58 .
drwxr-xr-x. 7 root root 144 Nov 18 14:58 ..
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 003
1666922867/003:
total 104
drwxr-xr-x. 2 root root 4096 Nov 18 14:58 .
drwxr-xr-x. 3 root root 17 Nov 18 14:58 ..
-rw-------. 1 root root 1388 Oct 27 22:07 dmesg-efi-166692286701003
-rw-------. 1 root root 1824 Oct 27 22:07 dmesg-efi-166692286702003
-rw-------. 1 root root 1795 Oct 27 22:07 dmesg-efi-166692286703003
-rw-------. 1 root root 1805 Oct 27 22:07 dmesg-efi-166692286704003
-rw-------. 1 root root 1813 Oct 27 22:07 dmesg-efi-166692286705003
-rw-------. 1 root root 1821 Oct 27 22:07 dmesg-efi-166692286706003
-rw-------. 1 root root 1814 Oct 27 22:07 dmesg-efi-166692286707003
-rw-------. 1 root root 1812 Oct 27 22:07 dmesg-efi-166692286708003
-rw-------. 1 root root 1769 Oct 27 22:07 dmesg-efi-166692286709003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286710003
-rw-------. 1 root root 1755 Oct 27 22:07 dmesg-efi-166692286711003
-rw-------. 1 root root 1790 Oct 27 22:07 dmesg-efi-166692286712003
-rw-------. 1 root root 1756 Oct 27 22:07 dmesg-efi-166692286713003
-rw-------. 1 root root 1763 Oct 27 22:07 dmesg-efi-166692286714003
-rw-------. 1 root root 1791 Oct 27 22:07 dmesg-efi-166692286715003
-rw-------. 1 root root 1775 Oct 27 22:07 dmesg-efi-166692286716003
-rw-------. 1 root root 1820 Oct 27 22:07 dmesg-efi-166692286717003
-rw-r-----. 1 root root 30111 Nov 18 14:58 dmesg.txt
Furthemore, pstore records on ERST are now able to accurately
identify the change in timestamp sequence in order to start a
new dmesg.txt, as needed.
(cherry picked from commit 5fbaa757077bde2db8d33b1c358518c41b990339)
Related: #2158832
---
src/pstore/pstore.c | 216 +++++++++++++++++++-------------------------
1 file changed, 92 insertions(+), 124 deletions(-)
diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c
index d70e142b4d..9f61e8f7f8 100644
--- a/src/pstore/pstore.c
+++ b/src/pstore/pstore.c
@@ -112,8 +112,8 @@ static int compare_pstore_entries(const void *_a, const void *_b) {
return strcmp(a->dirent.d_name, b->dirent.d_name);
}
-static int move_file(PStoreEntry *pe, const char *subdir) {
- _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL;
+static int move_file(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
+ _cleanup_free_ char *ifd_path = NULL, *ofd_path = NULL, *ofd_path_base = NULL;
_cleanup_free_ void *field = NULL;
const char *suffix, *message;
struct iovec iovec[2];
@@ -126,7 +126,11 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
if (!ifd_path)
return log_oom();
- ofd_path = path_join(arg_archivedir, subdir, pe->dirent.d_name);
+ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2);
+ if (!ofd_path_base)
+ return log_oom();
+
+ ofd_path = path_join(NULL, ofd_path_base, pe->dirent.d_name);
if (!ofd_path)
return log_oom();
@@ -169,155 +173,119 @@ static int move_file(PStoreEntry *pe, const char *subdir) {
return 0;
}
-static int write_dmesg(const char *dmesg, size_t size, const char *id) {
- _cleanup_(unlink_and_freep) char *tmp_path = NULL;
- _cleanup_free_ char *ofd_path = NULL;
+static int append_dmesg(PStoreEntry *pe, const char *subdir1, const char *subdir2) {
+ /* Append dmesg chunk to end, create if needed */
+ _cleanup_free_ char *ofd_path = NULL, *ofd_path_base = NULL;
_cleanup_close_ int ofd = -1;
ssize_t wr;
- int r;
- if (size == 0)
- return 0;
+ assert(pe);
- assert(dmesg);
+ if (pe->content_size == 0)
+ return 0;
- /* log_info("Record ID %s", id); */
+ ofd_path_base = path_join(arg_archivedir, subdir1, subdir2);
+ if (!ofd_path_base)
+ return log_oom();
- ofd_path = path_join(arg_archivedir, id, "dmesg.txt");
+ ofd_path = path_join(NULL, ofd_path_base, "dmesg.txt");
if (!ofd_path)
return log_oom();
- ofd = open_tmpfile_linkable(ofd_path, O_CLOEXEC|O_CREAT|O_TRUNC|O_WRONLY, &tmp_path);
+ ofd = open(ofd_path, O_CREAT|O_NOFOLLOW|O_NOCTTY|O_CLOEXEC|O_APPEND|O_WRONLY, 0640);
if (ofd < 0)
- return log_error_errno(ofd, "Failed to open temporary file %s: %m", ofd_path);
- wr = write(ofd, dmesg, size);
+ return log_error_errno(ofd, "Failed to open file %s: %m", ofd_path);
+ wr = write(ofd, pe->content, pe->content_size);
if (wr < 0)
return log_error_errno(errno, "Failed to store dmesg to %s: %m", ofd_path);
- if (wr != (ssize_t)size)
- return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, size - wr);
- r = link_tmpfile(ofd, tmp_path, ofd_path);
- if (r < 0)
- return log_error_errno(r, "Failed to write temporary file %s: %m", ofd_path);
- tmp_path = mfree(tmp_path);
+ if ((size_t)wr != pe->content_size)
+ return log_error_errno(-EIO, "Failed to store dmesg to %s. %zu bytes are lost.", ofd_path, pe->content_size - wr);
return 0;
}
-static void process_dmesg_files(PStoreList *list) {
+static int process_dmesg_files(PStoreList *list) {
/* Move files, reconstruct dmesg.txt */
- _cleanup_free_ char *dmesg = NULL, *dmesg_id = NULL;
- size_t dmesg_size = 0, dmesg_allocated = 0;
- bool dmesg_bad = false;
- PStoreEntry *pe;
+ _cleanup_free_ char *erst_subdir = NULL;
+ uint64_t last_record_id = 0;
+
+ /* When dmesg is written into pstore, it is done so in small chunks, whatever the exchange buffer
+ * size is with the underlying pstore backend (ie. EFI may be ~2KiB), which means an example
+ * pstore with approximately 64KB of storage may have up to roughly 32 dmesg files, some likely
+ * related.
+ *
+ * Here we look at the dmesg filename and try to discern if files are part of a related group,
+ * meaning the same original dmesg.
+ *
+ * The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER,
+ * record id, a 64-bit number.
+ *
+ * Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.*/
- /* Handle each dmesg file: files processed in reverse
- * order so as to properly reconstruct original dmesg */
for (size_t n = list->n_entries; n > 0; n--) {
- bool move_file_and_continue = false;
- _cleanup_free_ char *pe_id = NULL;
+ PStoreEntry *pe;
char *p;
- size_t plen;
pe = &list->entries[n-1];
if (pe->handled)
continue;
- if (!startswith(pe->dirent.d_name, "dmesg-"))
- continue;
-
if (endswith(pe->dirent.d_name, ".enc.z")) /* indicates a problem */
- move_file_and_continue = true;
- p = strrchr(pe->dirent.d_name, '-');
- if (!p)
- move_file_and_continue = true;
-
- if (move_file_and_continue) {
- /* A dmesg file on which we do NO additional processing */
- (void) move_file(pe, NULL);
continue;
- }
-
- /* See if this file is one of a related group of files
- * in order to reconstruct dmesg */
-
- /* When dmesg is written into pstore, it is done so in
- * small chunks, whatever the exchange buffer size is
- * with the underlying pstore backend (ie. EFI may be
- * ~2KiB), which means an example pstore with approximately
- * 64KB of storage may have up to roughly 32 dmesg files
- * that could be related, depending upon the size of the
- * original dmesg.
- *
- * Here we look at the dmesg filename and try to discern
- * if files are part of a related group, meaning the same
- * original dmesg.
- *
- * The two known pstore backends are EFI and ERST. These
- * backends store data in the Common Platform Error
- * Record, CPER, format. The dmesg- filename contains the
- * CPER record id, a 64bit number (in decimal notation).
- * In Linux, the record id is encoded with two digits for
- * the dmesg part (chunk) number and 3 digits for the
- * count number. So allowing an additional digit to
- * compensate for advancing time, this code ignores the
- * last six digits of the filename in determining the
- * record id.
- *
- * For the EFI backend, the record id encodes an id in the
- * upper 32 bits, and a timestamp in the lower 32-bits.
- * So ignoring the least significant 6 digits has proven
- * to generally identify related dmesg entries. */
-#define PSTORE_FILENAME_IGNORE 6
-
- /* determine common portion of record id */
- ++p; /* move beyond dmesg- */
- plen = strlen(p);
- if (plen > PSTORE_FILENAME_IGNORE) {
- pe_id = memdup_suffix0(p, plen - PSTORE_FILENAME_IGNORE);
- if (!pe_id) {
- log_oom();
- return;
- }
- } else
- pe_id = mfree(pe_id);
-
- /* Now move file from pstore to archive storage */
- move_file(pe, pe_id);
-
- if (dmesg_bad)
+ if (!startswith(pe->dirent.d_name, "dmesg-"))
continue;
- /* If the current record id is NOT the same as the
- * previous record id, then start a new dmesg.txt file */
- if (!streq_ptr(pe_id, dmesg_id)) {
- /* Encountered a new dmesg group, close out old one, open new one */
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
- dmesg_size = 0;
-
- /* now point dmesg_id to storage of pe_id */
- free_and_replace(dmesg_id, pe_id);
- }
-
- /* Reconstruction of dmesg is done as a useful courtesy: do not fail, but don't write garbled
- * output either. */
- size_t needed = strlen(pe->dirent.d_name) + strlen(":\n") + pe->content_size + 1;
- if (!GREEDY_REALLOC(dmesg, dmesg_allocated, dmesg_size + needed)) {
- log_warning_errno(ENOMEM, "Failed to write dmesg file: %m");
- dmesg_bad = true;
- continue;
- }
-
- dmesg_size += sprintf(dmesg + dmesg_size, "%s:\n", pe->dirent.d_name);
- if (pe->content) {
- memcpy(dmesg + dmesg_size, pe->content, pe->content_size);
- dmesg_size += pe->content_size;
- }
-
- pe_id = mfree(pe_id);
+ if ((p = startswith(pe->dirent.d_name, "dmesg-efi-"))) {
+ /* For the EFI backend, the 3 least significant digits of record id encodes a
+ * "count" number, the next 2 least significant digits for the dmesg part
+ * (chunk) number, and the remaining digits as the timestamp. See
+ * linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write(). */
+ _cleanup_free_ char *subdir1 = NULL, *subdir2 = NULL;
+ size_t plen = strlen(p);
+
+ if (plen < 6)
+ continue;
+
+ /* Extract base record id */
+ subdir1 = strndup(p, plen - 5);
+ if (!subdir1)
+ return log_oom();
+ /* Extract "count" field */
+ subdir2 = strndup(p + plen - 3, 3);
+ if (!subdir2)
+ return log_oom();
+
+ /* Now move file from pstore to archive storage */
+ (void) move_file(pe, subdir1, subdir2);
+
+ /* Append to the dmesg */
+ (void) append_dmesg(pe, subdir1, subdir2);
+ } else if ((p = startswith(pe->dirent.d_name, "dmesg-erst-"))) {
+ /* For the ERST backend, the record is a monotonically increasing number, seeded as
+ * a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer(). */
+ uint64_t record_id;
+
+ if (safe_atou64(p, &record_id) < 0)
+ continue;
+ if (last_record_id - 1 != record_id)
+ /* A discontinuity in the number has been detected, this current record id
+ * will become the directory name for all pieces of the dmesg in this
+ * series. */
+ if (free_and_strdup(&erst_subdir, p) < 0)
+ return log_oom();
+
+ /* Now move file from pstore to archive storage */
+ (void) move_file(pe, erst_subdir, NULL);
+
+ /* Append to the dmesg */
+ (void) append_dmesg(pe, erst_subdir, NULL);
+
+ /* Update, but keep erst_subdir for next file */
+ last_record_id = record_id;
+ } else
+ log_debug("Unknown backend, ignoring \"%s\".", pe->dirent.d_name);
}
-
- if (!dmesg_bad)
- (void) write_dmesg(dmesg, dmesg_size, dmesg_id);
+ return 0;
}
static int list_files(PStoreList *list, const char *sourcepath) {
@@ -394,11 +362,11 @@ static int run(int argc, char *argv[]) {
qsort_safe(list.entries, list.n_entries, sizeof(PStoreEntry), compare_pstore_entries);
/* Process known file types */
- process_dmesg_files(&list);
+ (void) process_dmesg_files(&list);
/* Move left over files out of pstore */
for (size_t n = 0; n < list.n_entries; n++)
- move_file(&list.entries[n], NULL);
+ (void) move_file(&list.entries[n], NULL, NULL);
return 0;
}

View File

@ -0,0 +1,27 @@
From 653a635086cfeaf0af12da3a722b0ebe2029b927 Mon Sep 17 00:00:00 2001
From: Balint Reczey <balint.reczey@canonical.com>
Date: Mon, 16 Dec 2019 19:03:19 +0100
Subject: [PATCH] pstore: Don't start systemd-pstore.service in containers
Usually it is not useful and can also fail making
boot-and-services autopkgtest fail.
(cherry picked from commit 287f506c32f3f4a48ba020408f964cb0f964d752)
Related: #2158832
---
units/systemd-pstore.service.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index dde21bc33e..89f34afe34 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -11,6 +11,7 @@
Description=Platform Persistent Storage Archival
Documentation=man:systemd-pstore(8)
ConditionDirectoryNotEmpty=/sys/fs/pstore
+ConditionVirtualization=!container
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service

View File

@ -0,0 +1,36 @@
From c7e65774a4ccc8a431f63c5a12ab776b24ee1190 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:12:00 +0200
Subject: [PATCH] units: pull in systemd-pstore.service from sysinit.target
sysinit.target is the target our early boot services are generally
pulled in from, make systemd-pstore.service not an exception of that.
Effectively this doesn't mean much, either way our unit is part of the
initial transaction.
(cherry picked from commit 167241912f51fbc0d7d0869b9af34c15b5ecc4b6)
Related: #2158832
---
units/systemd-pstore.service.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 89f34afe34..37fcf878f0 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -15,6 +15,7 @@ ConditionVirtualization=!container
DefaultDependencies=no
Wants=systemd-remount-fs.service
After=systemd-remount-fs.service
+Before=sysinit.target
[Service]
Type=oneshot
@@ -23,4 +24,4 @@ RemainAfterExit=yes
StateDirectory=systemd/pstore
[Install]
-WantedBy=systemd-remount-fs.service
+WantedBy=sysinit.target

View File

@ -0,0 +1,36 @@
From bc6f273a0475a1fa7ab56bc1e498ee62c96aa660 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:10:38 +0200
Subject: [PATCH] units: drop dependency on systemd-remount-fs.service from
systemd-pstore.service
This dependency is now generated automatically given we use
StateDirectory=. Moreover the combination of Wants= and After= was too
strong anway, as whether remount-fs is pulled in or not should not be up
to systemd-pstore.service, and in fact is part of the initial
transaction anyway.
[dtardon: This only removes Wants=, not After=, because I haven't
backported the auto-generation code the description talks about. The
code is simple, but it's just an optimisation allowing for slightly
shorter unit files, hence I don't think we really need it.]
(cherry picked from commit 0c978faa16fa9ecf92f0bbb5c7cc709dc472d115)
Related: #2158832
---
units/systemd-pstore.service.in | 1 -
1 file changed, 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 37fcf878f0..9a86f3145c 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -13,7 +13,6 @@ Documentation=man:systemd-pstore(8)
ConditionDirectoryNotEmpty=/sys/fs/pstore
ConditionVirtualization=!container
DefaultDependencies=no
-Wants=systemd-remount-fs.service
After=systemd-remount-fs.service
Before=sysinit.target

View File

@ -0,0 +1,29 @@
From 818ddd1efd751ef50f9960920284465befe9d704 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 8 Apr 2020 16:25:03 +0200
Subject: [PATCH] units: make sure systemd-pstore stops at shutdown
This doesn't matter too much given that the service doesn't do anything
on shutdown, but let's still stop it to make things cleaner.
(cherry picked from commit b0c1a07654c80d3cbbbcc52f860d4206707c0b08)
Related: #2158832
---
units/systemd-pstore.service.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/units/systemd-pstore.service.in b/units/systemd-pstore.service.in
index 9a86f3145c..8cbf264a99 100644
--- a/units/systemd-pstore.service.in
+++ b/units/systemd-pstore.service.in
@@ -14,7 +14,8 @@ ConditionDirectoryNotEmpty=/sys/fs/pstore
ConditionVirtualization=!container
DefaultDependencies=no
After=systemd-remount-fs.service
-Before=sysinit.target
+Conflicts=shutdown.target
+Before=sysinit.target shutdown.target
[Service]
Type=oneshot

Some files were not shown because too many files have changed in this diff Show More