import UBI systemd-252-55.el9_7.7

This commit is contained in:
eabdullin 2025-12-03 14:47:25 +00:00
parent 79e4d1719c
commit a80f066b12
21 changed files with 2016 additions and 1 deletions

View File

@ -0,0 +1,167 @@
From a8c056f2847f080e8ceb5d43fe0d36b5c5ee8655 Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
Date: Wed, 31 Jan 2024 13:11:21 +0100
Subject: [PATCH] cryptsetup: Add optional support for linking volume key in
keyring.
cryptsetup 2.7.0 adds feature to link effective volume key in custom
kernel keyring during device activation. It can be used later to pass
linked volume key to other services.
For example: kdump enabled systems installed on LUKS2 device.
This feature allows it to store volume key linked in a kernel keyring
to the kdump reserved memory and reuse it to reactivate LUKS2 device
in case of kernel crash.
(cherry picked from commit c5daf14c88ba44cefabe052de93a29d28b6b0175)
Resolves: RHEL-118294
---
man/crypttab.xml | 21 ++++++++++++
meson.build | 3 +-
src/cryptsetup/cryptsetup.c | 65 +++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/man/crypttab.xml b/man/crypttab.xml
index 1dd9bb1bb6..bd49e025fa 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -239,6 +239,27 @@
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>link-volume-key=</option></term>
+
+ <listitem><para>Specifies the kernel keyring and key description
+ (see <citerefentry project='man-pages'><refentrytitle>keyrings</refentrytitle><manvolnum>7</manvolnum></citerefentry>)
+ where LUKS2 volume key gets linked during device activation. The kernel keyring
+ description and key description must be separated by <literal>::</literal>.</para>
+
+ <para>The kernel keyring part can be a string description or a predefined
+ kernel keyring prefixed with <literal>@</literal> (e.g.: to use <literal>@s</literal> session or
+ <literal>@u</literal> user keyring directly). The type prefix text in the kernel keyring description
+ is not required. The specified kernel keyring must already exist at the time of device activation.</para>
+
+ <para>The key part is a string description optionally prefixed by a <literal>%key_type:</literal>.
+ If no type is specified, the <literal>user</literal> type key is linked by default. See
+ <citerefentry project='man-pages'><refentrytitle>keyctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for more information on key descriptions (KEY IDENTIFIERS section).</para>
+
+ <para>Note that the linked volume key is not cleaned up automatically when the device is detached.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>luks</option></term>
diff --git a/meson.build b/meson.build
index cbde702211..684324c6d7 100644
--- a/meson.build
+++ b/meson.build
@@ -1316,7 +1316,8 @@ if want_libcryptsetup != 'false' and not skip_deps
foreach ident : ['crypt_set_metadata_size',
'crypt_activate_by_signed_key',
- 'crypt_token_max']
+ 'crypt_token_max',
+ 'crypt_set_keyring_to_link']
have_ident = have and cc.has_function(
ident,
prefix : '#include <libcryptsetup.h>',
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 3f2cab1e41..f9130e2568 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -101,6 +101,9 @@ static bool arg_headless = false;
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
static unsigned arg_tpm2_measure_pcr = UINT_MAX; /* This and the following field is about measuring the unlocked volume key to the local TPM */
static char **arg_tpm2_measure_banks = NULL;
+static char *arg_link_keyring = NULL;
+static char *arg_link_key_type = NULL;
+static char *arg_link_key_description = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
@@ -113,6 +116,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_fido2_rp_id, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_banks, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
[PASSPHRASE_REGULAR] = "passphrase",
@@ -486,6 +492,56 @@ static int parse_one_option(const char *option) {
if (r < 0)
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
+ } else if ((val = startswith(option, "link-volume-key="))) {
+#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
+ const char *sep, *c;
+ _cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
+
+ /* Stick with cryptsetup --link-vk-to-keyring format
+ * <keyring_description>::%<key_type>:<key_description>,
+ * where %<key_type> is optional and defaults to 'user'.
+ */
+ if (!(sep = strstr(val, "::")))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %m");
+
+ /* cryptsetup (cli) supports <keyring_description> passed in various formats:
+ * - well-known keyrings prefixed with '@' (@u user, @s session, etc)
+ * - text descriptions prefixed with "%:" or "%keyring:".
+ * - text desription with no prefix.
+ * - numeric keyring id (ignored in current patch set). */
+ if (*val == '@' || *val == '%')
+ keyring = strndup(val, sep - val);
+ else
+ /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */
+ keyring = strnappend("%:", val, sep - val);
+ if (!keyring)
+ return log_oom();
+
+ sep += 2;
+
+ /* %<key_type> is optional (and defaults to 'user') */
+ if (*sep == '%') {
+ /* must be separated by colon */
+ if (!(c = strchr(sep, ':')))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %m");
+
+ key_type = strndup(sep + 1, c - sep - 1);
+ if (!key_type)
+ return log_oom();
+
+ sep = c + 1;
+ }
+
+ key_description = strdup(sep);
+ if (!key_description)
+ return log_oom();
+
+ free_and_replace(arg_link_keyring, keyring);
+ free_and_replace(arg_link_key_type, key_type);
+ free_and_replace(arg_link_key_description, key_description);
+#else
+ log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
+#endif
} else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
@@ -2207,6 +2263,15 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
+/* since cryptsetup 2.7.0 (Jan 2024) */
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
+ if (arg_link_key_description) {
+ r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
+ }
+#endif
+
if (arg_header) {
r = crypt_set_data_device(cd, source);
if (r < 0)

View File

@ -0,0 +1,27 @@
From 9807259b544cbf4f7a0a05bd426b95c788a89bd4 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 14 Feb 2024 04:01:36 +0900
Subject: [PATCH] cryptsetup: fix typo
Follow-up for c5daf14c88ba44cefabe052de93a29d28b6b0175.
(cherry picked from commit a14d3b48f7647676a0c43bceaecd56d9a77e3de6)
Resolves: RHEL-118294
---
src/cryptsetup/cryptsetup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index f9130e2568..1f672f19f1 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -507,7 +507,7 @@ static int parse_one_option(const char *option) {
/* cryptsetup (cli) supports <keyring_description> passed in various formats:
* - well-known keyrings prefixed with '@' (@u user, @s session, etc)
* - text descriptions prefixed with "%:" or "%keyring:".
- * - text desription with no prefix.
+ * - text description with no prefix.
* - numeric keyring id (ignored in current patch set). */
if (*val == '@' || *val == '%')
keyring = strndup(val, sep - val);

View File

@ -0,0 +1,27 @@
From 4920d1ca6823abe29e8cf2eceea497d9b677ee95 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 17 Aug 2025 21:05:24 +0900
Subject: [PATCH] cryptsetup: HAVE_CRYPT_SET_KEYRING_TO_LINK is always defined
Follow-up for c5daf14c88ba44cefabe052de93a29d28b6b0175 (v256).
(cherry picked from commit fb4aabf4432d523b97376099ce4353b5c268ae82)
Resolves: RHEL-118294
---
src/cryptsetup/cryptsetup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 1f672f19f1..4dc315e810 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -493,7 +493,7 @@ static int parse_one_option(const char *option) {
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
} else if ((val = startswith(option, "link-volume-key="))) {
-#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
const char *sep, *c;
_cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;

View File

@ -0,0 +1,51 @@
From 4d9bb355df2ba60d734a73a62bf489abbb8ec54c Mon Sep 17 00:00:00 2001
From: cpackham-atlnz <85916201+cpackham-atlnz@users.noreply.github.com>
Date: Tue, 12 Mar 2024 00:55:36 +1300
Subject: [PATCH] basic: add PIDFS magic (#31709)
Kernel commit cb12fd8e0dabb9a1c8aef55a6a41e2c255fcdf4b added pidfs.
Update filesystems-gperf.gperf and missing_magic.h accordingly.
This fixes the following error building against a bleeding edge kernel.
```
../src/basic/meson.build:234:8: ERROR: Problem encountered: Unknown filesystems defined in kernel headers:
Filesystem found in kernel header but not in filesystems-gperf.gperf: PID_FS_MAGIC
```
(cherry picked from commit ed01b92e1c92871bbd92711f280e2b2d15753f0e)
Resolves: RHEL-118294
---
src/basic/filesystems-gperf.gperf | 1 +
src/basic/missing_magic.h | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/src/basic/filesystems-gperf.gperf b/src/basic/filesystems-gperf.gperf
index e8c5357f91..1cd66b5a5f 100644
--- a/src/basic/filesystems-gperf.gperf
+++ b/src/basic/filesystems-gperf.gperf
@@ -91,6 +91,7 @@ ocfs2, {OCFS2_SUPER_MAGIC}
openpromfs, {OPENPROM_SUPER_MAGIC}
orangefs, {ORANGEFS_DEVREQ_MAGIC}
overlay, {OVERLAYFS_SUPER_MAGIC}
+pidfs, {PID_FS_MAGIC}
pipefs, {PIPEFS_MAGIC}
ppc-cmm, {PPC_CMM_MAGIC}
proc, {PROC_SUPER_MAGIC}
diff --git a/src/basic/missing_magic.h b/src/basic/missing_magic.h
index c104fcfba3..82ede1873e 100644
--- a/src/basic/missing_magic.h
+++ b/src/basic/missing_magic.h
@@ -128,6 +128,11 @@
#define DEVMEM_MAGIC 0x454d444d
#endif
+/* cb12fd8e0dabb9a1c8aef55a6a41e2c255fcdf4b (6.8) */
+#ifndef PID_FS_MAGIC
+#define PID_FS_MAGIC 0x50494446
+#endif
+
/* Not in mainline but included in Ubuntu */
#ifndef SHIFTFS_MAGIC
#define SHIFTFS_MAGIC 0x6a656a62

View File

@ -0,0 +1,74 @@
From a8ef307f05961e142b99cbbdda8855a24a44d4a1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 12 Mar 2023 20:57:16 +0900
Subject: [PATCH] time-util: make USEC_TIMESTAMP_FORMATTABLE_MAX for 32bit
system off by one day
As the same reason why we take one day off for 64bit case.
This also makes both upper bounds always defined for testing.
(cherry picked from commit bd5770da76ee157d3b31323ed2d22f5d9082bb36)
Related: RHEL-118294
---
src/basic/time-util.h | 14 +++++++++-----
src/test/test-date.c | 4 ++--
src/test/test-time-util.c | 2 +-
3 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 9d44cac747..7f8bda0948 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -200,13 +200,17 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
return usec_sub_unsigned(timestamp, (usec_t) delta);
}
+/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
+ * year territory. However, since we want to stay away from this in all timezones we take one day off. */
+#define USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT ((usec_t) 253402214399000000) /* Thu 9999-12-30 23:59:59 UTC */
+/* With a 32bit time_t we can't go beyond 2038...
+ * We parse timestamp with RFC-822/ISO 8601 (e.g. +06, or -03:00) as UTC, hence the upper bound must be off
+ * by USEC_PER_DAY. See parse_timestamp() for more details. */
+#define USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT (((usec_t) INT32_MAX) * USEC_PER_SEC - USEC_PER_DAY)
#if SIZEOF_TIME_T == 8
- /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
- * year territory. However, since we want to stay away from this in all timezones we take one day off. */
-# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
+# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT
#elif SIZEOF_TIME_T == 4
-/* With a 32bit time_t we can't go beyond 2038... */
-# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
+# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT
#else
# error "Yuck, time_t is neither 4 nor 8 bytes wide?"
#endif
diff --git a/src/test/test-date.c b/src/test/test-date.c
index cc11bd999e..ef316eeca7 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -104,8 +104,8 @@ int main(int argc, char *argv[]) {
test_should_fail("9999-12-31 00:00:00 UTC");
test_should_fail("10000-01-01 00:00:00 UTC");
#elif SIZEOF_TIME_T == 4
- test_should_pass("2038-01-19 03:14:07 UTC");
- test_should_fail("2038-01-19 03:14:08 UTC");
+ test_should_pass("2038-01-18 03:14:07 UTC");
+ test_should_fail("2038-01-18 03:14:08 UTC");
#endif
return 0;
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 21b05a3010..71ef5906ba 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -550,7 +550,7 @@ TEST(format_timestamp_utc) {
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Thu 9999-12-30 23:59:59 UTC");
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, "--- XXXX-XX-XX XX:XX:XX");
#elif SIZEOF_TIME_T == 4
- test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Tue 2038-01-19 03:14:07 UTC");
+ test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Mon 2038-01-18 03:14:07 UTC");
test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, "--- XXXX-XX-XX XX:XX:XX");
#endif

View File

@ -0,0 +1,34 @@
From a257453e7febc1c984b180e14095c2e6092dc850 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 31 Oct 2024 17:02:59 +0100
Subject: [PATCH] coredump: make check that all argv[] meta data fields are
passed strict
Otherwise, if some field is not supplied we might end up parsing a NULL
string later. Let's catch that early.
(cherry picked from commit 098c3975acb3df61eedfe471fca27c21f13cf04c)
Related: RHEL-104138
---
src/coredump/coredump.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index dca78fa72c..b24f4c8cc3 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1067,9 +1067,10 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
}
}
- if (!context->meta[META_ARGV_PID])
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to find the PID of crashing process");
+ /* The basic fields from argv[] should always be there, refuse early if not */
+ for (int i = 0; i < _META_ARGV_MAX; i++)
+ if (!context->meta[i])
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A required (%s) has not been sent, aborting.", meta_field_names[i]);
r = parse_pid(context->meta[META_ARGV_PID], &context->pid);
if (r < 0)

View File

@ -0,0 +1,122 @@
From de05f30a12a0f1ce03dc21a29a606c70e42d1de4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 29 Apr 2025 14:47:59 +0200
Subject: [PATCH] coredump: restore compatibility with older patterns
This was broken in f45b8015513d38ee5f7cc361db9c5b88c9aae704. Unfortunately
the review does not talk about backward compatibility at all. There are
two places where it matters:
- During upgrades, the replacement of kernel.core_pattern is asynchronous.
For example, during rpm upgrades, it would be updated a post-transaction
file trigger. In other scenarios, the update might only happen after
reboot. We have a potentially long window where the old pattern is in
place. We need to capture coredumps during upgrades too.
- With --backtrace. The interface of --backtrace, in hindsight, is not
great. But there are users of --backtrace which were written to use
a specific set of arguments, and we can't just break compatiblity.
One example is systemd-coredump-python, but there are also reports of
users using --backtrace to generate coredump logs.
Thus, we require the original set of args, and will use the additional args if
found.
A test is added to verify that --backtrace works with and without the optional
args.
(cherry picked from commit ded0aac389e647d35bce7ec4a48e718d77c0435b)
Related: RHEL-104138
---
src/coredump/coredump.c | 23 +++++++++++++++--------
test/units/testsuite-74.coredump.sh | 18 +++++++++++-------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index b24f4c8cc3..458857ffb2 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -94,8 +94,12 @@ enum {
META_ARGV_SIGNAL, /* %s: number of signal causing dump */
META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch (we expand this to µs granularity) */
META_ARGV_RLIMIT, /* %c: core file size soft resource limit */
- META_ARGV_HOSTNAME, /* %h: hostname */
+ _META_ARGV_REQUIRED,
+ /* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
+ META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
_META_ARGV_MAX,
+ /* If new fields are added, they should be added here, to maintain compatibility
+ * with callers which don't know about the new fields. */
/* The following indexes are cached for a couple of special fields we use (and
* thereby need to be retrieved quickly) for naming coredump files, and attaching
@@ -106,7 +110,7 @@ enum {
_META_MANDATORY_MAX,
/* The rest are similar to the previous ones except that we won't fail if one of
- * them is missing. */
+ * them is missing in a message sent over the socket. */
META_EXE = _META_MANDATORY_MAX,
META_UNIT,
@@ -1068,7 +1072,7 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
}
/* The basic fields from argv[] should always be there, refuse early if not */
- for (int i = 0; i < _META_ARGV_MAX; i++)
+ for (int i = 0; i < _META_ARGV_REQUIRED; i++)
if (!context->meta[i])
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A required (%s) has not been sent, aborting.", meta_field_names[i]);
@@ -1286,14 +1290,17 @@ static int gather_pid_metadata_from_argv(
char *t;
/* We gather all metadata that were passed via argv[] into an array of iovecs that
- * we'll forward to the socket unit */
+ * we'll forward to the socket unit.
+ *
+ * We require at least _META_ARGV_REQUIRED args, but will accept more.
+ * We know how to parse _META_ARGV_MAX args. The rest will be ignored. */
- if (argc < _META_ARGV_MAX)
+ if (argc < _META_ARGV_REQUIRED)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Not enough arguments passed by the kernel (%i, expected %i).",
- argc, _META_ARGV_MAX);
+ "Not enough arguments passed by the kernel (%i, expected between %i and %i).",
+ argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
- for (int i = 0; i < _META_ARGV_MAX; i++) {
+ for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
t = argv[i];
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
index 1093cad8a9..0163131096 100755
--- a/test/units/testsuite-74.coredump.sh
+++ b/test/units/testsuite-74.coredump.sh
@@ -218,14 +218,18 @@ rm -f /tmp/core.{output,redirected}
(! "${UNPRIV_CMD[@]}" coredumpctl dump "$CORE_TEST_BIN" >/dev/null)
# --backtrace mode
-# Pass one of the existing journal coredump records to systemd-coredump and
-# use our PID as the source to make matching the coredump later easier
-# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT HOSTNAME
+# Pass one of the existing journal coredump records to systemd-coredump.
+# Use our PID as the source to be able to create a PIDFD and to make matching easier.
+# systemd-coredump args: PID UID GID SIGNUM TIMESTAMP CORE_SOFT_RLIMIT [HOSTNAME]
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
- /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509994 12345 mymachine
-# Wait a bit for the coredump to get processed
-timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -eq 0 ]]; do sleep 1; done"
-coredumpctl info "$$"
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
+journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
+# Wait a bit for the coredumps to get processed
+timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
+coredumpctl info $$
+coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
+coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
coredumpctl info COREDUMP_HOSTNAME="mymachine"
# This used to cause a stack overflow

View File

@ -0,0 +1,158 @@
From 58550ccfee8cdf87e623aa70318a45a5e7c19901 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 29 Apr 2025 14:47:59 +0200
Subject: [PATCH] coredump: use %d in kernel core pattern
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The kernel provides %d which is documented as
"dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE".
We already query /proc/pid/auxv for this information, but unfortunately this
check is subject to a race, because the crashed process may be replaced by an
attacker before we read this data, for example replacing a SUID process that
was killed by a signal with another process that is not SUID, tricking us into
making the coredump of the original process readable by the attacker.
With this patch, we effectively add one more check to the list of conditions
that need be satisfied if we are to make the coredump accessible to the user.
Reportedy-by: Qualys Security Advisory <qsa@qualys.com>
In principle, %d might return a value other than 0, 1, or 2 in the future.
Thus, we accept those, but emit a notice.
(cherry picked from commit 0c49e0049b7665bb7769a13ef346fef92e1ad4d6)
Related: RHEL-104138
---
man/systemd-coredump.xml | 10 ++++++++++
src/coredump/coredump.c | 22 +++++++++++++++++++---
sysctl.d/50-coredump.conf.in | 2 +-
test/units/testsuite-74.coredump.sh | 5 +++++
4 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index cb9f47745b..6cfa04f466 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -259,6 +259,16 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>COREDUMP_DUMPABLE=</varname></term>
+
+ <listitem><para>The <constant>PR_GET_DUMPABLE</constant> field as reported by the kernel, see
+ <citerefentry
+ project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 458857ffb2..cd10678c43 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -97,7 +97,9 @@ enum {
_META_ARGV_REQUIRED,
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
+ META_ARGV_DUMPABLE, /* %d: as set by the kernel */
_META_ARGV_MAX,
+
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
@@ -126,6 +128,7 @@ static const char * const meta_field_names[_META_MAX] = {
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
+ [META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
[META_COMM] = "COREDUMP_COMM=",
[META_EXE] = "COREDUMP_EXE=",
[META_UNIT] = "COREDUMP_UNIT=",
@@ -138,6 +141,7 @@ typedef struct Context {
pid_t pid;
uid_t uid;
gid_t gid;
+ unsigned dumpable;
bool is_pid1;
bool is_journald;
} Context;
@@ -453,14 +457,16 @@ static int grant_user_access(int core_fd, const Context *context) {
if (r < 0)
return r;
- /* We allow access if we got all the data and at_secure is not set and
- * the uid/gid matches euid/egid. */
+ /* We allow access if %d/dumpable on the command line was exactly 1, we got all the data,
+ * at_secure is not set, and the uid/gid match euid/egid. */
bool ret =
+ context->dumpable == 1 &&
at_secure == 0 &&
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
- log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
+ log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
ret ? "permit" : "restrict",
+ context->dumpable,
uid, euid, gid, egid, yes_no(at_secure));
return ret;
}
@@ -1089,6 +1095,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
return log_error_errno(r, "Failed to parse GID \"%s\": %m", context->meta[META_ARGV_GID]);
+ /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2,
+ * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
+ if (context->meta[META_ARGV_DUMPABLE]) {
+ r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]);
+ if (context->dumpable > 2)
+ log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
+ }
+
unit = context->meta[META_UNIT];
context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
index 5fb551a8cf..9c10a89828 100644
--- a/sysctl.d/50-coredump.conf.in
+++ b/sysctl.d/50-coredump.conf.in
@@ -13,7 +13,7 @@
# the core dump.
#
# See systemd-coredump(8) and core(5).
-kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
+kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
# Allow 16 coredumps to be dispatched in parallel by the kernel.
# We collect metadata from /proc/%P/, and thus need to make sure the crashed
diff --git a/test/units/testsuite-74.coredump.sh b/test/units/testsuite-74.coredump.sh
index 0163131096..b72313672c 100755
--- a/test/units/testsuite-74.coredump.sh
+++ b/test/units/testsuite-74.coredump.sh
@@ -225,12 +225,17 @@ journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
+journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
+ /usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509902 12345 youmachine 1
# Wait a bit for the coredumps to get processed
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
coredumpctl info $$
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
coredumpctl info COREDUMP_HOSTNAME="mymachine"
+coredumpctl info COREDUMP_TIMESTAMP=1679509902000000
+coredumpctl info COREDUMP_HOSTNAME="youmachine"
+coredumpctl info COREDUMP_DUMPABLE="1"
# This used to cause a stack overflow
systemd-run -t --property CoredumpFilter=all ls /tmp

View File

@ -0,0 +1,230 @@
From c762a9a8764f8c6ce6640579ae8cf04f80360d16 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Sat, 9 Sep 2023 09:29:27 +0200
Subject: [PATCH] pidref: add structure that can reference a pid via both pidfd
and pid_t
Let's start with the conversion of PID 1 to pidfds. Let's add a simple
structure with just two fields that can be used to maintain a reference
to arbitrary processes via both pid_t and pidfd.
This is an embeddable struct, to keep it in line with where we
previously used a pid_t directly to track a process.
Of course, since this might contain an fd on systems where we have pidfd
this structure has a proper lifecycle.
(Note that this is quite different from sd_event_add_child() event
source objects as that one is only for child processes and collects
process results, while this infra is much simpler and more generic and
can be used to reference any process, anywhere in the tree.)
(cherry picked from commit 3bda3f17fa84557eeb28fa7c330cbd3a3f876d47)
Related: RHEL-104138
---
src/basic/meson.build | 1 +
src/basic/pidref.c | 145 ++++++++++++++++++++++++++++++++++++++++++
src/basic/pidref.h | 29 +++++++++
3 files changed, 175 insertions(+)
create mode 100644 src/basic/pidref.c
create mode 100644 src/basic/pidref.h
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 11053a5ecd..b8b4213c70 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -182,6 +182,7 @@ basic_sources = files(
'path-util.h',
'percent-util.c',
'percent-util.h',
+ 'pidref.c',
'prioq.c',
'prioq.h',
'proc-cmdline.c',
diff --git a/src/basic/pidref.c b/src/basic/pidref.c
new file mode 100644
index 0000000000..f41460938c
--- /dev/null
+++ b/src/basic/pidref.c
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "missing_syscall.h"
+#include "parse-util.h"
+#include "pidref.h"
+#include "process-util.h"
+
+int pidref_set_pid(PidRef *pidref, pid_t pid) {
+ int fd;
+
+ assert(pidref);
+
+ if (pid < 0)
+ return -ESRCH;
+ if (pid == 0)
+ pid = getpid_cached();
+
+ fd = pidfd_open(pid, 0);
+ if (fd < 0) {
+ /* Graceful fallback in case the kernel doesn't support pidfds or is out of fds */
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_RESOURCE(errno))
+ return -errno;
+
+ fd = -EBADF;
+ }
+
+ *pidref = (PidRef) {
+ .fd = fd,
+ .pid = pid,
+ };
+
+ return 0;
+}
+
+int pidref_set_pidstr(PidRef *pidref, const char *pid) {
+ pid_t nr;
+ int r;
+
+ assert(pidref);
+
+ r = parse_pid(pid, &nr);
+ if (r < 0)
+ return r;
+
+ return pidref_set_pid(pidref, nr);
+}
+
+int pidref_set_pidfd(PidRef *pidref, int fd) {
+ int r;
+
+ assert(pidref);
+
+ if (fd < 0)
+ return -EBADF;
+
+ int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (fd_copy < 0) {
+ pid_t pid;
+
+ if (!ERRNO_IS_RESOURCE(errno))
+ return -errno;
+
+ /* Graceful fallback if we are out of fds */
+ r = pidfd_get_pid(fd, &pid);
+ if (r < 0)
+ return r;
+
+ *pidref = (PidRef) {
+ .fd = -EBADF,
+ .pid = pid,
+ };
+
+ return 0;
+ }
+
+ return pidref_set_pidfd_consume(pidref, fd_copy);
+}
+
+int pidref_set_pidfd_take(PidRef *pidref, int fd) {
+ pid_t pid;
+ int r;
+
+ assert(pidref);
+
+ if (fd < 0)
+ return -EBADF;
+
+ r = pidfd_get_pid(fd, &pid);
+ if (r < 0)
+ return r;
+
+ *pidref = (PidRef) {
+ .fd = fd,
+ .pid = pid,
+ };
+
+ return 0;
+}
+
+int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
+ int r;
+
+ r = pidref_set_pidfd_take(pidref, fd);
+ if (r < 0)
+ safe_close(fd);
+
+ return r;
+}
+
+void pidref_done(PidRef *pidref) {
+ assert(pidref);
+
+ *pidref = (PidRef) {
+ .fd = safe_close(pidref->fd),
+ };
+}
+
+int pidref_kill(PidRef *pidref, int sig) {
+
+ if (!pidref)
+ return -ESRCH;
+
+ if (pidref->fd >= 0)
+ return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
+
+ if (pidref->pid > 0)
+ return RET_NERRNO(kill(pidref->pid, sig));
+
+ return -ESRCH;
+}
+
+int pidref_kill_and_sigcont(PidRef *pidref, int sig) {
+ int r;
+
+ r = pidref_kill(pidref, sig);
+ if (r < 0)
+ return r;
+
+ if (!IN_SET(sig, SIGCONT, SIGKILL))
+ (void) pidref_kill(pidref, SIGCONT);
+
+ return 0;
+}
diff --git a/src/basic/pidref.h b/src/basic/pidref.h
new file mode 100644
index 0000000000..2411e510f1
--- /dev/null
+++ b/src/basic/pidref.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "macro.h"
+
+/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continously. */
+typedef struct PidRef {
+ pid_t pid; /* always valid */
+ int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd */
+} PidRef;
+
+#define PIDREF_NULL (PidRef) { .fd = -EBADF }
+
+static inline bool pidref_is_set(const PidRef *pidref) {
+ return pidref && pidref->pid > 0;
+}
+
+int pidref_set_pid(PidRef *pidref, pid_t pid);
+int pidref_set_pidstr(PidRef *pidref, const char *pid);
+int pidref_set_pidfd(PidRef *pidref, int fd);
+int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success*/
+int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */
+
+void pidref_done(PidRef *pidref);
+
+int pidref_kill(PidRef *pidref, int sig);
+int pidref_kill_and_sigcont(PidRef *pidref, int sig);
+
+#define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL)

View File

@ -0,0 +1,54 @@
From 9cf24f219925df6e449eb0838af6e309d84cbb0c Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 5 May 2023 08:09:14 +0200
Subject: [PATCH] fd-util: introduce parse_fd()
It's a simple wrapper for safe_atoi() that returns error if the parsed
fd is < 0 .
(cherry picked from commit b8f83d7f0c35dca6ca3a23c42215d566e2815ca5)
Related: RHEL-104138
---
src/basic/parse-util.c | 15 +++++++++++++++
src/basic/parse-util.h | 1 +
2 files changed, 16 insertions(+)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 3b3efb0ab8..4161211c49 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -313,6 +313,21 @@ int parse_errno(const char *t) {
return e;
}
+int parse_fd(const char *t) {
+ int r, fd;
+
+ assert(t);
+
+ r = safe_atoi(t, &fd);
+ if (r < 0)
+ return r;
+
+ if (fd < 0)
+ return -ERANGE;
+
+ return fd;
+}
+
static const char *mangle_base(const char *s, unsigned *base) {
const char *k;
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 8d8d52327b..5c012d702a 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -20,6 +20,7 @@ int parse_mtu(int family, const char *s, uint32_t *ret);
int parse_size(const char *t, uint64_t base, uint64_t *size);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
int parse_errno(const char *t);
+int parse_fd(const char *t);
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)

View File

@ -0,0 +1,245 @@
From bbd5aec472b90aa55e184f58691085142b7e3aaa Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@gmail.com>
Date: Sun, 13 Apr 2025 22:10:36 +0100
Subject: [PATCH] coredump: add support for new %F PIDFD specifier
A new core_pattern specifier was added, %F, to provide a PIDFD
to the usermode helper process referring to the crashed process.
This removes all possible race conditions, ensuring only the
crashed process gets inspected by systemd-coredump.
(cherry picked from commit 868d95577ec9f862580ad365726515459be582fc)
Resolves: RHEL-104138
---
man/systemd-coredump.xml | 9 ++++
src/coredump/coredump.c | 89 ++++++++++++++++++++++++++++++++----
sysctl.d/50-coredump.conf.in | 2 +-
3 files changed, 89 insertions(+), 11 deletions(-)
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 6cfa04f466..b3d81d838a 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -186,6 +186,15 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>COREDUMP_BY_PIDFD=</varname></term>
+ <listitem><para>If the crashed process was analyzed using a PIDFD provided by the kernel (requires
+ kernel v6.16) then this field will be present and set to <literal>1</literal>. If this field is
+ not set, then the crashed process was analyzed via a PID, which is known to be subject to race
+ conditions.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>COREDUMP_TIMESTAMP=</varname></term>
<listitem><para>The time of the crash as reported by the kernel (in µs since the epoch).</para>
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index cd10678c43..e0aac3c8d0 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -39,6 +39,7 @@
#include "mkdir-label.h"
#include "namespace-util.h"
#include "parse-util.h"
+#include "pidref.h"
#include "process-util.h"
#include "signal-util.h"
#include "socket-util.h"
@@ -98,8 +99,8 @@ enum {
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
META_ARGV_DUMPABLE, /* %d: as set by the kernel */
+ META_ARGV_PIDFD, /* %F: pidfd of the process, since v6.16 */
_META_ARGV_MAX,
-
/* If new fields are added, they should be added here, to maintain compatibility
* with callers which don't know about the new fields. */
@@ -129,6 +130,7 @@ static const char * const meta_field_names[_META_MAX] = {
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
[META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
+ [META_ARGV_PIDFD] = "COREDUMP_BY_PIDFD=",
[META_COMM] = "COREDUMP_COMM=",
[META_EXE] = "COREDUMP_EXE=",
[META_UNIT] = "COREDUMP_UNIT=",
@@ -136,6 +138,7 @@ static const char * const meta_field_names[_META_MAX] = {
};
typedef struct Context {
+ PidRef pidref;
const char *meta[_META_MAX];
size_t meta_size[_META_MAX];
pid_t pid;
@@ -146,6 +149,14 @@ typedef struct Context {
bool is_journald;
} Context;
+#define CONTEXT_NULL \
+ (Context) { \
+ .pidref = PIDREF_NULL, \
+ .uid = UID_INVALID, \
+ .gid = GID_INVALID, \
+ }
+
+
typedef enum CoredumpStorage {
COREDUMP_STORAGE_NONE,
COREDUMP_STORAGE_EXTERNAL,
@@ -171,6 +182,12 @@ static uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX;
static uint64_t arg_keep_free = UINT64_MAX;
static uint64_t arg_max_use = UINT64_MAX;
+static void context_done(Context *c) {
+ assert(c);
+
+ pidref_done(&c->pidref);
+}
+
static int parse_config(void) {
static const ConfigTableItem items[] = {
{ "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
@@ -1114,7 +1131,7 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
static int process_socket(int fd) {
_cleanup_close_ int input_fd = -EBADF, mntns_fd = -EBADF;
- Context context = {};
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
struct iovec_wrapper iovw = {};
struct iovec iovec;
int iterations = 0, r;
@@ -1215,7 +1232,7 @@ static int process_socket(int fd) {
goto finish;
/* Make sure we received at least all fields we need. */
- for (int i = 0; i < _META_MANDATORY_MAX; i++)
+ for (int i = 0; i < _META_ARGV_REQUIRED; i++)
if (!context.meta[i]) {
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"A mandatory argument (%i) has not been sent, aborting.",
@@ -1301,9 +1318,9 @@ static int gather_pid_metadata_from_argv(
Context *context,
int argc, char **argv) {
+ _cleanup_(pidref_done) PidRef local_pidref = PIDREF_NULL;
_cleanup_free_ char *free_timestamp = NULL;
- int r, signo;
- char *t;
+ int r, signo, kernel_fd = -EBADF;
/* We gather all metadata that were passed via argv[] into an array of iovecs that
* we'll forward to the socket unit.
@@ -1317,8 +1334,7 @@ static int gather_pid_metadata_from_argv(
argc, _META_ARGV_REQUIRED, _META_ARGV_MAX);
for (int i = 0; i < MIN(argc, _META_ARGV_MAX); i++) {
-
- t = argv[i];
+ const char *t = argv[i];
switch (i) {
@@ -1343,6 +1359,47 @@ static int gather_pid_metadata_from_argv(
break;
}
+ if (i == META_ARGV_PID) {
+ /* Store this so that we can check whether the core will be forwarded to a container
+ * even when the kernel doesn't provide a pidfd. Can be dropped once baseline is
+ * >= v6.16. */
+ r = pidref_set_pidstr(&local_pidref, t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to initialize pidref from pid %s: %m", t);
+ }
+
+ if (i == META_ARGV_PIDFD) {
+ /* If the current kernel doesn't support the %F specifier (which resolves to a
+ * pidfd), but we included it in the core_pattern expression, we'll receive an empty
+ * string here. Deal with that gracefully. */
+ if (isempty(t))
+ continue;
+
+ assert(!pidref_is_set(&context->pidref));
+ assert(kernel_fd < 0);
+
+ kernel_fd = parse_fd(t);
+ if (kernel_fd < 0)
+ return log_error_errno(kernel_fd, "Failed to parse pidfd \"%s\": %m", t);
+
+ r = pidref_set_pidfd(&context->pidref, kernel_fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to initialize pidref from pidfd %d: %m", kernel_fd);
+
+ /* If there are containers involved with different versions of the code they might
+ * not be using pidfds, so it would be wrong to set the metadata, skip it. */
+ r = in_same_namespace(getpid_cached(), context->pidref.pid, NAMESPACE_PID);
+ if (r < 0)
+ log_debug_errno(r, "Failed to check pidns of crashing process, ignoring: %m");
+ if (r <= 0)
+ continue;
+
+ /* We don't print the fd number in the journal as it's meaningless, but we still
+ * record that the parsing was done with a kernel-provided fd as it means it's safe
+ * from races, which is valuable information to provide in the journal record. */
+ t = "1";
+ }
+
r = iovw_put_string_field(iovw, meta_field_names[i], t);
if (r < 0)
return r;
@@ -1350,7 +1407,19 @@ static int gather_pid_metadata_from_argv(
/* Cache some of the process metadata we collected so far and that we'll need to
* access soon */
- return save_context(context, iovw);
+ r = save_context(context, iovw);
+ if (r < 0)
+ return r;
+
+ /* If the kernel didn't give us a PIDFD, then use the one derived from the
+ * PID immediately, given we have it. */
+ if (!pidref_is_set(&context->pidref))
+ context->pidref = TAKE_PIDREF(local_pidref);
+
+ /* Close the kernel-provided FD as the last thing after everything else succeeded. */
+ kernel_fd = safe_close(kernel_fd);
+
+ return 0;
}
static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
@@ -1466,7 +1535,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
}
static int process_kernel(int argc, char* argv[]) {
- Context context = {};
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
struct iovec_wrapper *iovw;
int r, mntns_fd = -EBADF;
@@ -1543,7 +1612,7 @@ static int process_kernel(int argc, char* argv[]) {
}
static int process_backtrace(int argc, char *argv[]) {
- Context context = {};
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
struct iovec_wrapper *iovw;
char *message;
int r;
diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
index 9c10a89828..1c6230ad93 100644
--- a/sysctl.d/50-coredump.conf.in
+++ b/sysctl.d/50-coredump.conf.in
@@ -13,7 +13,7 @@
# the core dump.
#
# See systemd-coredump(8) and core(5).
-kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
+kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d %F
# Allow 16 coredumps to be dispatched in parallel by the kernel.
# We collect metadata from /proc/%P/, and thus need to make sure the crashed

View File

@ -0,0 +1,99 @@
From 1e97dc426766eef1590d9054952aa0d7d5882b79 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 23 Sep 2025 14:28:33 +0200
Subject: [PATCH] test: rename TEST-53-ISSUE-16347 to TEST-53-TIMER
And split the existing test into a separate subtest.
(cherry picked from commit 953c347fb6f293acbd6da009646bfc071b68ddd7)
Related: RHEL-127022
---
.../Makefile | 0
.../test.sh | 0
test/units/testsuite-53.issue-16347.sh | 27 ++++++++++++++++++
test/units/testsuite-53.sh | 28 +++----------------
4 files changed, 31 insertions(+), 24 deletions(-)
rename test/{TEST-53-ISSUE-16347 => TEST-53-TIMER}/Makefile (100%)
rename test/{TEST-53-ISSUE-16347 => TEST-53-TIMER}/test.sh (100%)
create mode 100755 test/units/testsuite-53.issue-16347.sh
diff --git a/test/TEST-53-ISSUE-16347/Makefile b/test/TEST-53-TIMER/Makefile
similarity index 100%
rename from test/TEST-53-ISSUE-16347/Makefile
rename to test/TEST-53-TIMER/Makefile
diff --git a/test/TEST-53-ISSUE-16347/test.sh b/test/TEST-53-TIMER/test.sh
similarity index 100%
rename from test/TEST-53-ISSUE-16347/test.sh
rename to test/TEST-53-TIMER/test.sh
diff --git a/test/units/testsuite-53.issue-16347.sh b/test/units/testsuite-53.issue-16347.sh
new file mode 100755
index 0000000000..8b266145cd
--- /dev/null
+++ b/test/units/testsuite-53.issue-16347.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+# Reset host date to current time, 3 days in the past.
+date -s "-3 days"
+trap 'date -s "+3 days"' EXIT
+
+# Run a timer for every 15 minutes.
+systemd-run --unit test-timer --on-calendar "*:0/15:0" true
+
+next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value)
+next_elapsed=$(date -d "${next_elapsed}" +%s)
+now=$(date +%s)
+time_delta=$((next_elapsed - now))
+
+# Check that the timer will elapse in less than 20 minutes.
+if [[ "$time_delta" -lt 0 || "$time_delta" -gt 1200 ]]; then
+ echo 'Timer elapse outside of the expected 20 minute window.'
+ echo " next_elapsed=${next_elapsed}"
+ echo " now=${now}"
+ echo " time_delta=${time_delta}"
+ echo
+
+ exit 1
+fi
diff --git a/test/units/testsuite-53.sh b/test/units/testsuite-53.sh
index 84cd66129d..9c2a033aa9 100755
--- a/test/units/testsuite-53.sh
+++ b/test/units/testsuite-53.sh
@@ -3,29 +3,9 @@
set -eux
set -o pipefail
-: >/failed
+# shellcheck source=test/units/test-control.sh
+. "$(dirname "$0")"/test-control.sh
-# Reset host date to current time, 3 days in the past.
-date -s "-3 days"
+run_subtests
-# Run a timer for every 15 minutes.
-systemd-run --unit test-timer --on-calendar "*:0/15:0" true
-
-next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value)
-next_elapsed=$(date -d "${next_elapsed}" +%s)
-now=$(date +%s)
-time_delta=$((next_elapsed - now))
-
-# Check that the timer will elapse in less than 20 minutes.
-((0 < time_delta && time_delta < 1200)) || {
- echo 'Timer elapse outside of the expected 20 minute window.'
- echo " next_elapsed=${next_elapsed}"
- echo " now=${now}"
- echo " time_delta=${time_delta}"
- echo ''
-} >>/failed
-
-if test ! -s /failed ; then
- rm -f /failed
- touch /testok
-fi
+touch /testok

View File

@ -0,0 +1,101 @@
From 9fbd356a6453822d0472d8f1488adfc902a8d241 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 23 Sep 2025 17:42:01 +0200
Subject: [PATCH] test: restarting elapsed timer shouldn't trigger the
corresponding service
Provides coverage for:
- https://github.com/systemd/systemd/issues/31231
- https://github.com/systemd/systemd/issues/35805
(cherry picked from commit 5730a400fd5ee82566fe03eb832121a0d4bc26b6)
Related: RHEL-127022
---
test/units/testsuite-53.restart-trigger.sh | 77 ++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100755 test/units/testsuite-53.restart-trigger.sh
diff --git a/test/units/testsuite-53.restart-trigger.sh b/test/units/testsuite-53.restart-trigger.sh
new file mode 100755
index 0000000000..057f379ddc
--- /dev/null
+++ b/test/units/testsuite-53.restart-trigger.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Restarting an already elapsed timer shouldn't immediately trigger the corresponding service unit.
+#
+# Provides coverage for:
+# - https://github.com/systemd/systemd/issues/31231
+# - https://github.com/systemd/systemd/issues/35805
+set -eux
+set -o pipefail
+
+# shellcheck source=test/units/test-control.sh
+. "$(dirname "$0")"/util.sh
+
+UNIT_NAME="timer-restart-$RANDOM"
+TEST_MESSAGE="Hello from timer $RANDOM"
+
+# Setup
+cat >"/run/systemd/system/$UNIT_NAME.timer" <<EOF
+[Timer]
+OnCalendar=$(date --date="+1 hour" "+%Y-%m-%d %H:%M:%S")
+AccuracySec=1s
+EOF
+
+cat >"/run/systemd/system/$UNIT_NAME.service" <<EOF
+[Service]
+ExecStart=echo "$TEST_MESSAGE"
+EOF
+
+systemctl daemon-reload
+
+JOURNAL_TS="$(date "+%s")"
+# Paranoia check that the test message is not already in the logs
+(! journalctl -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE")
+
+# Restart time timer and move time forward by 2 hours to trigger the timer
+systemctl restart "$UNIT_NAME.timer"
+systemctl status "$UNIT_NAME.timer"
+
+date -s '+2 hours'
+trap 'date -s "-2 hours"' EXIT
+sleep 1
+systemctl status "$UNIT_NAME.timer"
+assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
+
+# Restarting the timer unit shouldn't trigger neither the timer nor the service, so these
+# fields should remain constant through the following tests
+SERVICE_INV_ID="$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
+TIMER_LAST_TRIGGER="$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+
+# Now restart the timer and check if the timer and the service weren't triggered again
+systemctl restart "$UNIT_NAME.timer"
+sleep 5
+assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
+assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
+assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+
+# Set the timer into the past, restart it, and again check if it wasn't triggered
+TIMER_TS="$(date --date="-1 day" "+%Y-%m-%d %H:%M:%S")"
+mkdir "/run/systemd/system/$UNIT_NAME.timer.d/"
+cat >"/run/systemd/system/$UNIT_NAME.timer.d/99-override.conf" <<EOF
+[Timer]
+OnCalendar=$TIMER_TS
+EOF
+systemctl daemon-reload
+systemctl status "$UNIT_NAME.timer"
+assert_in "OnCalendar=$TIMER_TS" "$(systemctl show -P TimersCalendar "$UNIT_NAME".timer)"
+systemctl restart "$UNIT_NAME.timer"
+sleep 5
+assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
+assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
+assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+
+# Cleanup
+systemctl stop "$UNIT_NAME".{timer,service}
+rm -f "/run/systemd/system/$UNIT_NAME".{timer,service}
+systemctl daemon-reload

View File

@ -0,0 +1,156 @@
From c282dc4e58279b4db6f735228e210a6e46ec5638 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 23 Sep 2025 21:04:12 +0200
Subject: [PATCH] test: check the next elapse timer timestamp after
deserialization
When deserializing a serialized timer unit with RandomizedDelaySec= set,
systemd should use the last inactive exit timestamp instead of current
realtime to calculate the new next elapse, so the timer unit actually
runs in the given calendar window.
Provides coverage for:
- https://github.com/systemd/systemd/issues/18678
- https://github.com/systemd/systemd/pull/27752
(cherry picked from commit f4c3c107d9be4e922a080fc292ed3889c4e0f4a5)
Related: RHEL-127022
---
.../testsuite-53.RandomizedDelaySec-reload.sh | 97 +++++++++++++++++++
test/units/util.sh | 18 ++++
2 files changed, 115 insertions(+)
create mode 100755 test/units/testsuite-53.RandomizedDelaySec-reload.sh
diff --git a/test/units/testsuite-53.RandomizedDelaySec-reload.sh b/test/units/testsuite-53.RandomizedDelaySec-reload.sh
new file mode 100755
index 0000000000..08f4f469d6
--- /dev/null
+++ b/test/units/testsuite-53.RandomizedDelaySec-reload.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# When deserializing a serialized timer unit with RandomizedDelaySec= set, systemd should use the last
+# inactive exit timestamp instead of current realtime to calculate the new next elapse, so the timer unit
+# actually runs in the given calendar window.
+#
+# Provides coverage for:
+# - https://github.com/systemd/systemd/issues/18678
+# - https://github.com/systemd/systemd/pull/27752
+set -eux
+set -o pipefail
+
+# shellcheck source=test/units/test-control.sh
+. "$(dirname "$0")"/util.sh
+
+UNIT_NAME="timer-RandomizedDelaySec-$RANDOM"
+TARGET_TS="$(date --date="tomorrow 00:10")"
+TARGET_TS_S="$(date --date="$TARGET_TS" "+%s")"
+# Maximum possible next elapse timestamp: $TARGET_TS (OnCalendar=) + 22 hours (RandomizedDelaySec=)
+MAX_NEXT_ELAPSE_REALTIME_S="$((TARGET_TS_S + 22 * 60 * 60))"
+MAX_NEXT_ELAPSE_REALTIME="$(date --date="@$MAX_NEXT_ELAPSE_REALTIME_S")"
+
+# Let's make sure to return the date & time back to the original state once we're done with our time
+# shenigans. One way to do this would be to use hwclock, but the RTC in VMs can be unreliable or slow to
+# respond, causing unexpected test fails/timeouts.
+#
+# Instead, let's save the realtime timestamp before we start with the test together with a current monotonic
+# timestamp, after the test ends take the difference between the current monotonic timestamp and the "start"
+# one, add it to the originally saved realtime timestamp, and finally use that timestamp to set the system
+# time. This should advance the system time by the amount of time the test actually ran, and hence restore it
+# to some sane state after the time jumps performed by the test. It won't be perfect, but it should be close
+# enough for our needs.
+START_REALTIME="$(date "+%s")"
+START_MONOTONIC="$(cut -d . -f 1 /proc/uptime)"
+at_exit() {
+ : "Restore the system date to a sane state"
+ END_MONOTONIC="$(cut -d . -f 1 /proc/uptime)"
+ date --set="@$((START_REALTIME + END_MONOTONIC - START_MONOTONIC))"
+}
+trap at_exit EXIT
+
+# Set some predictable time so we can schedule the first timer elapse in a deterministic-ish way
+date --set="23:00"
+
+# Setup
+cat >"/run/systemd/system/$UNIT_NAME.timer" <<EOF
+[Timer]
+# Run this timer daily, ten minutes after midnight
+OnCalendar=*-*-* 00:10:00
+RandomizedDelaySec=22h
+AccuracySec=1ms
+EOF
+
+cat >"/run/systemd/system/$UNIT_NAME.service" <<EOF
+[Service]
+ExecStart=echo "Hello world"
+EOF
+
+systemctl daemon-reload
+
+check_elapse_timestamp() {
+ systemctl status "$UNIT_NAME.timer"
+ systemctl show -p InactiveExitTimestamp "$UNIT_NAME.timer"
+
+ NEXT_ELAPSE_REALTIME="$(systemctl show -P NextElapseUSecRealtime "$UNIT_NAME.timer")"
+ NEXT_ELAPSE_REALTIME_S="$(date --date="$NEXT_ELAPSE_REALTIME" "+%s")"
+ : "Next elapse timestamp should be $TARGET_TS <= $NEXT_ELAPSE_REALTIME <= $MAX_NEXT_ELAPSE_REALTIME"
+ assert_ge "$NEXT_ELAPSE_REALTIME_S" "$TARGET_TS_S"
+ assert_le "$NEXT_ELAPSE_REALTIME_S" "$MAX_NEXT_ELAPSE_REALTIME_S"
+}
+
+# Restart the timer unit and check the initial next elapse timestamp
+: "Initial next elapse timestamp"
+systemctl restart "$UNIT_NAME.timer"
+check_elapse_timestamp
+
+# Bump the system date to 1 minute after the original calendar timer would've expired (without any random
+# delay!) - systemd should recalculate the next elapse timestamp with a new randomized delay, but it should
+# use the original inactive exit timestamp as a "base", so the final timestamp should not end up beyond the
+# original calendar timestamp + randomized delay range.
+#
+# Similarly, do the same check after doing daemon-reload, as that also forces systemd to recalculate the next
+# elapse timestamp (this goes through a slightly different codepath that actually contained the original
+# issue).
+: "Next elapse timestamp after time jump"
+date -s "tomorrow 00:11"
+check_elapse_timestamp
+
+: "Next elapse timestamp after daemon-reload"
+systemctl daemon-reload
+check_elapse_timestamp
+
+# Cleanup
+systemctl stop "$UNIT_NAME".{timer,service}
+rm -f "/run/systemd/system/$UNIT_NAME".{timer,service}
+systemctl daemon-reload
diff --git a/test/units/util.sh b/test/units/util.sh
index 00b8c5e393..5728b324a9 100755
--- a/test/units/util.sh
+++ b/test/units/util.sh
@@ -26,6 +26,24 @@ assert_eq() {(
fi
)}
+assert_le() {(
+ set +ex
+
+ if [[ "${1:?}" -gt "${2:?}" ]]; then
+ echo "FAIL: '$1' > '$2'" >&2
+ exit 1
+ fi
+)}
+
+assert_ge() {(
+ set +ex
+
+ if [[ "${1:?}" -lt "${2:?}" ]]; then
+ echo "FAIL: '$1' < '$2'" >&2
+ exit 1
+ fi
+)}
+
assert_in() {(
set +ex

View File

@ -0,0 +1,29 @@
From 7dc588429e48ba6017fd75f6a266288768230025 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Tue, 9 Sep 2025 15:24:22 +0200
Subject: [PATCH] timer: don't run service immediately after restart of a timer
When a timer is restarted, don't reset the last_trigger field.
This prevents the timer from triggering immediately.
Fixes: #31231
(cherry picked from commit 3fc44a0f68412b649e16f12ff2f97a36c615457d)
Resolves: RHEL-127022
---
src/core/timer.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index 60e8fea79f..2eadca4f1a 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -635,8 +635,6 @@ static int timer_start(Unit *u) {
if (r < 0)
return r;
- t->last_trigger = DUAL_TIMESTAMP_NULL;
-
/* Reenable all timers that depend on unit activation time */
LIST_FOREACH(value, v, t->values)
if (v->base == TIMER_ACTIVE)

View File

@ -0,0 +1,49 @@
From 5f0eda80175f04929c34cdb46cd85e3f4d64b6d1 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 29 Sep 2025 16:11:27 +0200
Subject: [PATCH] test: store and compare just the property value
Follow-up for 5730a400fd5ee82566fe03eb832121a0d4bc26b6.
(cherry picked from commit 0cb252d50f35256bff569fa6213784f2d45ad6a1)
Related: RHEL-127022
---
test/units/testsuite-53.restart-trigger.sh | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/units/testsuite-53.restart-trigger.sh b/test/units/testsuite-53.restart-trigger.sh
index 057f379ddc..e5cd575d66 100755
--- a/test/units/testsuite-53.restart-trigger.sh
+++ b/test/units/testsuite-53.restart-trigger.sh
@@ -45,15 +45,15 @@ assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --
# Restarting the timer unit shouldn't trigger neither the timer nor the service, so these
# fields should remain constant through the following tests
-SERVICE_INV_ID="$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
-TIMER_LAST_TRIGGER="$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+SERVICE_INV_ID="$(systemctl show -P InvocationID "$UNIT_NAME.service")"
+TIMER_LAST_TRIGGER="$(systemctl show -P LastTriggerUSec "$UNIT_NAME.timer")"
# Now restart the timer and check if the timer and the service weren't triggered again
systemctl restart "$UNIT_NAME.timer"
sleep 5
assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
-assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
-assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+assert_eq "$SERVICE_INV_ID" "$(systemctl show -P InvocationID "$UNIT_NAME.service")"
+assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show -P LastTriggerUSec "$UNIT_NAME.timer")"
# Set the timer into the past, restart it, and again check if it wasn't triggered
TIMER_TS="$(date --date="-1 day" "+%Y-%m-%d %H:%M:%S")"
@@ -68,8 +68,8 @@ assert_in "OnCalendar=$TIMER_TS" "$(systemctl show -P TimersCalendar "$UNIT_NAME
systemctl restart "$UNIT_NAME.timer"
sleep 5
assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
-assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
-assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
+assert_eq "$SERVICE_INV_ID" "$(systemctl show -P InvocationID "$UNIT_NAME.service")"
+assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show -P LastTriggerUSec "$UNIT_NAME.timer")"
# Cleanup
systemctl stop "$UNIT_NAME".{timer,service}

View File

@ -0,0 +1,131 @@
From e71140d217b3a2a75a52b488da39568d6ea942bd Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Mon, 13 Oct 2025 17:36:55 +0200
Subject: [PATCH] timer: rebase the next elapse timestamp only if timer didn't
already run
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The test added in f4c3c107d9be4e922a080fc292ed3889c4e0f4a5 uncovered a
corner case while recalculating the next elapse timestamp of a timer unit
that uses RandomizedDelaySec= during deserialization.
If the scheduled time (without RandomizedDelaySec=) already elapsed,
systemd "rebases" the next elapse timestamp to the time when systemd
first started, to make the RandomizedDelaySec= feature work even at
boot. However, since it was done unconditionally, it always overrode the
next elapse timestamp, which could then cause the final next elapse
timestamp to fall out of the expected window.
With a couple of additional debug logs one of the test fail looks like
this:
[ 132.129815] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp after daemon-reload, try #328'
[ 132.129815] TEST-53-TIMER.sh[384]: + systemctl daemon-reload
[ 132.136352] systemd[1]: Reload requested from client PID 16399 ('systemctl') (unit TEST-53-TIMER.service)...
[ 132.136636] systemd[1]: Reloading...
[ 132.446160] systemd[1]: Rebasing next elapse timestamp
[ 132.446168] systemd[1]: v->next_elapse: Tue 2025-10-14 00:10:00 CEST
[ 132.446170] systemd[1]: rebased: Tue 2025-10-14 00:10:56 CEST
[ 132.446172] systemd[1]: v->next_elapse after rebase: Tue 2025-10-14 00:10:56 CEST
[ 132.447361] systemd[1]: Reloading finished in 310 ms.
[ 132.484041] TEST-53-TIMER.sh[384]: + check_elapse_timestamp
[ 132.484041] TEST-53-TIMER.sh[384]: + systemctl status timer-RandomizedDelaySec-16377.timer
[ 132.533657] TEST-53-TIMER.sh[16440]: ● timer-RandomizedDelaySec-16377.timer
[ 132.533657] TEST-53-TIMER.sh[16440]: Loaded: loaded (/run/systemd/system/timer-RandomizedDelaySec-16377.timer; static)
[ 132.533657] TEST-53-TIMER.sh[16440]: Active: active (waiting) since Mon 2025-10-13 23:00:00 CEST; 1h 13min ago
[ 132.533657] TEST-53-TIMER.sh[16440]: Invocation: 5555d4f060114a5493ff228013830d17
[ 132.533657] TEST-53-TIMER.sh[16440]: Trigger: Tue 2025-10-14 22:10:04 CEST; 21h left
[ 132.533657] TEST-53-TIMER.sh[16440]: Triggers: ● timer-RandomizedDelaySec-16377.service
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 15h 35min 1.230173s random time.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 15:45:58 CEST.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 16h 29min 44.084409s random time.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 16:40:41 CEST.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 21h 59min 7.955828s random time.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 22:10:04 CEST.
[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting
[ 132.535386] TEST-53-TIMER.sh[384]: + systemctl show -p InactiveExitTimestamp timer-RandomizedDelaySec-16377.timer
[ 132.537727] TEST-53-TIMER.sh[16442]: InactiveExitTimestamp=Mon 2025-10-13 23:00:00 CEST
[ 132.540317] TEST-53-TIMER.sh[16444]: ++ systemctl show -P NextElapseUSecRealtime timer-RandomizedDelaySec-16377.timer
[ 132.547745] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME='Tue 2025-10-14 22:10:04 CEST'
[ 132.548020] TEST-53-TIMER.sh[16445]: ++ date '--date=Tue 2025-10-14 22:10:04 CEST' +%s
[ 132.550218] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME_S=1760472604
[ 132.550218] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp should be Tue 2025-10-14 00:10:00 CEST <= Tue 2025-10-14 22:10:04 CEST <= Tue 2025-10-14 22:10:00 CEST'
[ 132.550218] TEST-53-TIMER.sh[384]: + assert_ge 1760472604 1760393400
[ 132.550555] TEST-53-TIMER.sh[16446]: + set +ex
[ 132.550702] TEST-53-TIMER.sh[384]: + assert_le 1760472604 1760472600
[ 132.550832] TEST-53-TIMER.sh[16447]: + set +ex
[ 132.551091] TEST-53-TIMER.sh[16447]: FAIL: '1760472604' > '1760472600'
Here the original next elapse timestamp was Tue 2025-10-14 00:10:00 CEST
as expected, but it was overridden by the rebased timestamp:
Tue 2025-10-14 00:10:56 CEST. And when a new randomized delay was added
to it (21h 59min 7.955828s) the final next elapse timestamp fell out of
the expected window, i.e. Tue 2025-10-14 00:10:00 (scheduled time) <
Tue 2025-10-14 22:10:04 CEST (rebased elapse timestamp + randomized
delay) < Tue 2025-10-14 22:10:00 CEST (scheduled time + maximum from
RandomizedDelaySec=, i.e. 22h).
By limiting the timestamp rebase only the case where the unit hasn't
already run should prevent this from happening during daemon-reload.
(cherry picked from commit bdb8e584f4509de0daebbe2357d23156160c3a90)
Related: RHEL-127022
---
src/core/timer.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index 2eadca4f1a..4b0266bc68 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -392,7 +392,8 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
continue;
if (v->base == TIMER_CALENDAR) {
- usec_t b, rebased;
+ bool rebase_after_boot_time = false;
+ usec_t b;
/* If we know the last time this was
* triggered, schedule the job based relative
@@ -403,21 +404,25 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
b = t->last_trigger.realtime;
else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
b = UNIT(t)->inactive_exit_timestamp.realtime;
- else
+ else {
b = ts.realtime;
+ rebase_after_boot_time = true;
+ }
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)
continue;
- /* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
- * time has already passed, set the time when systemd first started as the scheduled
- * time. Note that we base this on the monotonic timestamp of the boot, not the
- * realtime one, since the wallclock might have been off during boot. */
- rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic,
- CLOCK_MONOTONIC, CLOCK_REALTIME);
- if (v->next_elapse < rebased)
- v->next_elapse = rebased;
+ if (rebase_after_boot_time) {
+ /* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled
+ * time has already passed, set the time when systemd first started as the scheduled
+ * time. Note that we base this on the monotonic timestamp of the boot, not the
+ * realtime one, since the wallclock might have been off during boot. */
+ usec_t rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic,
+ CLOCK_MONOTONIC, CLOCK_REALTIME);
+ if (v->next_elapse < rebased)
+ v->next_elapse = rebased;
+ }
if (!found_realtime)
t->next_elapse_realtime = v->next_elapse;

View File

@ -0,0 +1,34 @@
From 6ae4c19c78b0daac097b4a7d88566f95daa9e60b Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 24 Oct 2025 12:55:20 +0200
Subject: [PATCH] coredump: handle ENOBUFS and EMSGSIZE the same way
Depending on the runtime configuration, e.g. sysctls
net.core.wmem_default= and net.core.rmem_default and on the actual
message size, sendmsg() can fail also with ENOBUFS. E.g. alloc_skb()
failure caused by net.core.[rw]mem_default=64MiB and huge fdinfo list
from process that has 90k opened FDs.
We should handle this case in the same way as EMSGSIZE and drop part of
the message.
(cherry picked from commit 28e62e684b631f928f1d857b04f45f0d34441675)
Resolves: RHEL-126114
---
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 e0aac3c8d0..28dabf017b 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -1273,7 +1273,7 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd, int mntns_
if (sendmsg(fd, &mh, MSG_NOSIGNAL) >= 0)
break;
- if (errno == EMSGSIZE && mh.msg_iov[0].iov_len > 0) {
+ if (IN_SET(errno, EMSGSIZE, ENOBUFS) && mh.msg_iov[0].iov_len > 0) {
/* This field didn't fit? That's a pity. Given that this is
* just metadata, let's truncate the field at half, and try
* again. We append three dots, in order to show that this is

View File

@ -0,0 +1,143 @@
From 6c05a35ce4d03cf25220de5e950970ef23417415 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 19 Nov 2025 14:44:13 +0100
Subject: [PATCH] timer: rebase last_trigger timestamp if needed
After bdb8e584f4509de0daebbe2357d23156160c3a90 we stopped rebasing the
next elapse timestamp unconditionally and the only case where we'd do
that was when both last trigger and last inactive timestamps were empty.
This covered timer units during boot just fine, since they would have
neither of those timestamps set. However, persistent timers
(Persistent=yes) store their last trigger timestamp on a persistent
storage and load it back after reboot, so the rebasing was skipped in
this case.
To mitigate this, check the last_trigger timestamp is older than the
current machine boot - if so, that means that it came from a stamp file
of a persistent timer unit and we need to rebase it to make
RandomizedDelaySec= work properly.
Follow-up for bdb8e584f4509de0daebbe2357d23156160c3a90.
(cherry picked from commit 3605b3ba87833a9919bfde05952a7d9de10499a2)
Related: RHEL-127022
---
src/core/timer.c | 15 +++--
...tsuite-53.RandomizedDelaySec-persistent.sh | 67 +++++++++++++++++++
2 files changed, 78 insertions(+), 4 deletions(-)
create mode 100755 test/units/testsuite-53.RandomizedDelaySec-persistent.sh
diff --git a/src/core/timer.c b/src/core/timer.c
index 4b0266bc68..8fb79bc0cb 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -394,15 +394,23 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
if (v->base == TIMER_CALENDAR) {
bool rebase_after_boot_time = false;
usec_t b;
+ usec_t boot_monotonic = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
/* If we know the last time this was
* triggered, schedule the job based relative
* to that. If we don't, just start from
* the activation time. */
- if (dual_timestamp_is_set(&t->last_trigger))
+ if (dual_timestamp_is_set(&t->last_trigger)) {
b = t->last_trigger.realtime;
- else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
+
+ /* Check if the last_trigger timestamp is older than the current machine
+ * boot. If so, this means the timestamp came from a stamp file of a
+ * persistent timer and we need to rebase it to make RandomizedDelaySec=
+ * work (see below). */
+ if (t->last_trigger.monotonic < boot_monotonic)
+ rebase_after_boot_time = true;
+ } else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
b = UNIT(t)->inactive_exit_timestamp.realtime;
else {
b = ts.realtime;
@@ -418,8 +426,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
* time has already passed, set the time when systemd first started as the scheduled
* time. Note that we base this on the monotonic timestamp of the boot, not the
* realtime one, since the wallclock might have been off during boot. */
- usec_t rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic,
- CLOCK_MONOTONIC, CLOCK_REALTIME);
+ usec_t rebased = map_clock_usec(boot_monotonic, CLOCK_MONOTONIC, CLOCK_REALTIME);
if (v->next_elapse < rebased)
v->next_elapse = rebased;
}
diff --git a/test/units/testsuite-53.RandomizedDelaySec-persistent.sh b/test/units/testsuite-53.RandomizedDelaySec-persistent.sh
new file mode 100755
index 0000000000..af22daecc7
--- /dev/null
+++ b/test/units/testsuite-53.RandomizedDelaySec-persistent.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Persistent timers (i.e. timers with Persitent=yes) save their last trigger timestamp to a persistent
+# storage (a stamp file), which is loaded during subsequent boots. As mentioned in the man page, such timers
+# should be still affected by RandomizedDelaySec= during boot even if they already elapsed and would be then
+# triggered immediately.
+#
+# This behavior was, however, broken by [0], which stopped rebasing the to-be next elapse timestamps
+# unconditionally and left that only for timers that have neither last trigger nor inactive exit timestamps
+# set, since rebasing is needed only during boot. This holds for regular timers during boot, but not for
+# persistent ones, since the last trigger timestamp is loaded from a persistent storage.
+#
+# Provides coverage for:
+# - https://github.com/systemd/systemd/issues/39739
+#
+# [0] bdb8e584f4509de0daebbe2357d23156160c3a90
+#
+set -eux
+set -o pipefail
+
+# shellcheck source=test/units/test-control.sh
+. "$(dirname "$0")"/util.sh
+
+UNIT_NAME="timer-RandomizedDelaySec-persistent-$RANDOM"
+STAMP_FILE="/var/lib/systemd/timers/stamp-$UNIT_NAME.timer"
+
+# Setup
+cat >"/run/systemd/system/$UNIT_NAME.timer" <<EOF
+[Timer]
+OnCalendar=daily
+Persistent=true
+RandomizedDelaySec=12h
+EOF
+
+cat >"/run/systemd/system/$UNIT_NAME.service" <<\EOF
+[Service]
+ExecStart=echo "Service ran at $(date)"
+EOF
+
+systemctl daemon-reload
+
+# Create timer's state file with an old-enough timestamp (~2 days ago), so it'd definitely elapse if the next
+# elapse timestamp wouldn't get rebased
+mkdir -p "$(dirname "$STAMP_FILE")"
+touch -d "2 days ago" "$STAMP_FILE"
+stat "$STAMP_FILE"
+SAVED_LAST_TRIGGER_S="$(stat --format="%Y" "$STAMP_FILE")"
+
+# Start the timer and verify that its last trigger timestamp didn't change
+#
+# The last trigger timestamp should get rebased before it gets used as a base for the next elapse timestamp
+# (since it pre-dates the machine boot time). This should then add a RandomizedDelaySec= to the rebased
+# timestamp and the timer unit should not get triggered immediately after starting.
+systemctl start "$UNIT_NAME.timer"
+systemctl status "$UNIT_NAME.timer"
+
+TIMER_LAST_TRIGGER="$(systemctl show --property=LastTriggerUSec --value "$UNIT_NAME.timer")"
+TIMER_LAST_TRIGGER_S="$(date --date="$TIMER_LAST_TRIGGER" "+%s")"
+: "The timer should not be triggered immediately, hence the last trigger timestamp should not change"
+assert_eq "$SAVED_LAST_TRIGGER_S" "$TIMER_LAST_TRIGGER_S"
+
+# Cleanup
+systemctl stop "$UNIT_NAME".{timer,service}
+systemctl clean --what=state "$UNIT_NAME.timer"
+rm -f "/run/systemd/system/$UNIT_NAME".{timer,service}
+systemctl daemon-reload

View File

@ -0,0 +1,36 @@
From ca32ed0b2451453eaff579d08f9e188f9c79ab0c Mon Sep 17 00:00:00 2001
From: Florian Schmaus <flo@geekplace.eu>
Date: Thu, 9 Nov 2023 08:59:59 +0100
Subject: [PATCH] core: fix array size in unit_log_resources()
In 0531bded79dc ("core: include peak memory in unit_log_resources()") new log
messages where added, however the size of the according arrays to hold the
messages was not adjusted.
Fixes: 0531bded79dc ("core: include peak memory in unit_log_resources()")
(cherry picked from commit 893028523469b3ec459388428ddc466942cdaf4d)
Resolves: RHEL-132120
---
src/core/unit.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 9e349402ff..3e04b12951 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2233,12 +2233,12 @@ static int raise_level(int log_level, bool condition_info, bool condition_notice
}
static int unit_log_resources(Unit *u) {
- struct iovec iovec[1 + _CGROUP_IP_ACCOUNTING_METRIC_MAX + _CGROUP_IO_ACCOUNTING_METRIC_MAX + 4];
+ struct iovec iovec[1 + 1 + _CGROUP_IP_ACCOUNTING_METRIC_MAX + _CGROUP_IO_ACCOUNTING_METRIC_MAX + 4];
bool any_traffic = false, have_ip_accounting = false, any_io = false, have_io_accounting = false;
_cleanup_free_ char *igress = NULL, *egress = NULL, *rr = NULL, *wr = NULL;
int log_level = LOG_DEBUG; /* May be raised if resources consumed over a threshold */
size_t n_message_parts = 0, n_iovec = 0;
- char* message_parts[1 + 2 + 2 + 1], *t;
+ char* message_parts[1 + 1 + 2 + 2 + 1], *t;
nsec_t nsec = NSEC_INFINITY;
uint64_t memory_peak = UINT64_MAX;
int r;

View File

@ -21,7 +21,7 @@
Name: systemd Name: systemd
Url: https://systemd.io Url: https://systemd.io
Version: 252 Version: 252
Release: 55%{?dist}.2 Release: 55%{?dist}.7
# For a breakdown of the licensing, see README # For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+ License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager Summary: System and Service Manager
@ -1333,6 +1333,26 @@ Patch1247: 1247-time-util-drop-unnecessary-assignment-of-timezone-na.patch
Patch1248: 1248-time-util-make-parse_timestamp-use-the-RFC-822-ISO-8.patch Patch1248: 1248-time-util-make-parse_timestamp-use-the-RFC-822-ISO-8.patch
Patch1249: 1249-time-util-fix-typo.patch Patch1249: 1249-time-util-fix-typo.patch
Patch1250: 1250-ci-bump-the-tools-tree-to-F42.patch Patch1250: 1250-ci-bump-the-tools-tree-to-F42.patch
Patch1251: 1251-cryptsetup-Add-optional-support-for-linking-volume-k.patch
Patch1252: 1252-cryptsetup-fix-typo.patch
Patch1253: 1253-cryptsetup-HAVE_CRYPT_SET_KEYRING_TO_LINK-is-always-.patch
Patch1254: 1254-basic-add-PIDFS-magic-31709.patch
Patch1255: 1255-time-util-make-USEC_TIMESTAMP_FORMATTABLE_MAX-for-32.patch
Patch1256: 1256-coredump-make-check-that-all-argv-meta-data-fields-a.patch
Patch1257: 1257-coredump-restore-compatibility-with-older-patterns.patch
Patch1258: 1258-coredump-use-d-in-kernel-core-pattern.patch
Patch1259: 1259-pidref-add-structure-that-can-reference-a-pid-via-bo.patch
Patch1260: 1260-fd-util-introduce-parse_fd.patch
Patch1261: 1261-coredump-add-support-for-new-F-PIDFD-specifier.patch
Patch1262: 1262-test-rename-TEST-53-ISSUE-16347-to-TEST-53-TIMER.patch
Patch1263: 1263-test-restarting-elapsed-timer-shouldn-t-trigger-the-.patch
Patch1264: 1264-test-check-the-next-elapse-timer-timestamp-after-des.patch
Patch1265: 1265-timer-don-t-run-service-immediately-after-restart-of.patch
Patch1266: 1266-test-store-and-compare-just-the-property-value.patch
Patch1267: 1267-timer-rebase-the-next-elapse-timestamp-only-if-timer.patch
Patch1268: 1268-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch
Patch1269: 1269-timer-rebase-last_trigger-timestamp-if-needed.patch
Patch1270: 1270-core-fix-array-size-in-unit_log_resources.patch
# Downstream-only patches (90009999) # Downstream-only patches (90009999)
@ -2210,6 +2230,34 @@ systemd-hwdb update &>/dev/null || :
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/* %{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
%changelog %changelog
* Mon Dec 01 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.7
- core: fix array size in unit_log_resources() (RHEL-132120)
* Mon Nov 24 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.6
- timer: rebase last_trigger timestamp if needed (RHEL-127022)
* Tue Nov 18 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.5
- test: rename TEST-53-ISSUE-16347 to TEST-53-TIMER (RHEL-127022)
- test: restarting elapsed timer shouldn't trigger the corresponding service (RHEL-127022)
- test: check the next elapse timer timestamp after deserialization (RHEL-127022)
- timer: don't run service immediately after restart of a timer (RHEL-127022)
- test: store and compare just the property value (RHEL-127022)
- timer: rebase the next elapse timestamp only if timer didn't already run (RHEL-127022)
- coredump: handle ENOBUFS and EMSGSIZE the same way (RHEL-126114)
* Thu Nov 06 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.4
- cryptsetup: Add optional support for linking volume key in keyring. (RHEL-118294)
- cryptsetup: fix typo (RHEL-118294)
- cryptsetup: HAVE_CRYPT_SET_KEYRING_TO_LINK is always defined (RHEL-118294)
- basic: add PIDFS magic (#31709) (RHEL-118294)
- time-util: make USEC_TIMESTAMP_FORMATTABLE_MAX for 32bit system off by one day (RHEL-118294)
- coredump: make check that all argv[] meta data fields are passed strict (RHEL-104138)
- coredump: restore compatibility with older patterns (RHEL-104138)
- coredump: use %d in kernel core pattern (RHEL-104138)
- pidref: add structure that can reference a pid via both pidfd and pid_t (RHEL-104138)
- fd-util: introduce parse_fd() (RHEL-104138)
- coredump: add support for new %F PIDFD specifier (RHEL-104138)
* Fri Sep 12 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.2 * Fri Sep 12 2025 systemd maintenance team <systemd-maint@redhat.com> - 252-55.2
- Revert "test-time-util: disable failing tests" (RHEL-110954) - Revert "test-time-util: disable failing tests" (RHEL-110954)
- test: use get_timezones() to iterate all known timezones (RHEL-110954) - test: use get_timezones() to iterate all known timezones (RHEL-110954)