Hi systemd maintainers and LTS folks,

I have prepared a fix for CVE-2025-4598 by mainly backporting the fixes
for systemd's stable version 252 and a required macro. Since systemd is
a very high profile package, I'd love a second (and a third :-) pair of
eyes looking at the changes. They are available in my salsa namespace
[1] and attached as debdiff. To test the fix, one can create a VM using
QEMU/debvm/incus --vm and run a reverse-engineered PoC sent to
oss-security [2]. Just make sure you run it as regular user with a
restricted pid_max (sysctl kernel.pid_max=1000) and use getfacl to see
if the regular user has read permission on the dump.

On a separate but important aspect, I've stumbled upon a buffer overflow
when running "systemd-run -t --property CoredumpFilter=all ls /tmp"
because it was in the coredump unit test. This does not have a CVE
assigned but it is a bug that might be worth fixing since it was
backported to systemd stable releases 253, 252 and 251 [3] (the feature
was introduced in systemd 246). I'm seeking advice if this bug should be
fixed in this bullseye update. The bug:

root@teste:~# systemd-run -t --property CoredumpFilter=all ls /tmp
Running as unit: run-u9.service
Press ^] three times within 1s to disconnect TTY.
*** buffer overflow detected ***: terminated

On a last note to systemd maintainers, currently we host the packaging
for LTS/ELTS in a fork under lts-team namespace [4], but it would be
nice to have it in the official repo. If you are okay with the idea,
please let me know and we can make the arrangements to use the official
one.

Cheers,
Charles

[1] https://salsa.debian.org/charles/systemd/-/tree/debian/bullseye
[2] https://www.openwall.com/lists/oss-security/2025/06/05/1
[3] https://github.com/systemd/systemd/pull/27421
[4] https://salsa.debian.org/lts-team/packages/systemd
diff -Nru systemd-247.3/debian/changelog systemd-247.3/debian/changelog
--- systemd-247.3/debian/changelog	2024-08-25 16:05:15.000000000 -0300
+++ systemd-247.3/debian/changelog	2025-06-25 21:44:53.000000000 -0300
@@ -1,3 +1,12 @@
+systemd (247.3-7+deb11u7) bullseye-security; urgency=medium
+
+  * Non-maintainer upload by the LTS Team.
+  * debian/patches/CVE-2025-4598-{0,1,2,3,4}.patch: import and backport
+    patches from upstream to fix CVE-2025-4598.
+  * debian/salsa-ci.yml: add (E)LTS pipeline for bullseye.
+
+ -- Carlos Henrique Lima Melara <charlesmel...@riseup.net>  Wed, 25 Jun 2025 21:44:53 -0300
+
 systemd (247.3-7+deb11u6) bullseye-security; urgency=medium
 
   * Non-maintainer upload by the LTS Team.
diff -Nru systemd-247.3/debian/patches/CVE-2025-4598-0.patch systemd-247.3/debian/patches/CVE-2025-4598-0.patch
--- systemd-247.3/debian/patches/CVE-2025-4598-0.patch	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/patches/CVE-2025-4598-0.patch	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,88 @@
+From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl>
+Date: Tue, 29 Apr 2025 14:47:59 +0200
+Subject: 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)
+(cherry picked from commit f9b8b75c11bba9b63096904be98cc529c304eb97)
+(cherry picked from commit 385a33b043406ad79a7207f3906c3b15192a3333)
+(cherry picked from commit c6f79626b6d175c6a5b62b8c5d957a83eb882301)
+(cherry picked from commit 9f02346d50e33c24acf879ce4dd5937d56473325)
+(cherry picked from commit ac0aa5d1fdc21db1ef035fce562cb6fc8602b544)
+
+Origin: upstream, https://github.com/systemd/systemd-stable/commit/cadd1b1a1f39fd13b1115a10f563017201d7b56a
+Forwarded: not-needed
+Last-Update: 2025-06-23
+---
+ src/coredump/coredump.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
+index b60dff3..a5fcb94 100644
+--- a/src/coredump/coredump.c
++++ b/src/coredump/coredump.c
+@@ -81,8 +81,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
+@@ -93,7 +97,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,
+@@ -1182,14 +1186,17 @@ static int gather_pid_metadata_from_argv(
+         char *t;
+
+         /* We gather all metadata that were passed via argv[] into an array of iovecs that
+-         * we'll forward to the socket unit */
++         * we'll forward to the socket unit.
++         *
++         * We require at least _META_ARGV_REQUIRED args, but will accept more.
++         * We know how to parse _META_ARGV_MAX args. The rest will be ignored. */
+
+-        if (argc < _META_ARGV_MAX)
++        if (argc < _META_ARGV_REQUIRED)
+                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+-                                       "Not enough arguments passed by the kernel (%i, expected %i).",
+-                                       argc, _META_ARGV_MAX);
++                                       "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
++                                       argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
+
+-        for (i = 0; i < _META_ARGV_MAX; i++) {
++        for (i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
+
+                 t = argv[i];
+
diff -Nru systemd-247.3/debian/patches/CVE-2025-4598-1.patch systemd-247.3/debian/patches/CVE-2025-4598-1.patch
--- systemd-247.3/debian/patches/CVE-2025-4598-1.patch	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/patches/CVE-2025-4598-1.patch	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,33 @@
+From c288a3aafdf11cd93eb7a21e4d587c6fc218a29c Mon Sep 17 00:00:00 2001
+From: Dan Streetman <ddstr...@ieee.org>
+Date: Thu, 2 Feb 2023 15:58:10 -0500
+Subject: [PATCH] basic/macro: add macro to iterate variadic args
+
+(cherry picked from commit e179f2d89c9f0c951636d74de00136b4075cd1ac)
+(cherry picked from commit cd4f43bf378ff33ce5cfeacd96f7f3726603bddc)
+
+Origin: upstream, https://github.com/systemd/systemd-stable/commit/c288a3aafdf11cd93eb7a21e4d587c6fc218a29c
+Forwarded: not-needed
+Last-Update: 2025-06-23
+---
+ src/basic/macro.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/basic/macro.h b/src/basic/macro.h
+index 2782553..ee83541 100644
+--- a/src/basic/macro.h
++++ b/src/basic/macro.h
+@@ -654,4 +654,13 @@ static inline size_t size_add(size_t x, size_t y) {
+         return y >= SIZE_MAX - x ? SIZE_MAX : x + y;
+ }
+ 
++/* Iterate through each variadic arg. All must be the same type as 'entry' or must be implicitly
++ * convertable. The iteration variable 'entry' must already be defined. */
++#define VA_ARGS_FOREACH(entry, ...)                                     \
++        _VA_ARGS_FOREACH(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), ##__VA_ARGS__)
++#define _VA_ARGS_FOREACH(entry, _entries_, _current_, ...)         \
++        for (typeof(entry) _entries_[] = { __VA_ARGS__ }, *_current_ = _entries_; \
++             ((long)(_current_ - _entries_) < (long)ELEMENTSOF(_entries_)) && ({ entry = *_current_; true; }); \
++             _current_++)
++
+ #include "log.h"
diff -Nru systemd-247.3/debian/patches/CVE-2025-4598-2.patch systemd-247.3/debian/patches/CVE-2025-4598-2.patch
--- systemd-247.3/debian/patches/CVE-2025-4598-2.patch	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/patches/CVE-2025-4598-2.patch	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,74 @@
+From 31ba3f4ea0f472355e985c7bcca66ffc35e5735c Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <franti...@sumsal.cz>
+Date: Wed, 17 Jan 2024 13:11:14 +0100
+Subject: [PATCH] macro: terminate the temporary VA_ARGS_FOREACH() array with a
+ sentinel
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So gcc-14 doesn't complain we're out of bounds on the last iteration:
+
+[2092/2414] Compiling C object test-macro.p/src_test_test-macro.c.o
+In file included from ../src/basic/list.h:209,
+                 from ../src/basic/log.h:10,
+                 from ../src/test/test-macro.c:5:
+../src/test/test-macro.c: In function ‘test_FOREACH_VA_ARGS’:
+../src/basic/macro.h:395:90: warning: array subscript 1 is outside array bounds of ‘uint8_t[1]’ {aka ‘unsigned char[1]’} [-Warray-bounds=]
+  395 |              ((long)(_current_ - _entries_) < (long)ELEMENTSOF(_entries_)) && ({ entry = *_current_; true; }); \
+../src/basic/macro.h:392:9: note: in expansion of macro ‘_VA_ARGS_FOREACH’
+  392 |         _VA_ARGS_FOREACH(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), ##__VA_ARGS__)
+      |         ^~~~~~~~~~~~~~~~
+../src/test/test-macro.c:322:9: note: in expansion of macro ‘VA_ARGS_FOREACH’
+  322 |         VA_ARGS_FOREACH(u8, 0) {
+      |         ^~~~~~~~~~~~~~~
+../src/fundamental/macro-fundamental.h:163:37: note: at offset 1 into object ‘__unique_prefix__entries_181’ of size 1
+  163 | #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
+      |                                     ^~~~~~~~~~~~~~~~
+../src/basic/macro.h:394:28: note: in definition of macro ‘_VA_ARGS_FOREACH’
+  394 |         for (typeof(entry) _entries_[] = { __VA_ARGS__ }, *_current_ = _entries_; \
+      |                            ^~~~~~~~~
+../src/fundamental/macro-fundamental.h:109:27: note: in expansion of macro ‘XCONCATENATE’
+  109 | #define CONCATENATE(x, y) XCONCATENATE(x, y)
+      |                           ^~~~~~~~~~~~
+../src/fundamental/macro-fundamental.h:163:25: note: in expansion of macro ‘CONCATENATE’
+  163 | #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
+      |                         ^~~~~~~~~~~
+../src/basic/macro.h:392:33: note: in expansion of macro ‘UNIQ_T’
+  392 |         _VA_ARGS_FOREACH(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), ##__VA_ARGS__)
+      |                                 ^~~~~~
+../src/test/test-macro.c:322:9: note: in expansion of macro ‘VA_ARGS_FOREACH’
+  322 |         VA_ARGS_FOREACH(u8, 0) {
+      |         ^~~~~~~~~~~~~~~
+
+(cherry picked from commit dc571cccd75db7be49b2aada64baf92e3a498c39)
+(cherry picked from commit 0ddd788136622da3320e43aaa5005b0a68c89137)
+(cherry picked from commit d44fe47f2ea48fd6da83d1748ff37f46df8b4ddd)
+(cherry picked from commit 6a8d6e29cee540e06eb7dba6d5c2185a7a0ac00b)
+
+Origin: upstream, https://github.com/systemd/systemd-stable/commit/31ba3f4ea0f472355e985c7bcca66ffc35e5735c
+Forwarded: not-needed
+Last-Update: 2025-06-23
+---
+ src/basic/macro.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/basic/macro.h b/src/basic/macro.h
+index ee83541..e57014c 100644
+--- a/src/basic/macro.h
++++ b/src/basic/macro.h
+@@ -657,10 +657,10 @@ static inline size_t size_add(size_t x, size_t y) {
+ /* Iterate through each variadic arg. All must be the same type as 'entry' or must be implicitly
+  * convertable. The iteration variable 'entry' must already be defined. */
+ #define VA_ARGS_FOREACH(entry, ...)                                     \
+-        _VA_ARGS_FOREACH(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), ##__VA_ARGS__)
+-#define _VA_ARGS_FOREACH(entry, _entries_, _current_, ...)         \
+-        for (typeof(entry) _entries_[] = { __VA_ARGS__ }, *_current_ = _entries_; \
+-             ((long)(_current_ - _entries_) < (long)ELEMENTSOF(_entries_)) && ({ entry = *_current_; true; }); \
++        _VA_ARGS_FOREACH(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), UNIQ_T(_va_sentinel_, UNIQ), ##__VA_ARGS__)
++#define _VA_ARGS_FOREACH(entry, _entries_, _current_, _va_sentinel_, ...)         \
++        for (typeof(entry) _va_sentinel_[1] = {}, _entries_[] = { __VA_ARGS__ __VA_OPT__(,) _va_sentinel_[0] }, *_current_ = _entries_; \
++             ((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
+              _current_++)
+ 
+ #include "log.h"
diff -Nru systemd-247.3/debian/patches/CVE-2025-4598-3.patch systemd-247.3/debian/patches/CVE-2025-4598-3.patch
--- systemd-247.3/debian/patches/CVE-2025-4598-3.patch	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/patches/CVE-2025-4598-3.patch	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,101 @@
+From 2c81e60fe0b8c506a4fe902e45bed6f58f482b39 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@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 49f1f2d4a7612bbed5211a73d11d6a94fbe3bb69)
+(cherry-picked from aea6a631bca93e8b04a11aaced694f25f4da155e)
+(cherry picked from cf16b6b6b2e0a656531bfd73ad66be3817b155cd)
+
+(cherry picked from commit b46a4f023cd80b24c8f1aa7a95700bc0cb828cdc)
+(cherry picked from commit 5855552310ed279180c21cb803408aa2ce36053d)
+(cherry picked from commit cc31f2d4146831b9f2fe7bf584468908ff9c4de5)
+
+Origin: upstream, https://github.com/systemd/systemd-stable/commit/2c81e60fe0b8c506a4fe902e45bed6f58f482b39
+Forwarded: not-needed
+Last-Update: 2025-06-23
+---
+ src/coredump/coredump.c | 29 ++++++++++++++++++++---------
+ 1 file changed, 20 insertions(+), 9 deletions(-)
+
+diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
+index a5fcb94..f787a7a 100644
+--- a/src/coredump/coredump.c
++++ b/src/coredump/coredump.c
+@@ -68,7 +68,7 @@
+  * size. See DATA_SIZE_MAX in journal-importer.h. */
+ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
+ 
+-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
+@@ -94,16 +94,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=",
+@@ -1018,7 +1017,7 @@ static int process_socket(int fd) {
+         Context context = {};
+         struct iovec_wrapper iovw = {};
+         struct iovec iovec;
+-        int i, r;
++        int r;
+ 
+         assert(fd >= 0);
+ 
+@@ -1095,12 +1094,24 @@ static int process_socket(int fd) {
+         if (r < 0)
+                 goto finish;
+ 
+-        /* Make sure we received at least all fields we need. */
+-        for (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;
++        VA_ARGS_FOREACH(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]) {
+                         r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+-                                            "A mandatory argument (%i) has not been sent, aborting.",
+-                                            i);
++                                            "Mandatory argument %s not received on socket, aborting.",
++                                            meta_field_names[i]);
+                         goto finish;
+                 }
+ 
diff -Nru systemd-247.3/debian/patches/CVE-2025-4598-4.patch systemd-247.3/debian/patches/CVE-2025-4598-4.patch
--- systemd-247.3/debian/patches/CVE-2025-4598-4.patch	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/patches/CVE-2025-4598-4.patch	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,267 @@
+From 2eb46dce078334805c547cbcf5e6462cf9d2f9f0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@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 <q...@qualys.com>
+
+(cherry-picked from commit 0c49e0049b7665bb7769a13ef346fef92e1ad4d6)
+(cherry-picked from commit c58a8a6ec9817275bb4babaa2c08e0e35090d4e3)
+(cherry picked from commit 19d439189ab85dd7222bdd59fd442bbcc8ea99a7)
+(cherry picked from commit 254ab8d2a7866679cee006d844d078774cbac3c9)
+(cherry picked from commit 7fc7aa5a4d28d7768dfd1eb85be385c3ea949168)
+(cherry picked from commit 19b228662e0fcc6596c0395a0af8486a4b3f1627)
+
+Origin: upstream, https://github.com/systemd/systemd-stable/commit/2eb46dce078334805c547cbcf5e6462cf9d2f9f0
+Forwarded: not-needed
+Last-Update: 2025-06-23
+---
+ src/coredump/coredump.c             |  21 +++++-
+ sysctl.d/50-coredump.conf.in        |   2 +-
+ test/units/testsuite-74.coredump.sh | 144 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 163 insertions(+), 4 deletions(-)
+ create mode 100755 test/units/testsuite-74.coredump.sh
+
+diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
+index f787a7a..a4678f6 100644
+--- a/src/coredump/coredump.c
++++ b/src/coredump/coredump.c
+@@ -84,6 +84,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 */
+         _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. */
+@@ -112,6 +113,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=",
+@@ -122,6 +124,7 @@ typedef struct Context {
+         const char *meta[_META_MAX];
+         size_t meta_size[_META_MAX];
+         pid_t pid;
++        unsigned dumpable;
+         bool is_pid1;
+         bool is_journald;
+ } Context;
+@@ -469,14 +472,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;
+ }
+@@ -1005,6 +1010,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
+         if (r < 0)
+                 return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
+ 
++        /* 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 8e501c4..2f92294 100644
+--- a/sysctl.d/50-coredump.conf.in
++++ b/sysctl.d/50-coredump.conf.in
+@@ -13,7 +13,7 @@
+ # the core dump.
+ #
+ # See systemd-coredump(8) and core(5).
+-kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t 9223372036854775808 %h
++kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t 9223372036854775808 %h %d
+ 
+ # Allow that 16 coredumps are dispatched in parallel by the kernel. We want to
+ # be able to collect process metadata from /proc/%P/ while processing
+diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
+new file mode 100755
+index 0000000..ff23418
+--- /dev/null
++++ b/test/units/testsuite-74.coredump.sh
+@@ -0,0 +1,144 @@
++#!/usr/bin/env bash
++# SPDX-License-Identifier: LGPL-2.1-or-later
++set -eux
++set -o pipefail
++
++# Make sure the binary name fits into 15 characters
++CORE_TEST_BIN="/tmp/test-dump"
++MAKE_DUMP_SCRIPT="/tmp/make-dump"
++# Unset $PAGER so we don't have to use --no-pager everywhere
++export PAGER=
++
++at_exit() {
++    rm -fv -- "$CORE_TEST_BIN" "$MAKE_DUMP_SCRIPT"
++}
++
++trap at_exit EXIT
++
++if systemd-detect-virt -cq; then
++    echo "Running in a container, skipping the systemd-coredump test..."
++    exit 0
++fi
++
++# To make all coredump entries stored in system.journal.
++journalctl --rotate
++
++# Check that we're the ones to receive coredumps
++sysctl kernel.core_pattern | grep systemd-coredump
++
++# Prepare "fake" binaries for coredumps, so we can properly exercise
++# the matching stuff too
++cp -vf /bin/sleep "${CORE_TEST_BIN:?}"
++# Simple script that spawns given "fake" binary and then kills it with
++# given signal
++cat >"${MAKE_DUMP_SCRIPT:?}" <<\EOF
++#!/bin/bash -ex
++
++bin="${1:?}"
++sig="${2:?}"
++
++ulimit -c unlimited
++"$bin" infinity &
++pid=$!
++# Sync with the "fake" binary, so we kill it once it's fully forked off,
++# otherwise we might kill it during fork and kernel would then report
++# "wrong" binary name (i.e. $MAKE_DUMP_SCRIPT instead of $CORE_TEST_BIN).
++# In this case, wait until the "fake" binary (sleep in this case) enters
++# the "interruptible sleep" state, at which point it should be ready
++# to be sacrificed.
++for _ in {0..9}; do
++    read -ra self_stat <"/proc/$pid/stat"
++    [[ "${self_stat[2]}" == S ]] && break
++    sleep .5
++done
++kill -s "$sig" "$pid"
++# This should always fail
++! wait "$pid"
++EOF
++chmod +x "$MAKE_DUMP_SCRIPT"
++
++# Privileged stuff
++[[ "$(id -u)" -eq 0 ]]
++# Trigger a couple of coredumps
++"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGTRAP"
++"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGABRT"
++# In the tests we store the coredumps in journals, so let's generate a couple
++# with Storage=external as well
++mkdir -p /run/systemd/coredump.conf.d/
++printf '[Coredump]\nStorage=external' >/run/systemd/coredump.conf.d/99-external.conf
++"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGTRAP"
++"$MAKE_DUMP_SCRIPT" "$CORE_TEST_BIN" "SIGABRT"
++rm -fv /run/systemd/coredump.conf.d/99-external.conf
++# Wait a bit for the coredumps to get processed
++timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done"
++
++coredumpctl
++SYSTEMD_LOG_LEVEL=debug coredumpctl
++coredumpctl --help
++coredumpctl --version
++coredumpctl --no-pager --no-legend
++coredumpctl -1
++coredumpctl --reverse
++coredumpctl -F COREDUMP_EXE
++coredumpctl --directory=/var/log/journal
++coredumpctl --file="/var/log/journal/$(</etc/machine-id)/system.journal"
++coredumpctl --since=@0
++coredumpctl --since=yesterday --until=tomorrow
++# We should have a couple of externally stored coredumps
++coredumpctl --field=COREDUMP_FILENAME | tee /tmp/coredumpctl.out
++grep "/var/lib/systemd/coredump/core" /tmp/coredumpctl.out
++rm -f /tmp/coredumpctl.out
++
++coredumpctl info
++coredumpctl info "$CORE_TEST_BIN"
++coredumpctl info /foo /bar/ /baz "$CORE_TEST_BIN"
++coredumpctl info "${CORE_TEST_BIN##*/}"
++coredumpctl info foo bar baz "${CORE_TEST_BIN##*/}"
++coredumpctl info COREDUMP_EXE="$CORE_TEST_BIN"
++coredumpctl info COREDUMP_EXE=aaaaa COREDUMP_EXE= COREDUMP_EXE="$CORE_TEST_BIN"
++
++coredumpctl debug --debugger=/bin/true "$CORE_TEST_BIN"
++SYSTEMD_DEBUGGER=/bin/true coredumpctl debug "$CORE_TEST_BIN"
++
++coredumpctl dump "$CORE_TEST_BIN" >/tmp/core.redirected
++test -s /tmp/core.redirected
++coredumpctl dump -o /tmp/core.output "${CORE_TEST_BIN##*/}"
++test -s /tmp/core.output
++rm -f /tmp/core.{output,redirected}
++
++# --backtrace mode
++# Pass one of the existing journal coredump records to systemd-coredump.
++# Use our PID as the source to be able to create a PIDFD and to make matching easier.
++# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT [HOSTNAME]
++journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
++    /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
++journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
++    /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
++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"
++
++systemd-run -t --property CoredumpFilter=default ls /tmp
++
++(! coredumpctl --hello-world)
++(! coredumpctl --file=/dev/null)
++(! coredumpctl --since=0)
++(! coredumpctl --until='')
++(! coredumpctl --since=today --until=yesterday)
++(! coredumpctl -F foo -F bar)
++(! coredumpctl list 0)
++(! coredumpctl list -- -1)
++(! coredumpctl list '')
++(! coredumpctl info /../.~=)
++(! coredumpctl info '')
++(! coredumpctl dump --output=/dev/full "$CORE_TEST_BIN")
++(! coredumpctl dump --output=/dev/null --output=/dev/null "$CORE_TEST_BIN")
++(! coredumpctl debug --debugger=/bin/false)
diff -Nru systemd-247.3/debian/patches/series systemd-247.3/debian/patches/series
--- systemd-247.3/debian/patches/series	2024-08-25 16:05:15.000000000 -0300
+++ systemd-247.3/debian/patches/series	2025-06-25 21:44:53.000000000 -0300
@@ -69,3 +69,8 @@
 0001-resolved-actually-check-authenticated-flag-of-SOA-tr.patch
 0002-resolved-limit-the-number-of-signature-validations-i.patch
 0003-resolved-reduce-the-maximum-nsec3-iterations-to-100.patch
+CVE-2025-4598-0.patch
+CVE-2025-4598-1.patch
+CVE-2025-4598-2.patch
+CVE-2025-4598-3.patch
+CVE-2025-4598-4.patch
diff -Nru systemd-247.3/debian/salsa-ci.yml systemd-247.3/debian/salsa-ci.yml
--- systemd-247.3/debian/salsa-ci.yml	1969-12-31 21:00:00.000000000 -0300
+++ systemd-247.3/debian/salsa-ci.yml	2025-06-25 21:44:53.000000000 -0300
@@ -0,0 +1,4 @@
+---
+# (E)LTS CI
+include:
+- https://salsa.debian.org/lts-team/pipeline/raw/master/recipes/bullseye.yml

Reply via email to