systemd-252-60
Resolves: RHEL-115182,RHEL-97175,RHEL-107268
This commit is contained in:
parent
35e0d14f41
commit
a673ceed38
27
1274-man-fix-a-missing-word.patch
Normal file
27
1274-man-fix-a-missing-word.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 5844efbf70321f5dd902f987947786d1ab4409c6 Mon Sep 17 00:00:00 2001
|
||||
From: Frantisek Sumsal <frantisek@sumsal.cz>
|
||||
Date: Wed, 8 Oct 2025 17:23:31 +0200
|
||||
Subject: [PATCH] man: fix a missing word
|
||||
|
||||
Follow-up for 6d48c7cf736ced70c1c2fef1e1f03618911d04bc.
|
||||
|
||||
(cherry picked from commit 67111e1bd918f9e1b4b542d1e0fe84f1d571876e)
|
||||
|
||||
Resolves: RHEL-115182
|
||||
---
|
||||
man/systemd.resource-control.xml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
|
||||
index 2a0e40a17d..9431fb20a1 100644
|
||||
--- a/man/systemd.resource-control.xml
|
||||
+++ b/man/systemd.resource-control.xml
|
||||
@@ -365,7 +365,7 @@
|
||||
an absolute number of tasks or a percentage value that is taken relative to the configured maximum
|
||||
number of tasks on the system. If assigned the special value <literal>infinity</literal>, no tasks
|
||||
limit is applied. This controls the <literal>pids.max</literal> control group attribute. For
|
||||
- details about this control group attribute, the
|
||||
+ details about this control group attribute, see the
|
||||
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#pid">pids controller
|
||||
</ulink>.</para>
|
||||
|
||||
167
1275-cryptsetup-Add-optional-support-for-linking-volume-k.patch
Normal file
167
1275-cryptsetup-Add-optional-support-for-linking-volume-k.patch
Normal file
@ -0,0 +1,167 @@
|
||||
From 26d6ea70cfb9232dc9ab66ee0927fb546fe0418b Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Kozina <okozina@redhat.com>
|
||||
Date: Wed, 31 Jan 2024 13:11:21 +0100
|
||||
Subject: [PATCH] cryptsetup: Add optional support for linking volume key in
|
||||
keyring.
|
||||
|
||||
cryptsetup 2.7.0 adds feature to link effective volume key in custom
|
||||
kernel keyring during device activation. It can be used later to pass
|
||||
linked volume key to other services.
|
||||
|
||||
For example: kdump enabled systems installed on LUKS2 device.
|
||||
This feature allows it to store volume key linked in a kernel keyring
|
||||
to the kdump reserved memory and reuse it to reactivate LUKS2 device
|
||||
in case of kernel crash.
|
||||
|
||||
(cherry picked from commit c5daf14c88ba44cefabe052de93a29d28b6b0175)
|
||||
|
||||
Resolves: RHEL-97175
|
||||
---
|
||||
man/crypttab.xml | 21 ++++++++++++
|
||||
meson.build | 3 +-
|
||||
src/cryptsetup/cryptsetup.c | 65 +++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 88 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/man/crypttab.xml b/man/crypttab.xml
|
||||
index 1dd9bb1bb6..bd49e025fa 100644
|
||||
--- a/man/crypttab.xml
|
||||
+++ b/man/crypttab.xml
|
||||
@@ -239,6 +239,27 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><option>link-volume-key=</option></term>
|
||||
+
|
||||
+ <listitem><para>Specifies the kernel keyring and key description
|
||||
+ (see <citerefentry project='man-pages'><refentrytitle>keyrings</refentrytitle><manvolnum>7</manvolnum></citerefentry>)
|
||||
+ where LUKS2 volume key gets linked during device activation. The kernel keyring
|
||||
+ description and key description must be separated by <literal>::</literal>.</para>
|
||||
+
|
||||
+ <para>The kernel keyring part can be a string description or a predefined
|
||||
+ kernel keyring prefixed with <literal>@</literal> (e.g.: to use <literal>@s</literal> session or
|
||||
+ <literal>@u</literal> user keyring directly). The type prefix text in the kernel keyring description
|
||||
+ is not required. The specified kernel keyring must already exist at the time of device activation.</para>
|
||||
+
|
||||
+ <para>The key part is a string description optionally prefixed by a <literal>%key_type:</literal>.
|
||||
+ If no type is specified, the <literal>user</literal> type key is linked by default. See
|
||||
+ <citerefentry project='man-pages'><refentrytitle>keyctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
+ for more information on key descriptions (KEY IDENTIFIERS section).</para>
|
||||
+
|
||||
+ <para>Note that the linked volume key is not cleaned up automatically when the device is detached.</para></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><option>luks</option></term>
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index cbde702211..684324c6d7 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -1316,7 +1316,8 @@ if want_libcryptsetup != 'false' and not skip_deps
|
||||
|
||||
foreach ident : ['crypt_set_metadata_size',
|
||||
'crypt_activate_by_signed_key',
|
||||
- 'crypt_token_max']
|
||||
+ 'crypt_token_max',
|
||||
+ 'crypt_set_keyring_to_link']
|
||||
have_ident = have and cc.has_function(
|
||||
ident,
|
||||
prefix : '#include <libcryptsetup.h>',
|
||||
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
|
||||
index 3f2cab1e41..f9130e2568 100644
|
||||
--- a/src/cryptsetup/cryptsetup.c
|
||||
+++ b/src/cryptsetup/cryptsetup.c
|
||||
@@ -101,6 +101,9 @@ static bool arg_headless = false;
|
||||
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
|
||||
static unsigned arg_tpm2_measure_pcr = UINT_MAX; /* This and the following field is about measuring the unlocked volume key to the local TPM */
|
||||
static char **arg_tpm2_measure_banks = NULL;
|
||||
+static char *arg_link_keyring = NULL;
|
||||
+static char *arg_link_key_type = NULL;
|
||||
+static char *arg_link_key_description = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
||||
@@ -113,6 +116,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_fido2_rp_id, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_banks, strv_freep);
|
||||
+STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
|
||||
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
|
||||
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
|
||||
|
||||
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
|
||||
[PASSPHRASE_REGULAR] = "passphrase",
|
||||
@@ -486,6 +492,56 @@ static int parse_one_option(const char *option) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
|
||||
|
||||
+ } else if ((val = startswith(option, "link-volume-key="))) {
|
||||
+#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
+ const char *sep, *c;
|
||||
+ _cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
|
||||
+
|
||||
+ /* Stick with cryptsetup --link-vk-to-keyring format
|
||||
+ * <keyring_description>::%<key_type>:<key_description>,
|
||||
+ * where %<key_type> is optional and defaults to 'user'.
|
||||
+ */
|
||||
+ if (!(sep = strstr(val, "::")))
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %m");
|
||||
+
|
||||
+ /* cryptsetup (cli) supports <keyring_description> passed in various formats:
|
||||
+ * - well-known keyrings prefixed with '@' (@u user, @s session, etc)
|
||||
+ * - text descriptions prefixed with "%:" or "%keyring:".
|
||||
+ * - text desription with no prefix.
|
||||
+ * - numeric keyring id (ignored in current patch set). */
|
||||
+ if (*val == '@' || *val == '%')
|
||||
+ keyring = strndup(val, sep - val);
|
||||
+ else
|
||||
+ /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */
|
||||
+ keyring = strnappend("%:", val, sep - val);
|
||||
+ if (!keyring)
|
||||
+ return log_oom();
|
||||
+
|
||||
+ sep += 2;
|
||||
+
|
||||
+ /* %<key_type> is optional (and defaults to 'user') */
|
||||
+ if (*sep == '%') {
|
||||
+ /* must be separated by colon */
|
||||
+ if (!(c = strchr(sep, ':')))
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %m");
|
||||
+
|
||||
+ key_type = strndup(sep + 1, c - sep - 1);
|
||||
+ if (!key_type)
|
||||
+ return log_oom();
|
||||
+
|
||||
+ sep = c + 1;
|
||||
+ }
|
||||
+
|
||||
+ key_description = strdup(sep);
|
||||
+ if (!key_description)
|
||||
+ return log_oom();
|
||||
+
|
||||
+ free_and_replace(arg_link_keyring, keyring);
|
||||
+ free_and_replace(arg_link_key_type, key_type);
|
||||
+ free_and_replace(arg_link_key_description, key_description);
|
||||
+#else
|
||||
+ log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
|
||||
+#endif
|
||||
} else if (!streq(option, "x-initrd.attach"))
|
||||
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
||||
|
||||
@@ -2207,6 +2263,15 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
|
||||
|
||||
+/* since cryptsetup 2.7.0 (Jan 2024) */
|
||||
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
+ if (arg_link_key_description) {
|
||||
+ r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
|
||||
+ if (r < 0)
|
||||
+ log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (arg_header) {
|
||||
r = crypt_set_data_device(cd, source);
|
||||
if (r < 0)
|
||||
27
1276-cryptsetup-fix-typo.patch
Normal file
27
1276-cryptsetup-fix-typo.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 44f65e9b9a0f67a69886d25367875e9707affc81 Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Wed, 14 Feb 2024 04:01:36 +0900
|
||||
Subject: [PATCH] cryptsetup: fix typo
|
||||
|
||||
Follow-up for c5daf14c88ba44cefabe052de93a29d28b6b0175.
|
||||
|
||||
(cherry picked from commit a14d3b48f7647676a0c43bceaecd56d9a77e3de6)
|
||||
|
||||
Resolves: RHEL-97175
|
||||
---
|
||||
src/cryptsetup/cryptsetup.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
|
||||
index f9130e2568..1f672f19f1 100644
|
||||
--- a/src/cryptsetup/cryptsetup.c
|
||||
+++ b/src/cryptsetup/cryptsetup.c
|
||||
@@ -507,7 +507,7 @@ static int parse_one_option(const char *option) {
|
||||
/* cryptsetup (cli) supports <keyring_description> passed in various formats:
|
||||
* - well-known keyrings prefixed with '@' (@u user, @s session, etc)
|
||||
* - text descriptions prefixed with "%:" or "%keyring:".
|
||||
- * - text desription with no prefix.
|
||||
+ * - text description with no prefix.
|
||||
* - numeric keyring id (ignored in current patch set). */
|
||||
if (*val == '@' || *val == '%')
|
||||
keyring = strndup(val, sep - val);
|
||||
@ -0,0 +1,27 @@
|
||||
From be6acfdfd0ddd5625d68bdeb1fb5962d710557be Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Sun, 17 Aug 2025 21:05:24 +0900
|
||||
Subject: [PATCH] cryptsetup: HAVE_CRYPT_SET_KEYRING_TO_LINK is always defined
|
||||
|
||||
Follow-up for c5daf14c88ba44cefabe052de93a29d28b6b0175 (v256).
|
||||
|
||||
(cherry picked from commit fb4aabf4432d523b97376099ce4353b5c268ae82)
|
||||
|
||||
Resolves: RHEL-97175
|
||||
---
|
||||
src/cryptsetup/cryptsetup.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
|
||||
index 1f672f19f1..4dc315e810 100644
|
||||
--- a/src/cryptsetup/cryptsetup.c
|
||||
+++ b/src/cryptsetup/cryptsetup.c
|
||||
@@ -493,7 +493,7 @@ static int parse_one_option(const char *option) {
|
||||
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
|
||||
|
||||
} else if ((val = startswith(option, "link-volume-key="))) {
|
||||
-#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
const char *sep, *c;
|
||||
_cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From 9109aaae160fe7dcb9390829db619e4e8f90274f Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 31 Oct 2024 17:02:59 +0100
|
||||
Subject: [PATCH] coredump: make check that all argv[] meta data fields are
|
||||
passed strict
|
||||
|
||||
Otherwise, if some field is not supplied we might end up parsing a NULL
|
||||
string later. Let's catch that early.
|
||||
|
||||
(cherry picked from commit 098c3975acb3df61eedfe471fca27c21f13cf04c)
|
||||
|
||||
Related: RHEL-104138
|
||||
---
|
||||
src/coredump/coredump.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
|
||||
index dca78fa72c..b24f4c8cc3 100644
|
||||
--- a/src/coredump/coredump.c
|
||||
+++ b/src/coredump/coredump.c
|
||||
@@ -1067,9 +1067,10 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
}
|
||||
}
|
||||
|
||||
- if (!context->meta[META_ARGV_PID])
|
||||
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
- "Failed to find the PID of crashing process");
|
||||
+ /* The basic fields from argv[] should always be there, refuse early if not */
|
||||
+ for (int i = 0; i < _META_ARGV_MAX; i++)
|
||||
+ if (!context->meta[i])
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A required (%s) has not been sent, aborting.", meta_field_names[i]);
|
||||
|
||||
r = parse_pid(context->meta[META_ARGV_PID], &context->pid);
|
||||
if (r < 0)
|
||||
122
1279-coredump-restore-compatibility-with-older-patterns.patch
Normal file
122
1279-coredump-restore-compatibility-with-older-patterns.patch
Normal file
@ -0,0 +1,122 @@
|
||||
From 38d7a52bcdad1cef1dba218f86e3905c24d51d9a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Tue, 29 Apr 2025 14:47:59 +0200
|
||||
Subject: [PATCH] coredump: restore compatibility with older patterns
|
||||
|
||||
This was broken in f45b8015513d38ee5f7cc361db9c5b88c9aae704. Unfortunately
|
||||
the review does not talk about backward compatibility at all. There are
|
||||
two places where it matters:
|
||||
- During upgrades, the replacement of kernel.core_pattern is asynchronous.
|
||||
For example, during rpm upgrades, it would be updated a post-transaction
|
||||
file trigger. In other scenarios, the update might only happen after
|
||||
reboot. We have a potentially long window where the old pattern is in
|
||||
place. We need to capture coredumps during upgrades too.
|
||||
- With --backtrace. The interface of --backtrace, in hindsight, is not
|
||||
great. But there are users of --backtrace which were written to use
|
||||
a specific set of arguments, and we can't just break compatiblity.
|
||||
One example is systemd-coredump-python, but there are also reports of
|
||||
users using --backtrace to generate coredump logs.
|
||||
|
||||
Thus, we require the original set of args, and will use the additional args if
|
||||
found.
|
||||
|
||||
A test is added to verify that --backtrace works with and without the optional
|
||||
args.
|
||||
|
||||
(cherry picked from commit ded0aac389e647d35bce7ec4a48e718d77c0435b)
|
||||
|
||||
Related: RHEL-104138
|
||||
---
|
||||
src/coredump/coredump.c | 23 +++++++++++++++--------
|
||||
test/units/testsuite-74.coredump.sh | 18 +++++++++++-------
|
||||
2 files changed, 26 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
|
||||
index b24f4c8cc3..458857ffb2 100644
|
||||
--- a/src/coredump/coredump.c
|
||||
+++ b/src/coredump/coredump.c
|
||||
@@ -94,8 +94,12 @@ enum {
|
||||
META_ARGV_SIGNAL, /* %s: number of signal causing dump */
|
||||
META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch (we expand this to µs granularity) */
|
||||
META_ARGV_RLIMIT, /* %c: core file size soft resource limit */
|
||||
- META_ARGV_HOSTNAME, /* %h: hostname */
|
||||
+ _META_ARGV_REQUIRED,
|
||||
+ /* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
|
||||
+ META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
|
||||
_META_ARGV_MAX,
|
||||
+ /* If new fields are added, they should be added here, to maintain compatibility
|
||||
+ * with callers which don't know about the new fields. */
|
||||
|
||||
/* The following indexes are cached for a couple of special fields we use (and
|
||||
* thereby need to be retrieved quickly) for naming coredump files, and attaching
|
||||
@@ -106,7 +110,7 @@ enum {
|
||||
_META_MANDATORY_MAX,
|
||||
|
||||
/* The rest are similar to the previous ones except that we won't fail if one of
|
||||
- * them is missing. */
|
||||
+ * them is missing in a message sent over the socket. */
|
||||
|
||||
META_EXE = _META_MANDATORY_MAX,
|
||||
META_UNIT,
|
||||
@@ -1068,7 +1072,7 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
}
|
||||
|
||||
/* The basic fields from argv[] should always be there, refuse early if not */
|
||||
- for (int i = 0; i < _META_ARGV_MAX; i++)
|
||||
+ for (int i = 0; i < _META_ARGV_REQUIRED; i++)
|
||||
if (!context->meta[i])
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A required (%s) has not been sent, aborting.", meta_field_names[i]);
|
||||
|
||||
@@ -1286,14 +1290,17 @@ static int gather_pid_metadata_from_argv(
|
||||
char *t;
|
||||
|
||||
/* We gather all metadata that were passed via argv[] into an array of iovecs that
|
||||
- * we'll forward to the socket unit */
|
||||
+ * we'll forward to the socket unit.
|
||||
+ *
|
||||
+ * We require at least _META_ARGV_REQUIRED args, but will accept more.
|
||||
+ * We know how to parse _META_ARGV_MAX args. The rest will be ignored. */
|
||||
|
||||
- if (argc < _META_ARGV_MAX)
|
||||
+ if (argc < _META_ARGV_REQUIRED)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
- "Not enough arguments passed by the kernel (%i, expected %i).",
|
||||
- argc, _META_ARGV_MAX);
|
||||
+ "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
|
||||
+ argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
|
||||
|
||||
- for (int i = 0; i < _META_ARGV_MAX; i++) {
|
||||
+ for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
|
||||
|
||||
t = argv[i];
|
||||
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index 1093cad8a9..0163131096 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -218,14 +218,18 @@ rm -f /tmp/core.{output,redirected}
|
||||
(! "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_BIN" >/dev/null)
|
||||
|
||||
# --backtrace mode
|
||||
-# Pass one of the existing journal coredump records to systemd-coredump and
|
||||
-# use our PID as the source to make matching the coredump later easier
|
||||
-# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT HOSTNAME
|
||||
+# Pass one of the existing journal coredump records to systemd-coredump.
|
||||
+# Use our PID as the source to be able to create a PIDFD and to make matching easier.
|
||||
+# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT [HOSTNAME]
|
||||
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
- /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509994 12345 mymachine
|
||||
-# Wait a bit for the coredump to get processed
|
||||
-timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done"
|
||||
-coredumpctl info "$$"
|
||||
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
|
||||
+journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
|
||||
+# Wait a bit for the coredumps to get processed
|
||||
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
|
||||
+coredumpctl info $$
|
||||
+coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
|
||||
+coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
|
||||
coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
|
||||
# This used to cause a stack overflow
|
||||
158
1280-coredump-use-d-in-kernel-core-pattern.patch
Normal file
158
1280-coredump-use-d-in-kernel-core-pattern.patch
Normal file
@ -0,0 +1,158 @@
|
||||
From fbc5015c95298c71c806b5e80207e52688aad69a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Tue, 29 Apr 2025 14:47:59 +0200
|
||||
Subject: [PATCH] coredump: use %d in kernel core pattern
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The kernel provides %d which is documented as
|
||||
"dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE".
|
||||
|
||||
We already query /proc/pid/auxv for this information, but unfortunately this
|
||||
check is subject to a race, because the crashed process may be replaced by an
|
||||
attacker before we read this data, for example replacing a SUID process that
|
||||
was killed by a signal with another process that is not SUID, tricking us into
|
||||
making the coredump of the original process readable by the attacker.
|
||||
|
||||
With this patch, we effectively add one more check to the list of conditions
|
||||
that need be satisfied if we are to make the coredump accessible to the user.
|
||||
|
||||
Reportedy-by: Qualys Security Advisory <qsa@qualys.com>
|
||||
|
||||
In principle, %d might return a value other than 0, 1, or 2 in the future.
|
||||
Thus, we accept those, but emit a notice.
|
||||
|
||||
(cherry picked from commit 0c49e0049b7665bb7769a13ef346fef92e1ad4d6)
|
||||
|
||||
Related: RHEL-104138
|
||||
---
|
||||
man/systemd-coredump.xml | 10 ++++++++++
|
||||
src/coredump/coredump.c | 22 +++++++++++++++++++---
|
||||
sysctl.d/50-coredump.conf.in | 2 +-
|
||||
test/units/testsuite-74.coredump.sh | 5 +++++
|
||||
4 files changed, 35 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
|
||||
index cb9f47745b..6cfa04f466 100644
|
||||
--- a/man/systemd-coredump.xml
|
||||
+++ b/man/systemd-coredump.xml
|
||||
@@ -259,6 +259,16 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><varname>COREDUMP_DUMPABLE=</varname></term>
|
||||
+
|
||||
+ <listitem><para>The <constant>PR_GET_DUMPABLE</constant> field as reported by the kernel, see
|
||||
+ <citerefentry
|
||||
+ project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
|
||||
|
||||
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
|
||||
index 458857ffb2..cd10678c43 100644
|
||||
--- a/src/coredump/coredump.c
|
||||
+++ b/src/coredump/coredump.c
|
||||
@@ -97,7 +97,9 @@ enum {
|
||||
_META_ARGV_REQUIRED,
|
||||
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
|
||||
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
|
||||
+ META_ARGV_DUMPABLE, /* %d: as set by the kernel */
|
||||
_META_ARGV_MAX,
|
||||
+
|
||||
/* If new fields are added, they should be added here, to maintain compatibility
|
||||
* with callers which don't know about the new fields. */
|
||||
|
||||
@@ -126,6 +128,7 @@ static const char * const meta_field_names[_META_MAX] = {
|
||||
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
|
||||
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
|
||||
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
|
||||
+ [META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
|
||||
[META_COMM] = "COREDUMP_COMM=",
|
||||
[META_EXE] = "COREDUMP_EXE=",
|
||||
[META_UNIT] = "COREDUMP_UNIT=",
|
||||
@@ -138,6 +141,7 @@ typedef struct Context {
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
+ unsigned dumpable;
|
||||
bool is_pid1;
|
||||
bool is_journald;
|
||||
} Context;
|
||||
@@ -453,14 +457,16 @@ static int grant_user_access(int core_fd, const Context *context) {
|
||||
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. */
|
||||
+ /* We allow access if %d/dumpable on the command line was exactly 1, we got all the data,
|
||||
+ * at_secure is not set, and the uid/gid match euid/egid. */
|
||||
bool ret =
|
||||
+ context->dumpable == 1 &&
|
||||
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)",
|
||||
+ log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
|
||||
ret ? "permit" : "restrict",
|
||||
+ context->dumpable,
|
||||
uid, euid, gid, egid, yes_no(at_secure));
|
||||
return ret;
|
||||
}
|
||||
@@ -1089,6 +1095,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
return log_error_errno(r, "Failed to parse GID \"%s\": %m", context->meta[META_ARGV_GID]);
|
||||
|
||||
|
||||
+ /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2,
|
||||
+ * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
|
||||
+ if (context->meta[META_ARGV_DUMPABLE]) {
|
||||
+ r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]);
|
||||
+ if (context->dumpable > 2)
|
||||
+ log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
|
||||
+ }
|
||||
+
|
||||
unit = context->meta[META_UNIT];
|
||||
context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
|
||||
context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);
|
||||
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
|
||||
index 5fb551a8cf..9c10a89828 100644
|
||||
--- a/sysctl.d/50-coredump.conf.in
|
||||
+++ b/sysctl.d/50-coredump.conf.in
|
||||
@@ -13,7 +13,7 @@
|
||||
# the core dump.
|
||||
#
|
||||
# See systemd-coredump(8) and core(5).
|
||||
-kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
|
||||
+kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
|
||||
|
||||
# Allow 16 coredumps to be dispatched in parallel by the kernel.
|
||||
# We collect metadata from /proc/%P/, and thus need to make sure the crashed
|
||||
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
|
||||
index 0163131096..b72313672c 100755
|
||||
--- a/test/units/testsuite-74.coredump.sh
|
||||
+++ b/test/units/testsuite-74.coredump.sh
|
||||
@@ -225,12 +225,17 @@ journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE
|
||||
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
|
||||
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
|
||||
+journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
|
||||
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509902 12345 youmachine 1
|
||||
# Wait a bit for the coredumps to get processed
|
||||
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
|
||||
coredumpctl info $$
|
||||
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
|
||||
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
|
||||
coredumpctl info COREDUMP_HOSTNAME="mymachine"
|
||||
+coredumpctl info COREDUMP_TIMESTAMP=1679509902000000
|
||||
+coredumpctl info COREDUMP_HOSTNAME="youmachine"
|
||||
+coredumpctl info COREDUMP_DUMPABLE="1"
|
||||
|
||||
# This used to cause a stack overflow
|
||||
systemd-run -t --property CoredumpFilter=all ls /tmp
|
||||
230
1281-pidref-add-structure-that-can-reference-a-pid-via-bo.patch
Normal file
230
1281-pidref-add-structure-that-can-reference-a-pid-via-bo.patch
Normal file
@ -0,0 +1,230 @@
|
||||
From e638eb667af0e8ac9d3d409edbbf51507a4eef0e Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Sat, 9 Sep 2023 09:29:27 +0200
|
||||
Subject: [PATCH] pidref: add structure that can reference a pid via both pidfd
|
||||
and pid_t
|
||||
|
||||
Let's start with the conversion of PID 1 to pidfds. Let's add a simple
|
||||
structure with just two fields that can be used to maintain a reference
|
||||
to arbitrary processes via both pid_t and pidfd.
|
||||
|
||||
This is an embeddable struct, to keep it in line with where we
|
||||
previously used a pid_t directly to track a process.
|
||||
|
||||
Of course, since this might contain an fd on systems where we have pidfd
|
||||
this structure has a proper lifecycle.
|
||||
|
||||
(Note that this is quite different from sd_event_add_child() event
|
||||
source objects as that one is only for child processes and collects
|
||||
process results, while this infra is much simpler and more generic and
|
||||
can be used to reference any process, anywhere in the tree.)
|
||||
|
||||
(cherry picked from commit 3bda3f17fa84557eeb28fa7c330cbd3a3f876d47)
|
||||
|
||||
Related: RHEL-104138
|
||||
---
|
||||
src/basic/meson.build | 1 +
|
||||
src/basic/pidref.c | 145 ++++++++++++++++++++++++++++++++++++++++++
|
||||
src/basic/pidref.h | 29 +++++++++
|
||||
3 files changed, 175 insertions(+)
|
||||
create mode 100644 src/basic/pidref.c
|
||||
create mode 100644 src/basic/pidref.h
|
||||
|
||||
diff --git a/src/basic/meson.build b/src/basic/meson.build
|
||||
index 11053a5ecd..b8b4213c70 100644
|
||||
--- a/src/basic/meson.build
|
||||
+++ b/src/basic/meson.build
|
||||
@@ -182,6 +182,7 @@ basic_sources = files(
|
||||
'path-util.h',
|
||||
'percent-util.c',
|
||||
'percent-util.h',
|
||||
+ 'pidref.c',
|
||||
'prioq.c',
|
||||
'prioq.h',
|
||||
'proc-cmdline.c',
|
||||
diff --git a/src/basic/pidref.c b/src/basic/pidref.c
|
||||
new file mode 100644
|
||||
index 0000000000..f41460938c
|
||||
--- /dev/null
|
||||
+++ b/src/basic/pidref.c
|
||||
@@ -0,0 +1,145 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+
|
||||
+#include "errno-util.h"
|
||||
+#include "fd-util.h"
|
||||
+#include "missing_syscall.h"
|
||||
+#include "parse-util.h"
|
||||
+#include "pidref.h"
|
||||
+#include "process-util.h"
|
||||
+
|
||||
+int pidref_set_pid(PidRef *pidref, pid_t pid) {
|
||||
+ int fd;
|
||||
+
|
||||
+ assert(pidref);
|
||||
+
|
||||
+ if (pid < 0)
|
||||
+ return -ESRCH;
|
||||
+ if (pid == 0)
|
||||
+ pid = getpid_cached();
|
||||
+
|
||||
+ fd = pidfd_open(pid, 0);
|
||||
+ if (fd < 0) {
|
||||
+ /* Graceful fallback in case the kernel doesn't support pidfds or is out of fds */
|
||||
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_RESOURCE(errno))
|
||||
+ return -errno;
|
||||
+
|
||||
+ fd = -EBADF;
|
||||
+ }
|
||||
+
|
||||
+ *pidref = (PidRef) {
|
||||
+ .fd = fd,
|
||||
+ .pid = pid,
|
||||
+ };
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int pidref_set_pidstr(PidRef *pidref, const char *pid) {
|
||||
+ pid_t nr;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(pidref);
|
||||
+
|
||||
+ r = parse_pid(pid, &nr);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ return pidref_set_pid(pidref, nr);
|
||||
+}
|
||||
+
|
||||
+int pidref_set_pidfd(PidRef *pidref, int fd) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(pidref);
|
||||
+
|
||||
+ if (fd < 0)
|
||||
+ return -EBADF;
|
||||
+
|
||||
+ int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
+ if (fd_copy < 0) {
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (!ERRNO_IS_RESOURCE(errno))
|
||||
+ return -errno;
|
||||
+
|
||||
+ /* Graceful fallback if we are out of fds */
|
||||
+ r = pidfd_get_pid(fd, &pid);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ *pidref = (PidRef) {
|
||||
+ .fd = -EBADF,
|
||||
+ .pid = pid,
|
||||
+ };
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return pidref_set_pidfd_consume(pidref, fd_copy);
|
||||
+}
|
||||
+
|
||||
+int pidref_set_pidfd_take(PidRef *pidref, int fd) {
|
||||
+ pid_t pid;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(pidref);
|
||||
+
|
||||
+ if (fd < 0)
|
||||
+ return -EBADF;
|
||||
+
|
||||
+ r = pidfd_get_pid(fd, &pid);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ *pidref = (PidRef) {
|
||||
+ .fd = fd,
|
||||
+ .pid = pid,
|
||||
+ };
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
|
||||
+ int r;
|
||||
+
|
||||
+ r = pidref_set_pidfd_take(pidref, fd);
|
||||
+ if (r < 0)
|
||||
+ safe_close(fd);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+void pidref_done(PidRef *pidref) {
|
||||
+ assert(pidref);
|
||||
+
|
||||
+ *pidref = (PidRef) {
|
||||
+ .fd = safe_close(pidref->fd),
|
||||
+ };
|
||||
+}
|
||||
+
|
||||
+int pidref_kill(PidRef *pidref, int sig) {
|
||||
+
|
||||
+ if (!pidref)
|
||||
+ return -ESRCH;
|
||||
+
|
||||
+ if (pidref->fd >= 0)
|
||||
+ return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
|
||||
+
|
||||
+ if (pidref->pid > 0)
|
||||
+ return RET_NERRNO(kill(pidref->pid, sig));
|
||||
+
|
||||
+ return -ESRCH;
|
||||
+}
|
||||
+
|
||||
+int pidref_kill_and_sigcont(PidRef *pidref, int sig) {
|
||||
+ int r;
|
||||
+
|
||||
+ r = pidref_kill(pidref, sig);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ if (!IN_SET(sig, SIGCONT, SIGKILL))
|
||||
+ (void) pidref_kill(pidref, SIGCONT);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/src/basic/pidref.h b/src/basic/pidref.h
|
||||
new file mode 100644
|
||||
index 0000000000..2411e510f1
|
||||
--- /dev/null
|
||||
+++ b/src/basic/pidref.h
|
||||
@@ -0,0 +1,29 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+#pragma once
|
||||
+
|
||||
+#include "macro.h"
|
||||
+
|
||||
+/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continously. */
|
||||
+typedef struct PidRef {
|
||||
+ pid_t pid; /* always valid */
|
||||
+ int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd */
|
||||
+} PidRef;
|
||||
+
|
||||
+#define PIDREF_NULL (PidRef) { .fd = -EBADF }
|
||||
+
|
||||
+static inline bool pidref_is_set(const PidRef *pidref) {
|
||||
+ return pidref && pidref->pid > 0;
|
||||
+}
|
||||
+
|
||||
+int pidref_set_pid(PidRef *pidref, pid_t pid);
|
||||
+int pidref_set_pidstr(PidRef *pidref, const char *pid);
|
||||
+int pidref_set_pidfd(PidRef *pidref, int fd);
|
||||
+int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success*/
|
||||
+int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */
|
||||
+
|
||||
+void pidref_done(PidRef *pidref);
|
||||
+
|
||||
+int pidref_kill(PidRef *pidref, int sig);
|
||||
+int pidref_kill_and_sigcont(PidRef *pidref, int sig);
|
||||
+
|
||||
+#define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL)
|
||||
54
1282-fd-util-introduce-parse_fd.patch
Normal file
54
1282-fd-util-introduce-parse_fd.patch
Normal file
@ -0,0 +1,54 @@
|
||||
From 8219e46540ddf0d6a7d3f97481debf297723a58f Mon Sep 17 00:00:00 2001
|
||||
From: David Tardon <dtardon@redhat.com>
|
||||
Date: Fri, 5 May 2023 08:09:14 +0200
|
||||
Subject: [PATCH] fd-util: introduce parse_fd()
|
||||
|
||||
It's a simple wrapper for safe_atoi() that returns error if the parsed
|
||||
fd is < 0 .
|
||||
|
||||
(cherry picked from commit b8f83d7f0c35dca6ca3a23c42215d566e2815ca5)
|
||||
|
||||
Related: RHEL-104138
|
||||
---
|
||||
src/basic/parse-util.c | 15 +++++++++++++++
|
||||
src/basic/parse-util.h | 1 +
|
||||
2 files changed, 16 insertions(+)
|
||||
|
||||
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
|
||||
index 3b3efb0ab8..4161211c49 100644
|
||||
--- a/src/basic/parse-util.c
|
||||
+++ b/src/basic/parse-util.c
|
||||
@@ -313,6 +313,21 @@ int parse_errno(const char *t) {
|
||||
return e;
|
||||
}
|
||||
|
||||
+int parse_fd(const char *t) {
|
||||
+ int r, fd;
|
||||
+
|
||||
+ assert(t);
|
||||
+
|
||||
+ r = safe_atoi(t, &fd);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ if (fd < 0)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ return fd;
|
||||
+}
|
||||
+
|
||||
static const char *mangle_base(const char *s, unsigned *base) {
|
||||
const char *k;
|
||||
|
||||
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
|
||||
index 8d8d52327b..5c012d702a 100644
|
||||
--- a/src/basic/parse-util.h
|
||||
+++ b/src/basic/parse-util.h
|
||||
@@ -20,6 +20,7 @@ int parse_mtu(int family, const char *s, uint32_t *ret);
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
||||
int parse_errno(const char *t);
|
||||
+int parse_fd(const char *t);
|
||||
|
||||
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
|
||||
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
|
||||
245
1283-coredump-add-support-for-new-F-PIDFD-specifier.patch
Normal file
245
1283-coredump-add-support-for-new-F-PIDFD-specifier.patch
Normal file
@ -0,0 +1,245 @@
|
||||
From 27faf1af778849841d7c3140bd3d92aceaea2ee3 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Sun, 13 Apr 2025 22:10:36 +0100
|
||||
Subject: [PATCH] coredump: add support for new %F PIDFD specifier
|
||||
|
||||
A new core_pattern specifier was added, %F, to provide a PIDFD
|
||||
to the usermode helper process referring to the crashed process.
|
||||
This removes all possible race conditions, ensuring only the
|
||||
crashed process gets inspected by systemd-coredump.
|
||||
|
||||
(cherry picked from commit 868d95577ec9f862580ad365726515459be582fc)
|
||||
|
||||
Resolves: RHEL-104138
|
||||
---
|
||||
man/systemd-coredump.xml | 9 ++++
|
||||
src/coredump/coredump.c | 89 ++++++++++++++++++++++++++++++++----
|
||||
sysctl.d/50-coredump.conf.in | 2 +-
|
||||
3 files changed, 89 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
|
||||
index 6cfa04f466..b3d81d838a 100644
|
||||
--- a/man/systemd-coredump.xml
|
||||
+++ b/man/systemd-coredump.xml
|
||||
@@ -186,6 +186,15 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><varname>COREDUMP_BY_PIDFD=</varname></term>
|
||||
+ <listitem><para>If the crashed process was analyzed using a PIDFD provided by the kernel (requires
|
||||
+ kernel v6.16) then this field will be present and set to <literal>1</literal>. If this field is
|
||||
+ not set, then the crashed process was analyzed via a PID, which is known to be subject to race
|
||||
+ conditions.</para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><varname>COREDUMP_TIMESTAMP=</varname></term>
|
||||
<listitem><para>The time of the crash as reported by the kernel (in µs since the epoch).</para>
|
||||
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
|
||||
index cd10678c43..e0aac3c8d0 100644
|
||||
--- a/src/coredump/coredump.c
|
||||
+++ b/src/coredump/coredump.c
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "mkdir-label.h"
|
||||
#include "namespace-util.h"
|
||||
#include "parse-util.h"
|
||||
+#include "pidref.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "socket-util.h"
|
||||
@@ -98,8 +99,8 @@ enum {
|
||||
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
|
||||
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
|
||||
META_ARGV_DUMPABLE, /* %d: as set by the kernel */
|
||||
+ META_ARGV_PIDFD, /* %F: pidfd of the process, since v6.16 */
|
||||
_META_ARGV_MAX,
|
||||
-
|
||||
/* If new fields are added, they should be added here, to maintain compatibility
|
||||
* with callers which don't know about the new fields. */
|
||||
|
||||
@@ -129,6 +130,7 @@ static const char * const meta_field_names[_META_MAX] = {
|
||||
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
|
||||
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
|
||||
[META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
|
||||
+ [META_ARGV_PIDFD] = "COREDUMP_BY_PIDFD=",
|
||||
[META_COMM] = "COREDUMP_COMM=",
|
||||
[META_EXE] = "COREDUMP_EXE=",
|
||||
[META_UNIT] = "COREDUMP_UNIT=",
|
||||
@@ -136,6 +138,7 @@ static const char * const meta_field_names[_META_MAX] = {
|
||||
};
|
||||
|
||||
typedef struct Context {
|
||||
+ PidRef pidref;
|
||||
const char *meta[_META_MAX];
|
||||
size_t meta_size[_META_MAX];
|
||||
pid_t pid;
|
||||
@@ -146,6 +149,14 @@ typedef struct Context {
|
||||
bool is_journald;
|
||||
} Context;
|
||||
|
||||
+#define CONTEXT_NULL \
|
||||
+ (Context) { \
|
||||
+ .pidref = PIDREF_NULL, \
|
||||
+ .uid = UID_INVALID, \
|
||||
+ .gid = GID_INVALID, \
|
||||
+ }
|
||||
+
|
||||
+
|
||||
typedef enum CoredumpStorage {
|
||||
COREDUMP_STORAGE_NONE,
|
||||
COREDUMP_STORAGE_EXTERNAL,
|
||||
@@ -171,6 +182,12 @@ static uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX;
|
||||
static uint64_t arg_keep_free = UINT64_MAX;
|
||||
static uint64_t arg_max_use = UINT64_MAX;
|
||||
|
||||
+static void context_done(Context *c) {
|
||||
+ assert(c);
|
||||
+
|
||||
+ pidref_done(&c->pidref);
|
||||
+}
|
||||
+
|
||||
static int parse_config(void) {
|
||||
static const ConfigTableItem items[] = {
|
||||
{ "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
|
||||
@@ -1114,7 +1131,7 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
|
||||
static int process_socket(int fd) {
|
||||
_cleanup_close_ int input_fd = -EBADF, mntns_fd = -EBADF;
|
||||
- Context context = {};
|
||||
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
|
||||
struct iovec_wrapper iovw = {};
|
||||
struct iovec iovec;
|
||||
int iterations = 0, r;
|
||||
@@ -1215,7 +1232,7 @@ static int process_socket(int fd) {
|
||||
goto finish;
|
||||
|
||||
/* Make sure we received at least all fields we need. */
|
||||
- for (int i = 0; i < _META_MANDATORY_MAX; i++)
|
||||
+ for (int i = 0; i < _META_ARGV_REQUIRED; i++)
|
||||
if (!context.meta[i]) {
|
||||
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"A mandatory argument (%i) has not been sent, aborting.",
|
||||
@@ -1301,9 +1318,9 @@ static int gather_pid_metadata_from_argv(
|
||||
Context *context,
|
||||
int argc, char **argv) {
|
||||
|
||||
+ _cleanup_(pidref_done) PidRef local_pidref = PIDREF_NULL;
|
||||
_cleanup_free_ char *free_timestamp = NULL;
|
||||
- int r, signo;
|
||||
- char *t;
|
||||
+ int r, signo, kernel_fd = -EBADF;
|
||||
|
||||
/* We gather all metadata that were passed via argv[] into an array of iovecs that
|
||||
* we'll forward to the socket unit.
|
||||
@@ -1317,8 +1334,7 @@ static int gather_pid_metadata_from_argv(
|
||||
argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
|
||||
|
||||
for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
|
||||
-
|
||||
- t = argv[i];
|
||||
+ const char *t = argv[i];
|
||||
|
||||
switch (i) {
|
||||
|
||||
@@ -1343,6 +1359,47 @@ static int gather_pid_metadata_from_argv(
|
||||
break;
|
||||
}
|
||||
|
||||
+ if (i == META_ARGV_PID) {
|
||||
+ /* Store this so that we can check whether the core will be forwarded to a container
|
||||
+ * even when the kernel doesn't provide a pidfd. Can be dropped once baseline is
|
||||
+ * >= v6.16. */
|
||||
+ r = pidref_set_pidstr(&local_pidref, t);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to initialize pidref from pid %s: %m", t);
|
||||
+ }
|
||||
+
|
||||
+ if (i == META_ARGV_PIDFD) {
|
||||
+ /* If the current kernel doesn't support the %F specifier (which resolves to a
|
||||
+ * pidfd), but we included it in the core_pattern expression, we'll receive an empty
|
||||
+ * string here. Deal with that gracefully. */
|
||||
+ if (isempty(t))
|
||||
+ continue;
|
||||
+
|
||||
+ assert(!pidref_is_set(&context->pidref));
|
||||
+ assert(kernel_fd < 0);
|
||||
+
|
||||
+ kernel_fd = parse_fd(t);
|
||||
+ if (kernel_fd < 0)
|
||||
+ return log_error_errno(kernel_fd, "Failed to parse pidfd \"%s\": %m", t);
|
||||
+
|
||||
+ r = pidref_set_pidfd(&context->pidref, kernel_fd);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to initialize pidref from pidfd %d: %m", kernel_fd);
|
||||
+
|
||||
+ /* If there are containers involved with different versions of the code they might
|
||||
+ * not be using pidfds, so it would be wrong to set the metadata, skip it. */
|
||||
+ r = in_same_namespace(getpid_cached(), context->pidref.pid, NAMESPACE_PID);
|
||||
+ if (r < 0)
|
||||
+ log_debug_errno(r, "Failed to check pidns of crashing process, ignoring: %m");
|
||||
+ if (r <= 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* We don't print the fd number in the journal as it's meaningless, but we still
|
||||
+ * record that the parsing was done with a kernel-provided fd as it means it's safe
|
||||
+ * from races, which is valuable information to provide in the journal record. */
|
||||
+ t = "1";
|
||||
+ }
|
||||
+
|
||||
r = iovw_put_string_field(iovw, meta_field_names[i], t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1350,7 +1407,19 @@ static int gather_pid_metadata_from_argv(
|
||||
|
||||
/* Cache some of the process metadata we collected so far and that we'll need to
|
||||
* access soon */
|
||||
- return save_context(context, iovw);
|
||||
+ r = save_context(context, iovw);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ /* If the kernel didn't give us a PIDFD, then use the one derived from the
|
||||
+ * PID immediately, given we have it. */
|
||||
+ if (!pidref_is_set(&context->pidref))
|
||||
+ context->pidref = TAKE_PIDREF(local_pidref);
|
||||
+
|
||||
+ /* Close the kernel-provided FD as the last thing after everything else succeeded. */
|
||||
+ kernel_fd = safe_close(kernel_fd);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
|
||||
@@ -1466,7 +1535,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
|
||||
}
|
||||
|
||||
static int process_kernel(int argc, char* argv[]) {
|
||||
- Context context = {};
|
||||
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
|
||||
struct iovec_wrapper *iovw;
|
||||
int r, mntns_fd = -EBADF;
|
||||
|
||||
@@ -1543,7 +1612,7 @@ static int process_kernel(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
static int process_backtrace(int argc, char *argv[]) {
|
||||
- Context context = {};
|
||||
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
|
||||
struct iovec_wrapper *iovw;
|
||||
char *message;
|
||||
int r;
|
||||
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
|
||||
index 9c10a89828..1c6230ad93 100644
|
||||
--- a/sysctl.d/50-coredump.conf.in
|
||||
+++ b/sysctl.d/50-coredump.conf.in
|
||||
@@ -13,7 +13,7 @@
|
||||
# the core dump.
|
||||
#
|
||||
# See systemd-coredump(8) and core(5).
|
||||
-kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
|
||||
+kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d %F
|
||||
|
||||
# Allow 16 coredumps to be dispatched in parallel by the kernel.
|
||||
# We collect metadata from /proc/%P/, and thus need to make sure the crashed
|
||||
24
systemd.spec
24
systemd.spec
@ -21,7 +21,7 @@
|
||||
Name: systemd
|
||||
Url: https://systemd.io
|
||||
Version: 252
|
||||
Release: 59%{?dist}
|
||||
Release: 60%{?dist}
|
||||
# For a breakdown of the licensing, see README
|
||||
License: LGPLv2+ and MIT and GPLv2+
|
||||
Summary: System and Service Manager
|
||||
@ -1356,6 +1356,16 @@ Patch1270: 1270-timer-don-t-run-service-immediately-after-restart-of.patch
|
||||
Patch1271: 1271-test-store-and-compare-just-the-property-value.patch
|
||||
Patch1272: 1272-test-make-test-fd-util-more-lenient-when-using-fd_mo.patch
|
||||
Patch1273: 1273-basic-add-PIDFS-magic-31709.patch
|
||||
Patch1274: 1274-man-fix-a-missing-word.patch
|
||||
Patch1275: 1275-cryptsetup-Add-optional-support-for-linking-volume-k.patch
|
||||
Patch1276: 1276-cryptsetup-fix-typo.patch
|
||||
Patch1277: 1277-cryptsetup-HAVE_CRYPT_SET_KEYRING_TO_LINK-is-always-.patch
|
||||
Patch1278: 1278-coredump-make-check-that-all-argv-meta-data-fields-a.patch
|
||||
Patch1279: 1279-coredump-restore-compatibility-with-older-patterns.patch
|
||||
Patch1280: 1280-coredump-use-d-in-kernel-core-pattern.patch
|
||||
Patch1281: 1281-pidref-add-structure-that-can-reference-a-pid-via-bo.patch
|
||||
Patch1282: 1282-fd-util-introduce-parse_fd.patch
|
||||
Patch1283: 1283-coredump-add-support-for-new-F-PIDFD-specifier.patch
|
||||
|
||||
# Downstream-only patches (9000–9999)
|
||||
|
||||
@ -2233,6 +2243,18 @@ systemd-hwdb update &>/dev/null || :
|
||||
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
|
||||
|
||||
%changelog
|
||||
* Wed Nov 05 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-60
|
||||
- man: fix a missing word (RHEL-115182)
|
||||
- cryptsetup: Add optional support for linking volume key in keyring. (RHEL-97175)
|
||||
- cryptsetup: fix typo (RHEL-97175)
|
||||
- cryptsetup: HAVE_CRYPT_SET_KEYRING_TO_LINK is always defined (RHEL-97175)
|
||||
- coredump: make check that all argv[] meta data fields are passed strict (RHEL-104138)
|
||||
- coredump: restore compatibility with older patterns (RHEL-104138)
|
||||
- coredump: use %d in kernel core pattern (RHEL-104138)
|
||||
- pidref: add structure that can reference a pid via both pidfd and pid_t (RHEL-104138)
|
||||
- fd-util: introduce parse_fd() (RHEL-104138)
|
||||
- coredump: add support for new %F PIDFD specifier (RHEL-104138)
|
||||
|
||||
* Thu Oct 02 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-59
|
||||
- test: rename TEST-53-ISSUE-16347 to TEST-53-TIMER (RHEL-118215)
|
||||
- test: restarting elapsed timer shouldn't trigger the corresponding service (RHEL-118215)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user