import UBI systemd-257-13.el10_1.3

This commit is contained in:
AlmaLinux RelEng Bot 2026-05-05 06:25:07 -04:00
parent b62a892a01
commit 965552652c
38 changed files with 2822 additions and 1 deletions

3
.abignore Normal file
View File

@ -0,0 +1,3 @@
[suppress_file]
# Those shared objects are private to systemd
file_name_regexp=libsystemd-(shared|core)-.*.so

View File

@ -0,0 +1,32 @@
From ae1394abcded51ed5e443d1124059b2e31748baa Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Fri, 11 Apr 2025 14:44:30 +0100
Subject: [PATCH] coredump: verify pidfd after parsing data in usermode helper
Ensure the pidfd is still valid before continuing
Follow-up for 313537da6ffdea4049873571202679734d49f0a1
(cherry picked from commit ba6c955f21ac3f46a6914c3607b910e371a25dee)
Related: RHEL-104135
---
src/coredump/coredump.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index d3a1f7c09d..db7f76f6c4 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1458,6 +1458,11 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *
if (get_process_environ(pid, &t) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
+ /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing */
+ r = pidref_verify(&context->pidref);
+ if (r < 0)
+ return log_error_errno(r, "PIDFD validation failed: %m");
+
/* we successfully acquired all metadata */
return context_parse_iovw(context, iovw);
}

View File

@ -0,0 +1,122 @@
From 942d050f98cc0b6c89dbe30157163a8610cf7f78 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-104135
---
src/coredump/coredump.c | 23 +++++++++++++++--------
test/units/TEST-74-AUX-UTILS.coredump.sh | 18 +++++++++++-------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index db7f76f6c4..58bcd4910f 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -105,8 +105,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
@@ -117,7 +121,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,
@@ -1046,7 +1050,7 @@ static int context_parse_iovw(Context *context, 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]);
@@ -1314,14 +1318,17 @@ static int gather_pid_metadata_from_argv(
assert(context);
/* 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++) {
_cleanup_free_ char *buf = NULL;
const char *t = argv[i];
diff --git a/test/units/TEST-74-AUX-UTILS.coredump.sh b/test/units/TEST-74-AUX-UTILS.coredump.sh
index 2c084f54d2..8173a23162 100755
--- a/test/units/TEST-74-AUX-UTILS.coredump.sh
+++ b/test/units/TEST-74-AUX-UTILS.coredump.sh
@@ -194,14 +194,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

View File

@ -0,0 +1,123 @@
From ad1453257d69a74bf8e47493394c601d733774de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 21 May 2025 22:33:50 +0200
Subject: [PATCH] coredump: wrap long lines, fix grammar in comments
(cherry picked from commit c673f1f67aa44f99be5fdcb0dc22d7599776e5ed)
Related: RHEL-104135
---
src/coredump/coredump.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 58bcd4910f..c96b59b2f5 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -95,9 +95,9 @@ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
enum {
/* We use these as array indexes for our process metadata cache.
*
- * The first indices of the cache stores the same metadata as the ones passed by
- * the kernel via argv[], ie the strings array passed by the kernel according to
- * our pattern defined in /proc/sys/kernel/core_pattern (see man:core(5)). */
+ * The first indices of the cache stores the same metadata as the ones passed by the kernel via
+ * argv[], i.e. the strings specified in our pattern defined in /proc/sys/kernel/core_pattern,
+ * see core(5). */
META_ARGV_PID, /* %P: as seen in the initial pid namespace */
META_ARGV_UID, /* %u: as seen in the initial user namespace */
@@ -274,7 +274,6 @@ static int fix_acl(int fd, uid_t uid, bool allow_user) {
}
static int fix_xattr(int fd, const Context *context) {
-
static const char * const xattrs[_META_MAX] = {
[META_ARGV_PID] = "user.coredump.pid",
[META_ARGV_UID] = "user.coredump.uid",
@@ -1032,9 +1031,9 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
bool have_signal_name = false;
FOREACH_ARRAY(iovec, iovw->iovec, iovw->count) {
for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
- /* Note that these strings are NUL terminated, because we made sure that a
+ /* 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 process_socket() and gather_pid_metadata_*()) */
+ * count (see process_socket() and gather_pid_metadata_*()). */
assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
const char *p = memory_startswith(iovec->iov_base, iovec->iov_len, meta_field_names[i]);
@@ -1049,10 +1048,11 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
memory_startswith(iovec->iov_base, iovec->iov_len, "COREDUMP_SIGNAL_NAME=");
}
- /* The basic fields from argv[] should always be there, refuse early if not */
+ /* The basic fields from argv[] should always be there, refuse early if not. */
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]);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "A required (%s) has not been sent, aborting.", meta_field_names[i]);
pid_t parsed_pid;
r = parse_pid(context->meta[META_ARGV_PID], &parsed_pid);
@@ -1060,7 +1060,8 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
if (pidref_is_set(&context->pidref)) {
if (context->pidref.pid != parsed_pid)
- return log_error_errno(r, "Passed PID " PID_FMT " does not match passed " PID_FMT ": %m", parsed_pid, context->pidref.pid);
+ return log_error_errno(r, "Passed PID " PID_FMT " does not match passed " PID_FMT ": %m",
+ parsed_pid, context->pidref.pid);
} else {
r = pidref_set_pid(&context->pidref, parsed_pid);
if (r < 0)
@@ -1158,7 +1159,8 @@ static int process_socket(int fd) {
* that's permissible for the final two fds. Hence let's be strict on the
* first fd, but lenient on the other two. */
- if (!cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1) && state != STATE_PAYLOAD) /* no fds, and already got the first fd → we are done */
+ if (!cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1) && state != STATE_PAYLOAD)
+ /* No fds, and already got the first fd → we are done. */
break;
cmsg_close_all(&mh);
@@ -1350,7 +1352,7 @@ 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 */
+ * access soon. */
return context_parse_iovw(context, iovw);
}
@@ -1465,12 +1467,12 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *
if (get_process_environ(pid, &t) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
- /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing */
+ /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing. */
r = pidref_verify(&context->pidref);
if (r < 0)
return log_error_errno(r, "PIDFD validation failed: %m");
- /* we successfully acquired all metadata */
+ /* We successfully acquired all metadata. */
return context_parse_iovw(context, iovw);
}
@@ -1826,12 +1828,12 @@ static int process_kernel(int argc, char* argv[]) {
log_warning_errno(r, "Failed to access the mount tree of a container, ignoring: %m");
}
- /* If this is PID 1 disable coredump collection, we'll unlikely be able to process
+ /* If this is PID 1, disable coredump collection, we'll unlikely be able to process
* it later on.
*
* FIXME: maybe we should disable coredumps generation from the beginning and
- * re-enable it only when we know it's either safe (ie we're not running OOM) or
- * it's not pid1 ? */
+ * re-enable it only when we know it's either safe (i.e. we're not running OOM) or
+ * it's not PID 1 ? */
if (context.is_pid1) {
log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
disable_coredumps();

View File

@ -0,0 +1,94 @@
From 6f678c43638caa6b0b349e56f0ded6d9c781a345 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 26 May 2025 12:04:44 +0200
Subject: [PATCH] coredump: get rid of _META_MANDATORY_MAX
No functional change. This change is done in preparation for future changes.
Currently, the list of fields which are received on the command line is a
strict subset of the fields which are always expected to be received on a
socket. But when we add new kernel args in the future, we'll have two
non-overlapping sets and this approach will not work. Get rid of the variable
and enumerate the required fields. This set will never change, so this is
actually more maintainable.
The message with the hint where to add new fields is switched with
_META_ARGV_MAX. The new order is more correct.
(cherry picked from commit 49f1f2d4a7612bbed5211a73d11d6a94fbe3bb69)
Related: RHEL-104135
---
src/coredump/coredump.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index c96b59b2f5..ac1e1cb9d3 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -92,7 +92,7 @@ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
#define MOUNT_TREE_ROOT "/run/systemd/mount-rootfs"
-enum {
+typedef enum {
/* We use these as array indexes for our process metadata cache.
*
* The first indices of the cache stores the same metadata as the ones passed by the kernel via
@@ -108,9 +108,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_MAX,
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
+ _META_ARGV_MAX,
/* 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
@@ -118,16 +118,15 @@ enum {
* environment. */
META_COMM = _META_ARGV_MAX,
- _META_MANDATORY_MAX,
/* The rest are similar to the previous ones except that we won't fail if one of
* them is missing in a message sent over the socket. */
- META_EXE = _META_MANDATORY_MAX,
+ META_EXE,
META_UNIT,
META_PROC_AUXV,
_META_MAX
-};
+} meta_argv_t;
static const char * const meta_field_names[_META_MAX] = {
[META_ARGV_PID] = "COREDUMP_PID=",
@@ -1224,10 +1223,24 @@ static int process_socket(int fd) {
if (r < 0)
return r;
- /* Make sure we received at least all fields we need. */
- for (int i = 0; i < _META_MANDATORY_MAX; i++)
+ /* Make sure we received all the expected fields. We support being called by an *older*
+ * systemd-coredump from the outside, so we require only the basic set of fields that
+ * was being sent when the support for sending to containers over a socket was added
+ * in a108c43e36d3ceb6e34efe37c014fc2cda856000. */
+ meta_argv_t i;
+ FOREACH_ARGUMENT(i,
+ META_ARGV_PID,
+ META_ARGV_UID,
+ META_ARGV_GID,
+ META_ARGV_SIGNAL,
+ META_ARGV_TIMESTAMP,
+ META_ARGV_RLIMIT,
+ META_ARGV_HOSTNAME,
+ META_COMM)
if (!context.meta[i])
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A mandatory argument (%i) has not been sent, aborting.", i);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Mandatory argument %s not received on socket, aborting.",
+ meta_field_names[i]);
return submit_coredump(&context, &iovw, input_fd);
}

View File

@ -0,0 +1,155 @@
From 0ade63d15214fa8e184cc87522bfac9533be441b 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>
(cherry picked from commit 0c49e0049b7665bb7769a13ef346fef92e1ad4d6)
Related: RHEL-104135
---
man/systemd-coredump.xml | 12 ++++++++++++
src/coredump/coredump.c | 21 ++++++++++++++++++---
sysctl.d/50-coredump.conf.in | 2 +-
test/units/TEST-74-AUX-UTILS.coredump.sh | 5 +++++
4 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 737b80de9a..0f5ccf12f9 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -292,6 +292,18 @@ 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>
+
+ <xi:include href="version-info.xml" xpointer="v258"/>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index ac1e1cb9d3..19d4d02437 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -108,6 +108,7 @@ typedef 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 */
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
_META_ARGV_MAX,
@@ -136,6 +137,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=",
@@ -146,6 +148,7 @@ typedef struct Context {
PidRef pidref;
uid_t uid;
gid_t gid;
+ unsigned dumpable;
int signo;
uint64_t rlimit;
bool is_pid1;
@@ -433,14 +436,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 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;
}
@@ -1083,6 +1088,16 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
if (r < 0)
log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", context->meta[META_ARGV_RLIMIT]);
+ /* 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 90c080bdfe..a550c87258 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=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
+kernel.core_pattern=|{{LIBEXECDIR}}/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/TEST-74-AUX-UTILS.coredump.sh b/test/units/TEST-74-AUX-UTILS.coredump.sh
index 8173a23162..f157f97443 100755
--- a/test/units/TEST-74-AUX-UTILS.coredump.sh
+++ b/test/units/TEST-74-AUX-UTILS.coredump.sh
@@ -201,12 +201,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

View File

@ -0,0 +1,52 @@
From 69d7d75a872d319b5fda048044238a735dce3834 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 5 May 2025 15:48:40 +0200
Subject: [PATCH] coredump: also stop forwarding non-dumpable processes
See the comment in the patch for details.
Suggested-by: Qualys Security Advisory <qsa@qualys.com>
(cherry picked from commit 8fc7b2a211eb13ef1a94250b28e1c79cab8bdcb9)
Related: RHEL-104135
---
src/coredump/coredump.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 19d4d02437..048eb53546 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1560,10 +1560,21 @@ static int receive_ucred(int transport_fd, struct ucred *ret_ucred) {
return 0;
}
-static int can_forward_coredump(pid_t pid) {
+static int can_forward_coredump(Context *context, pid_t pid) {
_cleanup_free_ char *cgroup = NULL, *path = NULL, *unit = NULL;
int r;
+ assert(context);
+
+ /* We don't use %F/pidfd to pin down the crashed process yet. We need to avoid a situation where the
+ * attacker crashes a SUID process or a root daemon and quickly replaces it with a namespaced process
+ * and we forward the initial part of the coredump to the attacker, inside the namespace.
+ *
+ * TODO: relax this check when %F is implemented and used.
+ */
+ if (context->dumpable != 1)
+ return false;
+
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return r;
@@ -1607,7 +1618,7 @@ static int forward_coredump_to_container(Context *context) {
if (r < 0)
return log_debug_errno(r, "Failed to get namespace leader: %m");
- r = can_forward_coredump(leader_pid);
+ r = can_forward_coredump(context, leader_pid);
if (r < 0)
return log_debug_errno(r, "Failed to check if coredump can be forwarded: %m");
if (r == 0)

View File

@ -0,0 +1,42 @@
From cee91ba610d7ae7b80d32e487c79ea10c8fb98bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 26 May 2025 15:24:04 +0200
Subject: [PATCH] coredump: get rid of a bogus assertion
The check looks plausible, but when I started checking whether it needs
to be lowered for the recent changes, I realized that it doesn't make
much sense.
context_parse_iovw() is called from a few places, e.g.:
- process_socket(), where the other side controls the contents of the
message. We already do other checks on the correctness of the message
and this assert is not needed.
- gather_pid_metadata_from_argv(), which is called after
inserting MESSAGE_ID= and PRIORITY= into the array, so there is no
direct relation between _META_ARGV_MAX and the number of args in the
iovw.
- gather_pid_metadata_from_procfs(), where we insert a bazillion fields,
but without any relation to _META_ARGV_MAX.
Since we already separately check if the required stuff was set, drop this
misleading check.
(cherry picked from commit 13902e025321242b1d95c6d8b4e482b37f58cdef)
Related: RHEL-104135
---
src/coredump/coredump.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 048eb53546..88cd1c394d 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1027,7 +1027,6 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
assert(context);
assert(iovw);
- assert(iovw->count >= _META_ARGV_MAX);
/* Converts the data in the iovec array iovw into separate fields. Fills in context->meta[] (for
* which no memory is allocated, it just contains direct pointers into the iovec array memory). */

View File

@ -0,0 +1,153 @@
From 46e24959ecb9390f61403925bb1569c57ca375df 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)
Related: RHEL-104135
---
man/systemd-coredump.xml | 11 +++++++
src/coredump/coredump.c | 60 ++++++++++++++++++++++++++++++++++--
sysctl.d/50-coredump.conf.in | 2 +-
3 files changed, 70 insertions(+), 3 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 0f5ccf12f9..185497125c 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -192,6 +192,17 @@ 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>
+
+ <xi:include href="version-info.xml" xpointer="v258"/>
+ </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 88cd1c394d..940eb44528 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -109,6 +109,7 @@ typedef 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 */
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
_META_ARGV_MAX,
@@ -138,6 +139,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=",
@@ -1341,7 +1343,8 @@ static int gather_pid_metadata_from_argv(
Context *context,
int argc, char **argv) {
- int r;
+ _cleanup_(pidref_done) PidRef local_pidref = PIDREF_NULL;
+ int r, kernel_fd = -EBADF;
assert(iovw);
assert(context);
@@ -1373,6 +1376,47 @@ static int gather_pid_metadata_from_argv(
t = buf;
}
+ 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(/* pid1 = */ 0, 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;
@@ -1380,7 +1424,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 context_parse_iovw(context, iovw);
+ r = context_parse_iovw(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_from_procfs(struct iovec_wrapper *iovw, Context *context) {
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
index a550c87258..fe8f7670b0 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=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
+kernel.core_pattern=|{{LIBEXECDIR}}/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

View File

@ -0,0 +1,53 @@
From 1a01ba0f895a8781908cfebfa1d74f326f6faacb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 May 2025 10:44:32 +0200
Subject: [PATCH] coredump: when %F/pidfd is used, again allow forwarding to
containers
(cherry picked from commit e6a8687b939ab21854f12f59a3cce703e32768cf)
Related: RHEL-104135
---
src/coredump/coredump.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 940eb44528..67abc20ec5 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -155,6 +155,7 @@ typedef struct Context {
uint64_t rlimit;
bool is_pid1;
bool is_journald;
+ bool got_pidfd;
int mount_tree_fd;
/* These point into external memory, are not owned by this object */
@@ -1403,6 +1404,8 @@ static int gather_pid_metadata_from_argv(
if (r < 0)
return log_error_errno(r, "Failed to initialize pidref from pidfd %d: %m", kernel_fd);
+ context->got_pidfd = 1;
+
/* 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(/* pid1 = */ 0, context->pidref.pid, NAMESPACE_PID);
@@ -1621,13 +1624,11 @@ static int can_forward_coredump(Context *context, pid_t pid) {
assert(context);
- /* We don't use %F/pidfd to pin down the crashed process yet. We need to avoid a situation where the
- * attacker crashes a SUID process or a root daemon and quickly replaces it with a namespaced process
- * and we forward the initial part of the coredump to the attacker, inside the namespace.
- *
- * TODO: relax this check when %F is implemented and used.
- */
- if (context->dumpable != 1)
+ /* We need to avoid a situation where the attacker crashes a SUID process or a root daemon and
+ * quickly replaces it with a namespaced process and we forward the coredump to the attacker, into
+ * the namespace. With %F/pidfd we can reliably check the namespace of the original process, hence we
+ * can allow forwarding. */
+ if (!context->got_pidfd && context->dumpable != 1)
return false;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);

View File

@ -0,0 +1,82 @@
From 20b0f1e07885ffc887ac27f9dad164271b07581c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 27 May 2025 20:32:30 +0200
Subject: [PATCH] coredump: introduce an enum to wrap dumpable constants
Two constants are described in the man page, but are not defined by a header.
The third constant is described in the kernel docs. Use explicit values to
show that those are values are defined externally.
(cherry picked from commit 76e0ab49c47965877c19772a2b3bf55f6417ca39)
Related: RHEL-104135
---
src/coredump/coredump.c | 10 +++++-----
src/shared/coredump-util.h | 7 +++++++
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 67abc20ec5..7bde2f5196 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -442,7 +442,7 @@ static int grant_user_access(int core_fd, const Context *context) {
/* We allow access if 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 &&
+ context->dumpable == SUID_DUMP_USER &&
at_secure == 0 &&
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
@@ -1090,13 +1090,13 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
if (r < 0)
log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", context->meta[META_ARGV_RLIMIT]);
- /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2,
+ /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to SUID_DUMP_SAFE (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)
+ if (context->dumpable > SUID_DUMP_SAFE)
log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
}
@@ -1628,7 +1628,7 @@ static int can_forward_coredump(Context *context, pid_t pid) {
* quickly replaces it with a namespaced process and we forward the coredump to the attacker, into
* the namespace. With %F/pidfd we can reliably check the namespace of the original process, hence we
* can allow forwarding. */
- if (!context->got_pidfd && context->dumpable != 1)
+ if (!context->got_pidfd && context->dumpable != SUID_DUMP_USER)
return false;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
@@ -2016,7 +2016,7 @@ static int run(int argc, char *argv[]) {
log_set_target_and_open(LOG_TARGET_KMSG);
/* Make sure we never enter a loop */
- (void) prctl(PR_SET_DUMPABLE, 0);
+ (void) prctl(PR_SET_DUMPABLE, SUID_DUMP_DISABLE);
/* Ignore all parse errors */
(void) parse_config();
diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h
index 4f54bb94c0..73c74c98c7 100644
--- a/src/shared/coredump-util.h
+++ b/src/shared/coredump-util.h
@@ -25,6 +25,13 @@ typedef enum CoredumpFilter {
/* The kernel doesn't like UINT64_MAX and returns ERANGE, use UINT32_MAX to support future new flags */
#define COREDUMP_FILTER_MASK_ALL UINT32_MAX
+typedef enum SuidDumpMode {
+ SUID_DUMP_DISABLE = 0, /* PR_SET_DUMPABLE(2const) */
+ SUID_DUMP_USER = 1, /* PR_SET_DUMPABLE(2const) */
+ SUID_DUMP_SAFE = 2, /* https://www.kernel.org/doc/html/latest/admin-guide/sysctl/fs.html#suid-dumpable */
+ _SUID_DUMP_MODE_MAX,
+} SuidDumpMode;
+
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);

View File

@ -0,0 +1,115 @@
From 2271674c5776fa8308ad8d425e64246910366d2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 28 May 2025 18:31:13 +0200
Subject: [PATCH] Define helper to call PR_SET_DUMPABLE
(cherry picked from commit 9ce8e3e449def92c75ada41b7d10c5bc3946be77)
Related: RHEL-104135
---
src/coredump/coredump.c | 3 +--
src/shared/coredump-util.c | 7 +++++++
src/shared/coredump-util.h | 2 ++
src/shared/elf-util.c | 4 ++--
src/shared/tests.c | 1 +
5 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 7bde2f5196..caec4bb76c 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -3,7 +3,6 @@
#include <errno.h>
#include <stdio.h>
#include <sys/mount.h>
-#include <sys/prctl.h>
#include <sys/statvfs.h>
#include <sys/auxv.h>
#include <sys/xattr.h>
@@ -2016,7 +2015,7 @@ static int run(int argc, char *argv[]) {
log_set_target_and_open(LOG_TARGET_KMSG);
/* Make sure we never enter a loop */
- (void) prctl(PR_SET_DUMPABLE, SUID_DUMP_DISABLE);
+ (void) set_dumpable(SUID_DUMP_DISABLE);
/* Ignore all parse errors */
(void) parse_config();
diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c
index 805503f366..0050e133c4 100644
--- a/src/shared/coredump-util.c
+++ b/src/shared/coredump-util.c
@@ -1,14 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <elf.h>
+#include <sys/prctl.h>
#include "coredump-util.h"
+#include "errno-util.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-table.h"
#include "unaligned.h"
#include "virt.h"
+int set_dumpable(SuidDumpMode mode) {
+ /* Cast mode explicitly to long, because prctl wants longs but is varargs. */
+ return RET_NERRNO(prctl(PR_SET_DUMPABLE, (long) mode));
+}
+
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
[COREDUMP_FILTER_PRIVATE_ANONYMOUS] = "private-anonymous",
[COREDUMP_FILTER_SHARED_ANONYMOUS] = "shared-anonymous",
diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h
index 73c74c98c7..b18cb33c84 100644
--- a/src/shared/coredump-util.h
+++ b/src/shared/coredump-util.h
@@ -32,6 +32,8 @@ typedef enum SuidDumpMode {
_SUID_DUMP_MODE_MAX,
} SuidDumpMode;
+int set_dumpable(SuidDumpMode mode);
+
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
index a3ff1fd3fb..ff8818de27 100644
--- a/src/shared/elf-util.c
+++ b/src/shared/elf-util.c
@@ -6,12 +6,12 @@
#include <elfutils/libdwelf.h>
#include <elfutils/libdwfl.h>
#include <libelf.h>
-#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
+#include "coredump-util.h"
#include "dlfcn-util.h"
#include "elf-util.h"
#include "errno-util.h"
@@ -825,7 +825,7 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
if (r == 0) {
/* We want to avoid loops, given this can be called from systemd-coredump */
if (fork_disable_dump) {
- r = RET_NERRNO(prctl(PR_SET_DUMPABLE, 0));
+ r = set_dumpable(SUID_DUMP_DISABLE);
if (r < 0)
report_errno_and_exit(error_pipe[1], r);
}
diff --git a/src/shared/tests.c b/src/shared/tests.c
index 50b30ca17d..88031e90d9 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -16,6 +16,7 @@
#include "bus-wait-for-jobs.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
+#include "coredump-util.h"
#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"

View File

@ -0,0 +1,25 @@
From 35d4cb60dcfbb65359708a98c3474a8b3827f4a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 6 Jun 2025 17:03:46 +0200
Subject: [PATCH] coredump: fix 0-passed-as-pointer warning
(cherry picked from commit 8ec2e177b01339ee940efd323361971acf027cc9)
Related: RHEL-104135
---
src/coredump/coredump.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index caec4bb76c..412411bff7 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -217,7 +217,7 @@ static int parse_config(void) {
#if HAVE_DWFL_SET_SYSROOT
{ "Coredump", "EnterNamespace", config_parse_bool, 0, &arg_enter_namespace },
#else
- { "Coredump", "EnterNamespace", config_parse_warn_compat, DISABLED_CONFIGURATION, 0 },
+ { "Coredump", "EnterNamespace", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
#endif
{}
};

View File

@ -0,0 +1,25 @@
From 40d1437d8aab83c50018decac472608b91f53e49 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: fix 0-passed-as-pointer warning"
This reverts commit 35d4cb60dcfbb65359708a98c3474a8b3827f4a0.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 412411bff7..caec4bb76c 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -217,7 +217,7 @@ static int parse_config(void) {
#if HAVE_DWFL_SET_SYSROOT
{ "Coredump", "EnterNamespace", config_parse_bool, 0, &arg_enter_namespace },
#else
- { "Coredump", "EnterNamespace", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
+ { "Coredump", "EnterNamespace", config_parse_warn_compat, DISABLED_CONFIGURATION, 0 },
#endif
{}
};

View File

@ -0,0 +1,115 @@
From e6fad9f1bcdf98fe8636b1f41da55afd75a0832d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "Define helper to call PR_SET_DUMPABLE"
This reverts commit 2271674c5776fa8308ad8d425e64246910366d2f.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 3 ++-
src/shared/coredump-util.c | 7 -------
src/shared/coredump-util.h | 2 --
src/shared/elf-util.c | 4 ++--
src/shared/tests.c | 1 -
5 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index caec4bb76c..7bde2f5196 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -3,6 +3,7 @@
#include <errno.h>
#include <stdio.h>
#include <sys/mount.h>
+#include <sys/prctl.h>
#include <sys/statvfs.h>
#include <sys/auxv.h>
#include <sys/xattr.h>
@@ -2015,7 +2016,7 @@ static int run(int argc, char *argv[]) {
log_set_target_and_open(LOG_TARGET_KMSG);
/* Make sure we never enter a loop */
- (void) set_dumpable(SUID_DUMP_DISABLE);
+ (void) prctl(PR_SET_DUMPABLE, SUID_DUMP_DISABLE);
/* Ignore all parse errors */
(void) parse_config();
diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c
index 0050e133c4..805503f366 100644
--- a/src/shared/coredump-util.c
+++ b/src/shared/coredump-util.c
@@ -1,21 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <elf.h>
-#include <sys/prctl.h>
#include "coredump-util.h"
-#include "errno-util.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-table.h"
#include "unaligned.h"
#include "virt.h"
-int set_dumpable(SuidDumpMode mode) {
- /* Cast mode explicitly to long, because prctl wants longs but is varargs. */
- return RET_NERRNO(prctl(PR_SET_DUMPABLE, (long) mode));
-}
-
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
[COREDUMP_FILTER_PRIVATE_ANONYMOUS] = "private-anonymous",
[COREDUMP_FILTER_SHARED_ANONYMOUS] = "shared-anonymous",
diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h
index b18cb33c84..73c74c98c7 100644
--- a/src/shared/coredump-util.h
+++ b/src/shared/coredump-util.h
@@ -32,8 +32,6 @@ typedef enum SuidDumpMode {
_SUID_DUMP_MODE_MAX,
} SuidDumpMode;
-int set_dumpable(SuidDumpMode mode);
-
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
index ff8818de27..a3ff1fd3fb 100644
--- a/src/shared/elf-util.c
+++ b/src/shared/elf-util.c
@@ -6,12 +6,12 @@
#include <elfutils/libdwelf.h>
#include <elfutils/libdwfl.h>
#include <libelf.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
-#include "coredump-util.h"
#include "dlfcn-util.h"
#include "elf-util.h"
#include "errno-util.h"
@@ -825,7 +825,7 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
if (r == 0) {
/* We want to avoid loops, given this can be called from systemd-coredump */
if (fork_disable_dump) {
- r = set_dumpable(SUID_DUMP_DISABLE);
+ r = RET_NERRNO(prctl(PR_SET_DUMPABLE, 0));
if (r < 0)
report_errno_and_exit(error_pipe[1], r);
}
diff --git a/src/shared/tests.c b/src/shared/tests.c
index 88031e90d9..50b30ca17d 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -16,7 +16,6 @@
#include "bus-wait-for-jobs.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
-#include "coredump-util.h"
#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"

View File

@ -0,0 +1,79 @@
From b00298da67577bd432df17ab640ab36b37e03d74 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: introduce an enum to wrap dumpable
constants"
This reverts commit 20b0f1e07885ffc887ac27f9dad164271b07581c.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 10 +++++-----
src/shared/coredump-util.h | 7 -------
2 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 7bde2f5196..67abc20ec5 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -442,7 +442,7 @@ static int grant_user_access(int core_fd, const Context *context) {
/* We allow access if 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 == SUID_DUMP_USER &&
+ context->dumpable == 1 &&
at_secure == 0 &&
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
@@ -1090,13 +1090,13 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
if (r < 0)
log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", context->meta[META_ARGV_RLIMIT]);
- /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to SUID_DUMP_SAFE (2),
+ /* 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 > SUID_DUMP_SAFE)
+ if (context->dumpable > 2)
log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
}
@@ -1628,7 +1628,7 @@ static int can_forward_coredump(Context *context, pid_t pid) {
* quickly replaces it with a namespaced process and we forward the coredump to the attacker, into
* the namespace. With %F/pidfd we can reliably check the namespace of the original process, hence we
* can allow forwarding. */
- if (!context->got_pidfd && context->dumpable != SUID_DUMP_USER)
+ if (!context->got_pidfd && context->dumpable != 1)
return false;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
@@ -2016,7 +2016,7 @@ static int run(int argc, char *argv[]) {
log_set_target_and_open(LOG_TARGET_KMSG);
/* Make sure we never enter a loop */
- (void) prctl(PR_SET_DUMPABLE, SUID_DUMP_DISABLE);
+ (void) prctl(PR_SET_DUMPABLE, 0);
/* Ignore all parse errors */
(void) parse_config();
diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h
index 73c74c98c7..4f54bb94c0 100644
--- a/src/shared/coredump-util.h
+++ b/src/shared/coredump-util.h
@@ -25,13 +25,6 @@ typedef enum CoredumpFilter {
/* The kernel doesn't like UINT64_MAX and returns ERANGE, use UINT32_MAX to support future new flags */
#define COREDUMP_FILTER_MASK_ALL UINT32_MAX
-typedef enum SuidDumpMode {
- SUID_DUMP_DISABLE = 0, /* PR_SET_DUMPABLE(2const) */
- SUID_DUMP_USER = 1, /* PR_SET_DUMPABLE(2const) */
- SUID_DUMP_SAFE = 2, /* https://www.kernel.org/doc/html/latest/admin-guide/sysctl/fs.html#suid-dumpable */
- _SUID_DUMP_MODE_MAX,
-} SuidDumpMode;
-
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);

View File

@ -0,0 +1,53 @@
From dd0b6f16a367e8b1e5fb97233fb1c2099d0c4629 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: when %F/pidfd is used, again allow
forwarding to containers"
This reverts commit 1a01ba0f895a8781908cfebfa1d74f326f6faacb.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 67abc20ec5..940eb44528 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -155,7 +155,6 @@ typedef struct Context {
uint64_t rlimit;
bool is_pid1;
bool is_journald;
- bool got_pidfd;
int mount_tree_fd;
/* These point into external memory, are not owned by this object */
@@ -1404,8 +1403,6 @@ static int gather_pid_metadata_from_argv(
if (r < 0)
return log_error_errno(r, "Failed to initialize pidref from pidfd %d: %m", kernel_fd);
- context->got_pidfd = 1;
-
/* 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(/* pid1 = */ 0, context->pidref.pid, NAMESPACE_PID);
@@ -1624,11 +1621,13 @@ static int can_forward_coredump(Context *context, pid_t pid) {
assert(context);
- /* We need to avoid a situation where the attacker crashes a SUID process or a root daemon and
- * quickly replaces it with a namespaced process and we forward the coredump to the attacker, into
- * the namespace. With %F/pidfd we can reliably check the namespace of the original process, hence we
- * can allow forwarding. */
- if (!context->got_pidfd && context->dumpable != 1)
+ /* We don't use %F/pidfd to pin down the crashed process yet. We need to avoid a situation where the
+ * attacker crashes a SUID process or a root daemon and quickly replaces it with a namespaced process
+ * and we forward the initial part of the coredump to the attacker, inside the namespace.
+ *
+ * TODO: relax this check when %F is implemented and used.
+ */
+ if (context->dumpable != 1)
return false;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);

View File

@ -0,0 +1,148 @@
From 8655b93872dc5d5468042164e71c117813a680e8 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: add support for new %F PIDFD specifier"
This reverts commit 46e24959ecb9390f61403925bb1569c57ca375df.
Reverts: RHEL-104135
---
man/systemd-coredump.xml | 11 -------
src/coredump/coredump.c | 60 ++----------------------------------
sysctl.d/50-coredump.conf.in | 2 +-
3 files changed, 3 insertions(+), 70 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 185497125c..0f5ccf12f9 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -192,17 +192,6 @@ 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>
-
- <xi:include href="version-info.xml" xpointer="v258"/>
- </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 940eb44528..88cd1c394d 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -109,7 +109,6 @@ typedef 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 */
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
_META_ARGV_MAX,
@@ -139,7 +138,6 @@ 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=",
@@ -1343,8 +1341,7 @@ static int gather_pid_metadata_from_argv(
Context *context,
int argc, char **argv) {
- _cleanup_(pidref_done) PidRef local_pidref = PIDREF_NULL;
- int r, kernel_fd = -EBADF;
+ int r;
assert(iovw);
assert(context);
@@ -1376,47 +1373,6 @@ static int gather_pid_metadata_from_argv(
t = buf;
}
- 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(/* pid1 = */ 0, 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;
@@ -1424,19 +1380,7 @@ 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. */
- r = context_parse_iovw(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;
+ return context_parse_iovw(context, iovw);
}
static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *context) {
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
index fe8f7670b0..a550c87258 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=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d %F
+kernel.core_pattern=|{{LIBEXECDIR}}/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

View File

@ -0,0 +1,24 @@
From 41f7b831986b1eda992ea40081ec9d7fe6157e41 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: get rid of a bogus assertion"
This reverts commit cee91ba610d7ae7b80d32e487c79ea10c8fb98bc.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 88cd1c394d..048eb53546 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1027,6 +1027,7 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
assert(context);
assert(iovw);
+ assert(iovw->count >= _META_ARGV_MAX);
/* Converts the data in the iovec array iovw into separate fields. Fills in context->meta[] (for
* which no memory is allocated, it just contains direct pointers into the iovec array memory). */

View File

@ -0,0 +1,49 @@
From 5281235691ff5b64702d9cfb3f704fd069c6169d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: also stop forwarding non-dumpable
processes"
This reverts commit 69d7d75a872d319b5fda048044238a735dce3834.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 048eb53546..19d4d02437 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1560,21 +1560,10 @@ static int receive_ucred(int transport_fd, struct ucred *ret_ucred) {
return 0;
}
-static int can_forward_coredump(Context *context, pid_t pid) {
+static int can_forward_coredump(pid_t pid) {
_cleanup_free_ char *cgroup = NULL, *path = NULL, *unit = NULL;
int r;
- assert(context);
-
- /* We don't use %F/pidfd to pin down the crashed process yet. We need to avoid a situation where the
- * attacker crashes a SUID process or a root daemon and quickly replaces it with a namespaced process
- * and we forward the initial part of the coredump to the attacker, inside the namespace.
- *
- * TODO: relax this check when %F is implemented and used.
- */
- if (context->dumpable != 1)
- return false;
-
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return r;
@@ -1618,7 +1607,7 @@ static int forward_coredump_to_container(Context *context) {
if (r < 0)
return log_debug_errno(r, "Failed to get namespace leader: %m");
- r = can_forward_coredump(context, leader_pid);
+ r = can_forward_coredump(leader_pid);
if (r < 0)
return log_debug_errno(r, "Failed to check if coredump can be forwarded: %m");
if (r == 0)

View File

@ -0,0 +1,138 @@
From cfb8f2d6b759ae93827908afccc18b2b8c3ccc4b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: use %d in kernel core pattern"
This reverts commit 0ade63d15214fa8e184cc87522bfac9533be441b.
Reverts: RHEL-104135
---
man/systemd-coredump.xml | 12 ------------
src/coredump/coredump.c | 21 +++------------------
sysctl.d/50-coredump.conf.in | 2 +-
test/units/TEST-74-AUX-UTILS.coredump.sh | 5 -----
4 files changed, 4 insertions(+), 36 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 0f5ccf12f9..737b80de9a 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -292,18 +292,6 @@ 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>
-
- <xi:include href="version-info.xml" xpointer="v258"/>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 19d4d02437..ac1e1cb9d3 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -108,7 +108,6 @@ typedef 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 */
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
_META_ARGV_MAX,
@@ -137,7 +136,6 @@ 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=",
@@ -148,7 +146,6 @@ typedef struct Context {
PidRef pidref;
uid_t uid;
gid_t gid;
- unsigned dumpable;
int signo;
uint64_t rlimit;
bool is_pid1;
@@ -436,16 +433,14 @@ static int grant_user_access(int core_fd, const Context *context) {
if (r < 0)
return r;
- /* We allow access if 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. */
+ /* We allow access if we got all the data and at_secure is not set and
+ * the uid/gid matches 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 (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
+ log_debug("Will %s access (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;
}
@@ -1088,16 +1083,6 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
if (r < 0)
log_warning_errno(r, "Failed to parse resource limit \"%s\", ignoring: %m", context->meta[META_ARGV_RLIMIT]);
- /* 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 a550c87258..90c080bdfe 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=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
+kernel.core_pattern=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
# 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/TEST-74-AUX-UTILS.coredump.sh b/test/units/TEST-74-AUX-UTILS.coredump.sh
index f157f97443..8173a23162 100755
--- a/test/units/TEST-74-AUX-UTILS.coredump.sh
+++ b/test/units/TEST-74-AUX-UTILS.coredump.sh
@@ -201,17 +201,12 @@ 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

View File

@ -0,0 +1,83 @@
From 52ec2f34b8313eab2dd6a0eeadec2720d43fa3f1 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: get rid of _META_MANDATORY_MAX"
This reverts commit 6f678c43638caa6b0b349e56f0ded6d9c781a345.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index ac1e1cb9d3..c96b59b2f5 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -92,7 +92,7 @@ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
#define MOUNT_TREE_ROOT "/run/systemd/mount-rootfs"
-typedef enum {
+enum {
/* We use these as array indexes for our process metadata cache.
*
* The first indices of the cache stores the same metadata as the ones passed by the kernel via
@@ -108,9 +108,9 @@ typedef 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_MAX,
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
- _META_ARGV_MAX,
/* 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
@@ -118,15 +118,16 @@ typedef enum {
* environment. */
META_COMM = _META_ARGV_MAX,
+ _META_MANDATORY_MAX,
/* The rest are similar to the previous ones except that we won't fail if one of
* them is missing in a message sent over the socket. */
- META_EXE,
+ META_EXE = _META_MANDATORY_MAX,
META_UNIT,
META_PROC_AUXV,
_META_MAX
-} meta_argv_t;
+};
static const char * const meta_field_names[_META_MAX] = {
[META_ARGV_PID] = "COREDUMP_PID=",
@@ -1223,24 +1224,10 @@ static int process_socket(int fd) {
if (r < 0)
return r;
- /* Make sure we received all the expected fields. We support being called by an *older*
- * systemd-coredump from the outside, so we require only the basic set of fields that
- * was being sent when the support for sending to containers over a socket was added
- * in a108c43e36d3ceb6e34efe37c014fc2cda856000. */
- meta_argv_t i;
- FOREACH_ARGUMENT(i,
- META_ARGV_PID,
- META_ARGV_UID,
- META_ARGV_GID,
- META_ARGV_SIGNAL,
- META_ARGV_TIMESTAMP,
- META_ARGV_RLIMIT,
- META_ARGV_HOSTNAME,
- META_COMM)
+ /* Make sure we received at least all fields we need. */
+ for (int i = 0; i < _META_MANDATORY_MAX; i++)
if (!context.meta[i])
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Mandatory argument %s not received on socket, aborting.",
- meta_field_names[i]);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A mandatory argument (%i) has not been sent, aborting.", i);
return submit_coredump(&context, &iovw, input_fd);
}

View File

@ -0,0 +1,123 @@
From 6474cfc2bd0274be6ee9de8cd8cebeee49e3073d Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: wrap long lines, fix grammar in comments"
This reverts commit ad1453257d69a74bf8e47493394c601d733774de.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index c96b59b2f5..58bcd4910f 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -95,9 +95,9 @@ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
enum {
/* We use these as array indexes for our process metadata cache.
*
- * The first indices of the cache stores the same metadata as the ones passed by the kernel via
- * argv[], i.e. the strings specified in our pattern defined in /proc/sys/kernel/core_pattern,
- * see core(5). */
+ * The first indices of the cache stores the same metadata as the ones passed by
+ * the kernel via argv[], ie the strings array passed by the kernel according to
+ * our pattern defined in /proc/sys/kernel/core_pattern (see man:core(5)). */
META_ARGV_PID, /* %P: as seen in the initial pid namespace */
META_ARGV_UID, /* %u: as seen in the initial user namespace */
@@ -274,6 +274,7 @@ static int fix_acl(int fd, uid_t uid, bool allow_user) {
}
static int fix_xattr(int fd, const Context *context) {
+
static const char * const xattrs[_META_MAX] = {
[META_ARGV_PID] = "user.coredump.pid",
[META_ARGV_UID] = "user.coredump.uid",
@@ -1031,9 +1032,9 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
bool have_signal_name = false;
FOREACH_ARRAY(iovec, iovw->iovec, iovw->count) {
for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
- /* Note that these strings are NUL-terminated, because we made sure that a
+ /* 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 process_socket() and gather_pid_metadata_*()). */
+ * count (see process_socket() and gather_pid_metadata_*()) */
assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
const char *p = memory_startswith(iovec->iov_base, iovec->iov_len, meta_field_names[i]);
@@ -1048,11 +1049,10 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
memory_startswith(iovec->iov_base, iovec->iov_len, "COREDUMP_SIGNAL_NAME=");
}
- /* The basic fields from argv[] should always be there, refuse early if not. */
+ /* The basic fields from argv[] should always be there, refuse early if not */
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]);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A required (%s) has not been sent, aborting.", meta_field_names[i]);
pid_t parsed_pid;
r = parse_pid(context->meta[META_ARGV_PID], &parsed_pid);
@@ -1060,8 +1060,7 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
if (pidref_is_set(&context->pidref)) {
if (context->pidref.pid != parsed_pid)
- return log_error_errno(r, "Passed PID " PID_FMT " does not match passed " PID_FMT ": %m",
- parsed_pid, context->pidref.pid);
+ return log_error_errno(r, "Passed PID " PID_FMT " does not match passed " PID_FMT ": %m", parsed_pid, context->pidref.pid);
} else {
r = pidref_set_pid(&context->pidref, parsed_pid);
if (r < 0)
@@ -1159,8 +1158,7 @@ static int process_socket(int fd) {
* that's permissible for the final two fds. Hence let's be strict on the
* first fd, but lenient on the other two. */
- if (!cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1) && state != STATE_PAYLOAD)
- /* No fds, and already got the first fd → we are done. */
+ if (!cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1) && state != STATE_PAYLOAD) /* no fds, and already got the first fd → we are done */
break;
cmsg_close_all(&mh);
@@ -1352,7 +1350,7 @@ 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. */
+ * access soon */
return context_parse_iovw(context, iovw);
}
@@ -1467,12 +1465,12 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *
if (get_process_environ(pid, &t) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
- /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing. */
+ /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing */
r = pidref_verify(&context->pidref);
if (r < 0)
return log_error_errno(r, "PIDFD validation failed: %m");
- /* We successfully acquired all metadata. */
+ /* we successfully acquired all metadata */
return context_parse_iovw(context, iovw);
}
@@ -1828,12 +1826,12 @@ static int process_kernel(int argc, char* argv[]) {
log_warning_errno(r, "Failed to access the mount tree of a container, ignoring: %m");
}
- /* If this is PID 1, disable coredump collection, we'll unlikely be able to process
+ /* If this is PID 1 disable coredump collection, we'll unlikely be able to process
* it later on.
*
* FIXME: maybe we should disable coredumps generation from the beginning and
- * re-enable it only when we know it's either safe (i.e. we're not running OOM) or
- * it's not PID 1 ? */
+ * re-enable it only when we know it's either safe (ie we're not running OOM) or
+ * it's not pid1 ? */
if (context.is_pid1) {
log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
disable_coredumps();

View File

@ -0,0 +1,102 @@
From 1e9bb0d1a4a8c4fba9bb2f9a4282c4f71a8475b7 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: restore compatibility with older patterns"
This reverts commit 942d050f98cc0b6c89dbe30157163a8610cf7f78.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 23 ++++++++---------------
test/units/TEST-74-AUX-UTILS.coredump.sh | 18 +++++++-----------
2 files changed, 15 insertions(+), 26 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 58bcd4910f..db7f76f6c4 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -105,12 +105,8 @@ 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_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_HOSTNAME, /* %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
@@ -121,7 +117,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 in a message sent over the socket. */
+ * them is missing. */
META_EXE = _META_MANDATORY_MAX,
META_UNIT,
@@ -1050,7 +1046,7 @@ static int context_parse_iovw(Context *context, struct iovec_wrapper *iovw) {
}
/* The basic fields from argv[] should always be there, refuse early if not */
- for (int i = 0; i < _META_ARGV_REQUIRED; i++)
+ 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]);
@@ -1318,17 +1314,14 @@ static int gather_pid_metadata_from_argv(
assert(context);
/* We gather all metadata that were passed via argv[] into an array of iovecs that
- * 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. */
+ * we'll forward to the socket unit */
- if (argc < _META_ARGV_REQUIRED)
+ if (argc < _META_ARGV_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
- argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
+ "Not enough arguments passed by the kernel (%i, expected %i).",
+ argc, _META_ARGV_MAX);
- for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
+ for (int i = 0; i < _META_ARGV_MAX; i++) {
_cleanup_free_ char *buf = NULL;
const char *t = argv[i];
diff --git a/test/units/TEST-74-AUX-UTILS.coredump.sh b/test/units/TEST-74-AUX-UTILS.coredump.sh
index 8173a23162..2c084f54d2 100755
--- a/test/units/TEST-74-AUX-UTILS.coredump.sh
+++ b/test/units/TEST-74-AUX-UTILS.coredump.sh
@@ -194,18 +194,14 @@ rm -f /tmp/core.{output,redirected}
(! "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_BIN" >/dev/null)
# --backtrace mode
-# Pass one of the existing journal coredump records to systemd-coredump.
-# Use our PID as the source to be able to create a PIDFD and to make matching easier.
-# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT [HOSTNAME]
+# Pass one of the existing journal coredump records to systemd-coredump and
+# use our PID as the source to make matching the coredump later easier
+# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT HOSTNAME
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
- /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 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
+ /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 "$$"
coredumpctl info COREDUMP_HOSTNAME="mymachine"
# This used to cause a stack overflow

View File

@ -0,0 +1,29 @@
From 38b2ad72c1926c45790e678ce8c6207b3a93b2e5 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 13 Jan 2026 17:45:45 +0100
Subject: [PATCH] Revert "coredump: verify pidfd after parsing data in usermode
helper"
This reverts commit ae1394abcded51ed5e443d1124059b2e31748baa.
Reverts: RHEL-104135
---
src/coredump/coredump.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index db7f76f6c4..d3a1f7c09d 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1458,11 +1458,6 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *
if (get_process_environ(pid, &t) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
- /* Now that we have parsed info from /proc/ ensure the pidfd is still valid before continuing */
- r = pidref_verify(&context->pidref);
- if (r < 0)
- return log_error_errno(r, "PIDFD validation failed: %m");
-
/* we successfully acquired all metadata */
return context_parse_iovw(context, iovw);
}

View File

@ -0,0 +1,89 @@
From 2307a76cb78af02167bef314906f9ad0f9f9d339 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Fri, 17 Oct 2025 14:00:23 +0100
Subject: [PATCH] ci: re-enable bpf-framework option for build and unit test
jobs
Use the same trickery we do in the package build and search for
the actual bpftool binary. For the CI job any one we find is
good enough.
When we switch all jobs to 26.04 we can drop all of this.
This reverts commit cc814110af7a453db898ea2990a0281616d5ceff.
(cherry picked from commit 3b11139c0db9dd0a37b0493a8d2ad5f531a92344)
Related: RHEL-155394
---
.github/workflows/build_test.sh | 12 ++++++++++++
.github/workflows/unit_tests.sh | 13 +++++++++++++
2 files changed, 25 insertions(+)
diff --git a/.github/workflows/build_test.sh b/.github/workflows/build_test.sh
index 113af704a8..462203be9a 100755
--- a/.github/workflows/build_test.sh
+++ b/.github/workflows/build_test.sh
@@ -47,6 +47,7 @@ PACKAGES=(
libxkbcommon-dev
libxtables-dev
libzstd-dev
+ linux-tools-generic
mold
mount
net-tools
@@ -131,6 +132,17 @@ sudo apt-get -y install "${PACKAGES[@]}"
pip3 install --user -r .github/workflows/requirements.txt --require-hashes --break-system-packages
export PATH="$HOME/.local/bin:$PATH"
+# TODO: drop after we switch to ubuntu 26.04
+bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
+if [ -n "$bpftool_dir" ]; then
+ export PATH="$bpftool_dir:$PATH"
+fi
+
+if [[ -n "$CUSTOM_PYTHON" ]]; then
+ # If CUSTOM_PYTHON is set we need to pull jinja2 from pip, as a local interpreter is used
+ pip3 install --user --break-system-packages jinja2
+fi
+
$CC --version
meson --version
ninja --version
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
index 168bcc55c3..3acaf75417 100755
--- a/.github/workflows/unit_tests.sh
+++ b/.github/workflows/unit_tests.sh
@@ -18,6 +18,7 @@ ADDITIONAL_DEPS=(
libtss2-dev
libxkbcommon-dev
libzstd-dev
+ linux-tools-generic
python3-libevdev
python3-pefile
python3-pyelftools
@@ -70,6 +71,12 @@ for phase in "${PHASES[@]}"; do
capsh --drop=all -- -c "stat $PWD/meson.build"
;;
RUN|RUN_GCC|RUN_CLANG|RUN_CLANG_RELEASE)
+ # TODO: drop after we switch to ubuntu 26.04
+ bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
+ if [ -n "$bpftool_dir" ]; then
+ export PATH="$bpftool_dir:$PATH"
+ fi
+
if [[ "$phase" =~ ^RUN_CLANG ]]; then
export CC=clang
export CXX=clang++
@@ -94,6 +101,12 @@ for phase in "${PHASES[@]}"; do
TZ=GMT+12 meson test -C build --print-errorlogs
;;
RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN_NO_DEPS)
+ # TODO: drop after we switch to ubuntu 26.04
+ bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
+ if [ -n "$bpftool_dir" ]; then
+ export PATH="$bpftool_dir:$PATH"
+ fi
+
MESON_ARGS=(--optimization=1)
if [[ "$phase" =~ ^RUN_CLANG_ASAN_UBSAN ]]; then

View File

@ -0,0 +1,32 @@
From 5cb269a74ace5da67a9065ae1520c5420858bf9d Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Fri, 17 Oct 2025 15:39:09 +0100
Subject: [PATCH] ci: add bpftool workaround to codeql job too
(cherry picked from commit e9fd2bbfffc5c2c7cd1ea0a288d5435fc15e387f)
Related: RHEL-155394
---
.github/workflows/codeql.yml | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 51034783ca..443221fa11 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -44,7 +44,14 @@ jobs:
languages: ${{ matrix.language }}
config-file: ./.github/codeql-config.yml
- - run: sudo -E .github/workflows/unit_tests.sh SETUP
+ - run: |
+ sudo -E .github/workflows/unit_tests.sh SETUP
+ # TODO: drop after we switch to ubuntu 26.04
+ bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
+ if [ -n "$bpftool_binary" ]; then
+ sudo rm -f /usr/bin/bpftool
+ sudo ln -s "$bpftool_binary" /usr/bin/
+ fi
- name: Autobuild
uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88

View File

@ -0,0 +1,27 @@
From 633ed4d425167afe0bf692d47c7767085247d871 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sat, 18 Oct 2025 10:39:13 +0900
Subject: [PATCH] ci: fix workaround about bpftool for codeql
Follow-up for e9fd2bbfffc5c2c7cd1ea0a288d5435fc15e387f.
(cherry picked from commit a6836cfa0bdf1bb1fcf05686c5af3f2b5ad97f6b)
Related: RHEL-155394
---
.github/workflows/codeql.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 443221fa11..cfe54d59ac 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -49,7 +49,7 @@ jobs:
# TODO: drop after we switch to ubuntu 26.04
bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
if [ -n "$bpftool_binary" ]; then
- sudo rm -f /usr/bin/bpftool
+ sudo rm -f /usr/{bin,sbin}/bpftool
sudo ln -s "$bpftool_binary" /usr/bin/
fi

View File

@ -0,0 +1,31 @@
From 71097b7dc72abeaca5cb8389c0f7384521835eef Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Sat, 18 Oct 2025 14:23:59 +0100
Subject: [PATCH] ci: add bpftool workaround to coverity too
(cherry picked from commit d29f181cf02100c146fc8691a5515a708d06ddbf)
Related: RHEL-155394
---
.github/workflows/coverity.yml | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index 66204069c4..80d25d380a 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -25,6 +25,13 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
# Reuse the setup phase of the unit test script to avoid code duplication
- name: Install build dependencies
- run: sudo -E .github/workflows/unit_tests.sh SETUP
+ run: |
+ sudo -E .github/workflows/unit_tests.sh SETUP
+ # TODO: drop after we switch to ubuntu 26.04
+ bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
+ if [ -n "$bpftool_binary" ]; then
+ sudo rm -f /usr/{bin,sbin}/bpftool
+ sudo ln -s "$bpftool_binary" /usr/bin/
+ fi
- name: Build & upload the results
run: tools/coverity.sh

View File

@ -0,0 +1,40 @@
From 9c2aea3a3811a194bb3b9710cf521b68c5809b82 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Tue, 13 Jan 2026 18:26:48 +0100
Subject: [PATCH] ci: pin Packit/mkosi to the latest RHEL 10.1 commit
rhel-only: ci
Related: RHEL-155394
---
.packit.yml | 3 ++-
mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/.packit.yml b/.packit.yml
index a5d9aca0e1..0c2b256102 100644
--- a/.packit.yml
+++ b/.packit.yml
@@ -24,7 +24,8 @@ actions:
post-upstream-clone:
# Use the CentOS Stream 10 specfile
- - "git clone -b c10s https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1"
+ # Pin this to the latest 10.1 version (systemd-257-13)
+ - "git clone https://gitlab.com/redhat/centos-stream/rpms/systemd.git .packit_rpm --depth=1 --revision=8adcfa40b029b11bb2512c8cc7e6301ee3a77df9"
# Drop the "sources" file so rebase-helper doesn't think we're a dist-git
- "rm -fv .packit_rpm/sources"
# Drop all patches, since they're already included in the tarball
diff --git a/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf b/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf
index 31f03ca120..ea922ec18c 100644
--- a/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf
+++ b/mkosi.images/build/mkosi.conf.d/centos-fedora/mkosi.conf
@@ -8,7 +8,8 @@ Distribution=|fedora
Environment=
GIT_URL=https://gitlab.com/redhat/centos-stream/rpms/systemd/
GIT_BRANCH=c10s
- GIT_COMMIT=c10s
+ # Pin this to the latest 10.1 version (systemd-257-13)
+ GIT_COMMIT=8adcfa40b029b11bb2512c8cc7e6301ee3a77df9
PKG_SUBDIR=fedora
[Content]

View File

@ -0,0 +1,50 @@
From c5d5e72f711379c032259897a34d8f177d333d46 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 6 Feb 2026 14:17:54 +0100
Subject: [PATCH] ci: run apt-get update before running mkosi
This is alternative to https://github.com/systemd/mkosi/commit/8c9f6cc6586c4f3b8fedafc5a19e6bf30531ebfc
The repository metadata in the image can get out of date. Let's run
apt-get update to make sure it is fresh.
```
Err:21 https://security.ubuntu.com/ubuntu noble-updates/main amd64 libboost-thread1.83.0 amd64 1.83.0-2.1ubuntu3.1
404 Not Found [IP: 52.161.185.214 80]
E: Failed to fetch https://security.ubuntu.com/ubuntu/pool/main/b/boost1.83/libboost-thread1.83.0_1.83.0-2.1ubuntu3.1_amd64.deb 404 Not Found [IP: 52.161.185.214 80]
Fetched 8320 kB in 2s (3488 kB/s)
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
Error: Process completed with exit code 100.
```
rhel-only: ci
Related: RHEL-155394
---
.github/workflows/coverage.yml | 1 +
.github/workflows/mkosi.yml | 1 +
2 files changed, 2 insertions(+)
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 1cce9a97f3..bf918bc399 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -16,6 +16,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - run: sudo apt-get update
- uses: systemd/mkosi@d501139032aa659fa8d34bdb850f4eb6b5f458ed
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index 6ddfaf1a87..fe2922ac70 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -83,6 +83,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - run: sudo apt-get update
- uses: systemd/mkosi@d501139032aa659fa8d34bdb850f4eb6b5f458ed
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space

View File

@ -0,0 +1,162 @@
From 15e39369ff74425283c401f0b4c335c806c8fb99 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 19 May 2025 12:58:52 +0200
Subject: [PATCH] path-util: add flavour of path_startswith() that leaves a
leading slash in place
(cherry picked from commit ee19edbb9f3455db3f750089082f3e5a925e3a0c)
Related: RHEL-155394
---
src/basic/fs-util.c | 2 +-
src/basic/mkdir.c | 2 +-
src/basic/path-util.c | 39 ++++++++++++++++++++++++++++-----------
src/basic/path-util.h | 10 ++++++++--
src/test/test-path-util.c | 16 ++++++++++++++++
5 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 4ede324c34..21a670c9e8 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -66,7 +66,7 @@ int rmdir_parents(const char *path, const char *stop) {
assert(*slash == '/');
*slash = '\0';
- if (path_startswith_full(stop, p, /* accept_dot_dot= */ false))
+ if (path_startswith_full(stop, p, /* flags= */ 0))
return 0;
if (rmdir(p) < 0 && errno != ENOENT)
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 3e1545a58b..6fc2a79944 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -149,7 +149,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
assert(_mkdirat != mkdirat);
if (prefix) {
- p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false);
+ p = path_startswith_full(path, prefix, /* flags= */ 0);
if (!p)
return -EINVAL;
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 78ba10ed80..a4709e1b7d 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -405,8 +405,8 @@ char* path_simplify_full(char *path, PathSimplifyFlags flags) {
return path;
}
-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
- assert(path);
+char* path_startswith_full(const char *original_path, const char *prefix, PathStartWithFlags flags) {
+ assert(original_path);
assert(prefix);
/* Returns a pointer to the start of the first component after the parts matched by
@@ -419,28 +419,45 @@ char* path_startswith_full(const char *path, const char *prefix, bool accept_dot
* Returns NULL otherwise.
*/
+ const char *path = original_path;
+
if ((path[0] == '/') != (prefix[0] == '/'))
return NULL;
for (;;) {
const char *p, *q;
- int r, k;
+ int m, n;
- r = path_find_first_component(&path, accept_dot_dot, &p);
- if (r < 0)
+ m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p);
+ if (m < 0)
return NULL;
- k = path_find_first_component(&prefix, accept_dot_dot, &q);
- if (k < 0)
+ n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q);
+ if (n < 0)
return NULL;
- if (k == 0)
- return (char*) (p ?: path);
+ if (n == 0) {
+ if (!p)
+ p = path;
+
+ if (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) {
+
+ if (p <= original_path)
+ return NULL;
+
+ p--;
+
+ if (*p != '/')
+ return NULL;
+ }
+
+ return (char*) p;
+ }
- if (r != k)
+ if (m != n)
return NULL;
- if (!strneq(p, q, r))
+ if (!strneq(p, q, m))
return NULL;
}
}
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index dff5a3a549..d1e9f4b785 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -52,9 +52,15 @@ int safe_getcwd(char **ret);
int path_make_absolute_cwd(const char *p, char **ret);
int path_make_relative(const char *from, const char *to, char **ret);
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
+
+typedef enum PathStartWithFlags {
+ PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0,
+ PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1,
+} PathStartWithFlags;
+
+char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_;
static inline char* path_startswith(const char *path, const char *prefix) {
- return path_startswith_full(path, prefix, true);
+ return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT);
}
int path_compare(const char *a, const char *b) _pure_;
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index e02bd8c857..8aa477bd69 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -756,6 +756,22 @@ TEST(path_startswith) {
test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL);
}
+static void test_path_startswith_return_leading_slash_one(const char *path, const char *prefix, const char *expected) {
+ const char *p;
+
+ log_debug("/* %s(%s, %s) */", __func__, path, prefix);
+
+ p = path_startswith_full(path, prefix, PATH_STARTSWITH_RETURN_LEADING_SLASH);
+ ASSERT_STREQ(p, expected);
+}
+
+TEST(path_startswith_return_leading_slash) {
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/", "/foo/bar");
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo", "/bar");
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo/bar", NULL);
+ test_path_startswith_return_leading_slash_one("/foo/bar/", "/foo/bar", "/");
+}
+
static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
_cleanup_free_ char *s = NULL;
const char *t;

View File

@ -0,0 +1,45 @@
From 6128d02c345422150a2e702b5fd1e51212236577 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 22 May 2025 18:35:25 +0200
Subject: [PATCH] cgroup: port some code over to path_startswith_full()
(cherry picked from commit 482107724f64cb8dd24db3e65b6ea3151a330301)
Related: RHEL-155394
---
src/basic/cgroup-util.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 309dccb45a..b8a17badea 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -1013,13 +1013,12 @@ int cg_get_root_path(char **ret_path) {
}
int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted) {
- _cleanup_free_ char *rt = NULL;
- char *p;
int r;
assert(cgroup);
assert(ret_shifted);
+ _cleanup_free_ char *rt = NULL;
if (!root) {
/* If the root was specified let's use that, otherwise
* let's determine it from PID 1 */
@@ -1031,12 +1030,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
root = rt;
}
- p = path_startswith(cgroup, root);
- if (p && p > cgroup)
- *ret_shifted = p - 1;
- else
- *ret_shifted = cgroup;
-
+ *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH) ?: cgroup;
return 0;
}

View File

@ -0,0 +1,95 @@
From 324340b11bbdef8a0b1e607acd741bc453b222dc Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 23 May 2025 06:45:40 +0200
Subject: [PATCH] path-util: invert PATH_STARTSWITH_ACCEPT_DOT_DOT flag
As requested: https://github.com/systemd/systemd/pull/37572#pullrequestreview-2861928094
(cherry picked from commit ceed11e465f1c8efff1931412a85924d9de7c08d)
Related: RHEL-155394
---
src/basic/cgroup-util.c | 2 +-
src/basic/fs-util.c | 2 +-
src/basic/mkdir.c | 2 +-
src/basic/path-util.c | 4 ++--
src/basic/path-util.h | 4 ++--
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index b8a17badea..925b753c39 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -1030,7 +1030,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
root = rt;
}
- *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH) ?: cgroup;
+ *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup;
return 0;
}
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 21a670c9e8..69e76653ab 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -66,7 +66,7 @@ int rmdir_parents(const char *path, const char *stop) {
assert(*slash == '/');
*slash = '\0';
- if (path_startswith_full(stop, p, /* flags= */ 0))
+ if (path_startswith_full(stop, p, PATH_STARTSWITH_REFUSE_DOT_DOT))
return 0;
if (rmdir(p) < 0 && errno != ENOENT)
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 6fc2a79944..f1e5f2dc8d 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -149,7 +149,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
assert(_mkdirat != mkdirat);
if (prefix) {
- p = path_startswith_full(path, prefix, /* flags= */ 0);
+ p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT);
if (!p)
return -EINVAL;
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index a4709e1b7d..fda6066bc6 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -428,11 +428,11 @@ char* path_startswith_full(const char *original_path, const char *prefix, PathSt
const char *p, *q;
int m, n;
- m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p);
+ m = path_find_first_component(&path, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &p);
if (m < 0)
return NULL;
- n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q);
+ n = path_find_first_component(&prefix, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &q);
if (n < 0)
return NULL;
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index d1e9f4b785..429d7ac507 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -54,13 +54,13 @@ int path_make_relative(const char *from, const char *to, char **ret);
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
typedef enum PathStartWithFlags {
- PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0,
+ PATH_STARTSWITH_REFUSE_DOT_DOT = 1U << 0,
PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1,
} PathStartWithFlags;
char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_;
static inline char* path_startswith(const char *path, const char *prefix) {
- return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT);
+ return path_startswith_full(path, prefix, 0);
}
int path_compare(const char *a, const char *b) _pure_;

View File

@ -0,0 +1,28 @@
From 1f710e3d70ab5303adc27b61e2da86b039cd4caa Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Thu, 26 Feb 2026 11:07:39 +0100
Subject: [PATCH] sd-json: fix off-by-one issue when updating parent for array
elements
Follow-up for 8525bb369a09f488ec77f94e1557ecc2343eb4ab
(cherry picked from commit 4e6e3b8707c84018051ae1885af20e06b2a5209e)
Related: RHEL-155394
---
src/libsystemd/sd-json/sd-json.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c
index 64b59e0f3f..97897122b8 100644
--- a/src/libsystemd/sd-json/sd-json.c
+++ b/src/libsystemd/sd-json/sd-json.c
@@ -2243,7 +2243,7 @@ _public_ int sd_json_variant_append_array(sd_json_variant **v, sd_json_variant *
if (old != *v)
/* Readjust the parent pointers to the new address */
- for (size_t i = 1; i < size; i++)
+ for (size_t i = 0; i < size; i++)
(*v)[1 + i].parent = *v;
return json_variant_array_put_element(*v, element);

View File

@ -0,0 +1,96 @@
From 35cf009cf363a0657ca812246f7f9233677a2369 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Thu, 26 Feb 2026 11:06:00 +0100
Subject: [PATCH] core/cgroup: avoid one unnecessary strjoina()
(cherry picked from commit 42aee39107fbdd7db1ccd402a2151822b2805e9f)
Related: RHEL-155394
---
src/core/cgroup.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 22a29666b6..88ba883f77 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -2961,12 +2961,13 @@ static int unit_update_cgroup(
return 0;
}
-static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suffix_path) {
+static int unit_attach_pid_to_cgroup_via_bus(Unit *u, const char *cgroup_path, pid_t pid) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- char *pp;
int r;
assert(u);
+ assert(cgroup_path);
+ assert(pid_is_valid(pid));
if (MANAGER_IS_SYSTEM(u->manager))
return -EINVAL;
@@ -2974,18 +2975,13 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
if (!u->manager->system_bus)
return -EIO;
- CGroupRuntime *crt = unit_get_cgroup_runtime(u);
- if (!crt || !crt->cgroup_path)
- return -EOWNERDEAD;
-
/* Determine this unit's cgroup path relative to our cgroup root */
- pp = path_startswith(crt->cgroup_path, u->manager->cgroup_root);
+ const char *pp = path_startswith_full(cgroup_path,
+ u->manager->cgroup_root,
+ PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT);
if (!pp)
return -EINVAL;
- pp = strjoina("/", pp, suffix_path);
- path_simplify(pp);
-
r = bus_call_method(u->manager->system_bus,
bus_systemd_mgr,
"AttachProcessesToUnit",
@@ -3026,8 +3022,10 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
CGroupRuntime *crt = ASSERT_PTR(unit_get_cgroup_runtime(u));
if (isempty(suffix_path))
- p = crt->cgroup_path;
+ p = empty_to_root(crt->cgroup_path);
else {
+ assert(path_is_absolute(suffix_path));
+
joined = path_join(crt->cgroup_path, suffix_path);
if (!joined)
return -ENOMEM;
@@ -3045,7 +3043,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
* before we use it */
r = pidref_verify(pid);
if (r < 0) {
- log_unit_info_errno(u, r, "PID " PID_FMT " vanished before we could move it to target cgroup '%s', skipping: %m", pid->pid, empty_to_root(p));
+ log_unit_info_errno(u, r, "PID " PID_FMT " vanished before we could move it to target cgroup '%s', skipping: %m", pid->pid, p);
continue;
}
@@ -3056,7 +3054,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
log_unit_full_errno(u, again ? LOG_DEBUG : LOG_INFO, r,
"Couldn't move process "PID_FMT" to%s requested cgroup '%s': %m",
- pid->pid, again ? " directly" : "", empty_to_root(p));
+ pid->pid, again ? " directly" : "", p);
if (again) {
int z;
@@ -3066,9 +3064,9 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
* Since it's more privileged it might be able to move the process across the
* leaves of a subtree whose top node is not owned by us. */
- z = unit_attach_pid_to_cgroup_via_bus(u, pid->pid, suffix_path);
+ z = unit_attach_pid_to_cgroup_via_bus(u, p, pid->pid);
if (z < 0)
- log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid->pid, empty_to_root(p));
+ log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid->pid, p);
else {
if (ret >= 0)
ret++; /* Count successful additions */

View File

@ -0,0 +1,29 @@
From 5d45ce22093b7dc6911a94213b0cc29898aff393 Mon Sep 17 00:00:00 2001
From: Mike Yuan <me@yhndnzj.com>
Date: Thu, 26 Feb 2026 11:06:34 +0100
Subject: [PATCH] core: validate input cgroup path more prudently
(cherry picked from commit efa6ba2ab625aaa160ac435a09e6482fc63bdbe8)
Resolves: RHEL-155394
---
src/core/dbus-manager.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 8e39d67a00..d516f30c96 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -622,6 +622,12 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd
if (r < 0)
return r;
+ if (!path_is_absolute(cgroup))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not absolute: %s", cgroup);
+
+ if (!path_is_normalized(cgroup))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not normalized: %s", cgroup);
+
u = manager_get_unit_by_cgroup(m, cgroup);
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,

View File

@ -48,7 +48,7 @@ Url: https://systemd.io
# Allow users to specify the version and release when building the rpm by
# setting the %%version_override and %%release_override macros.
Version: %{?version_override}%{!?version_override:257}
Release: 13%{?dist}
Release: 13%{?dist}.3
%global stable %(c="%version"; [ "$c" = "${c#*.*}" ]; echo $?)
@ -548,6 +548,42 @@ Patch0435: 0435-hwdb-Add-launch-emoji-keyboard-mapping-for-Asus-M160.patch
Patch0436: 0436-Enable-KEY_PERFORMANCE-key-present-on-Linux-6.17.patch
Patch0437: 0437-hwdb-add-HP-150-Wired-Mouse-37341.patch
Patch0438: 0438-core-transaction-do-not-attempt-to-log-n-a-as-a-jour.patch
Patch0439: 0439-coredump-verify-pidfd-after-parsing-data-in-usermode.patch
Patch0440: 0440-coredump-restore-compatibility-with-older-patterns.patch
Patch0441: 0441-coredump-wrap-long-lines-fix-grammar-in-comments.patch
Patch0442: 0442-coredump-get-rid-of-_META_MANDATORY_MAX.patch
Patch0443: 0443-coredump-use-d-in-kernel-core-pattern.patch
Patch0444: 0444-coredump-also-stop-forwarding-non-dumpable-processes.patch
Patch0445: 0445-coredump-get-rid-of-a-bogus-assertion.patch
Patch0446: 0446-coredump-add-support-for-new-F-PIDFD-specifier.patch
Patch0447: 0447-coredump-when-F-pidfd-is-used-again-allow-forwarding.patch
Patch0448: 0448-coredump-introduce-an-enum-to-wrap-dumpable-constant.patch
Patch0449: 0449-Define-helper-to-call-PR_SET_DUMPABLE.patch
Patch0450: 0450-coredump-fix-0-passed-as-pointer-warning.patch
Patch0451: 0451-Revert-coredump-fix-0-passed-as-pointer-warning.patch
Patch0452: 0452-Revert-Define-helper-to-call-PR_SET_DUMPABLE.patch
Patch0453: 0453-Revert-coredump-introduce-an-enum-to-wrap-dumpable-c.patch
Patch0454: 0454-Revert-coredump-when-F-pidfd-is-used-again-allow-for.patch
Patch0455: 0455-Revert-coredump-add-support-for-new-F-PIDFD-specifie.patch
Patch0456: 0456-Revert-coredump-get-rid-of-a-bogus-assertion.patch
Patch0457: 0457-Revert-coredump-also-stop-forwarding-non-dumpable-pr.patch
Patch0458: 0458-Revert-coredump-use-d-in-kernel-core-pattern.patch
Patch0459: 0459-Revert-coredump-get-rid-of-_META_MANDATORY_MAX.patch
Patch0460: 0460-Revert-coredump-wrap-long-lines-fix-grammar-in-comme.patch
Patch0461: 0461-Revert-coredump-restore-compatibility-with-older-pat.patch
Patch0462: 0462-Revert-coredump-verify-pidfd-after-parsing-data-in-u.patch
Patch0463: 0463-ci-re-enable-bpf-framework-option-for-build-and-unit.patch
Patch0464: 0464-ci-add-bpftool-workaround-to-codeql-job-too.patch
Patch0465: 0465-ci-fix-workaround-about-bpftool-for-codeql.patch
Patch0466: 0466-ci-add-bpftool-workaround-to-coverity-too.patch
Patch0467: 0467-ci-pin-Packit-mkosi-to-the-latest-RHEL-10.1-commit.patch
Patch0468: 0468-ci-run-apt-get-update-before-running-mkosi.patch
Patch0469: 0469-path-util-add-flavour-of-path_startswith-that-leaves.patch
Patch0470: 0470-cgroup-port-some-code-over-to-path_startswith_full.patch
Patch0471: 0471-path-util-invert-PATH_STARTSWITH_ACCEPT_DOT_DOT-flag.patch
Patch0472: 0472-sd-json-fix-off-by-one-issue-when-updating-parent-fo.patch
Patch0473: 0473-core-cgroup-avoid-one-unnecessary-strjoina.patch
Patch0474: 0474-core-validate-input-cgroup-path-more-prudently.patch
# Downstream-only patches (90009999)
%endif
@ -1494,6 +1530,48 @@ rm -f .file-list-*
rm -f %{name}.lang
%changelog
* Wed Apr 08 2026 systemd maintenance team <systemd-maint@redhat.com> - 257-13.3
- ci: re-enable bpf-framework option for build and unit test jobs (RHEL-155394)
- ci: add bpftool workaround to codeql job too (RHEL-155394)
- ci: fix workaround about bpftool for codeql (RHEL-155394)
- ci: add bpftool workaround to coverity too (RHEL-155394)
- ci: pin Packit/mkosi to the latest RHEL 10.1 commit (RHEL-155394)
- ci: run apt-get update before running mkosi (RHEL-155394)
- path-util: add flavour of path_startswith() that leaves a leading slash in place (RHEL-155394)
- cgroup: port some code over to path_startswith_full() (RHEL-155394)
- path-util: invert PATH_STARTSWITH_ACCEPT_DOT_DOT flag (RHEL-155394)
- sd-json: fix off-by-one issue when updating parent for array elements (RHEL-155394)
- core/cgroup: avoid one unnecessary strjoina() (RHEL-155394)
- core: validate input cgroup path more prudently (RHEL-155394)
* Thu Jan 22 2026 systemd maintenance team <systemd-maint@redhat.com> - 257-13.2
- Revert "coredump: fix 0-passed-as-pointer warning" (RHEL-104135)
- Revert "Define helper to call PR_SET_DUMPABLE" (RHEL-104135)
- Revert "coredump: introduce an enum to wrap dumpable constants" (RHEL-104135)
- Revert "coredump: when %F/pidfd is used, again allow forwarding to containers" (RHEL-104135)
- Revert "coredump: add support for new %F PIDFD specifier" (RHEL-104135)
- Revert "coredump: get rid of a bogus assertion" (RHEL-104135)
- Revert "coredump: also stop forwarding non-dumpable processes" (RHEL-104135)
- Revert "coredump: use %d in kernel core pattern" (RHEL-104135)
- Revert "coredump: get rid of _META_MANDATORY_MAX" (RHEL-104135)
- Revert "coredump: wrap long lines, fix grammar in comments" (RHEL-104135)
- Revert "coredump: restore compatibility with older patterns" (RHEL-104135)
- Revert "coredump: verify pidfd after parsing data in usermode helper" (RHEL-104135)
* Fri Nov 21 2025 systemd maintenance team <systemd-maint@redhat.com> - 257-13.1
- coredump: verify pidfd after parsing data in usermode helper (RHEL-104135)
- coredump: restore compatibility with older patterns (RHEL-104135)
- coredump: wrap long lines, fix grammar in comments (RHEL-104135)
- coredump: get rid of _META_MANDATORY_MAX (RHEL-104135)
- coredump: use %d in kernel core pattern (RHEL-104135)
- coredump: also stop forwarding non-dumpable processes (RHEL-104135)
- coredump: get rid of a bogus assertion (RHEL-104135)
- coredump: add support for new %F PIDFD specifier (RHEL-104135)
- coredump: when %F/pidfd is used, again allow forwarding to containers (RHEL-104135)
- coredump: introduce an enum to wrap dumpable constants (RHEL-104135)
- Define helper to call PR_SET_DUMPABLE (RHEL-104135)
- coredump: fix 0-passed-as-pointer warning (RHEL-104135)
* Fri Aug 15 2025 systemd maintenance team <systemd-maint@redhat.com> - 257-13
- core/transaction: do not attempt to log "n/a" as a journal field (RHEL-106260)