diff --git a/1290-ukify-rstrip-and-escape-binary-null-characters-from-.patch b/1290-ukify-rstrip-and-escape-binary-null-characters-from-.patch new file mode 100644 index 0000000..1af21ae --- /dev/null +++ b/1290-ukify-rstrip-and-escape-binary-null-characters-from-.patch @@ -0,0 +1,32 @@ +From 2a16be65ca89cf18adf63a99ae1b1748e63d6773 Mon Sep 17 00:00:00 2001 +From: Li Tian <94442129+litian1992@users.noreply.github.com> +Date: Tue, 19 Aug 2025 05:43:41 +0800 +Subject: [PATCH] ukify: rstrip and escape binary null characters from + 'inspect' output (#38607) + +SBAT section of UKI may contain \u000 null characters. Rstrip them, and if there's anything left in the middle, +escape them so they are displayed as text. + +Fixes #38606 + +(cherry picked from commit 776991a3f349d9c99fd166a0c87fcd2bc1bf92a5) +Signed-off-by: Li Tian + +Resolves: RHEL-109558 +--- + src/ukify/ukify.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py +index 08f505a271..2d5050eaca 100755 +--- a/src/ukify/ukify.py ++++ b/src/ukify/ukify.py +@@ -986,7 +986,7 @@ def inspect_section(opts, section): + + if ttype == 'text': + try: +- struct['text'] = data.decode() ++ struct['text'] = data.rstrip(b'\0').replace(b'\0', b'\\0').decode() + except UnicodeDecodeError as e: + print(f"Section {name!r} is not valid text: {e}") + struct['text'] = '(not valid UTF-8)' diff --git a/1291-timer-rebase-last_trigger-timestamp-if-needed.patch b/1291-timer-rebase-last_trigger-timestamp-if-needed.patch new file mode 100644 index 0000000..ef16654 --- /dev/null +++ b/1291-timer-rebase-last_trigger-timestamp-if-needed.patch @@ -0,0 +1,143 @@ +From 6085358791b712a60fb22c7870abf0aa75c5f157 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +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-118215 +--- + 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" <"/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 diff --git a/systemd.spec b/systemd.spec index 26ba218..6a7ac49 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://systemd.io Version: 252 -Release: 61%{?dist} +Release: 62%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -1372,6 +1372,8 @@ Patch1286: 1286-unit-file-introduce-unit_file_remove_from_name_map.patch Patch1287: 1287-core-unit-remove-path-to-transient-unit-file-from-un.patch Patch1288: 1288-TEST-07-PID1-add-reprudcer-for-issue-35190.patch Patch1289: 1289-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch +Patch1290: 1290-ukify-rstrip-and-escape-binary-null-characters-from-.patch +Patch1291: 1291-timer-rebase-last_trigger-timestamp-if-needed.patch # Downstream-only patches (9000–9999) @@ -2249,6 +2251,10 @@ systemd-hwdb update &>/dev/null || : %{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/* %changelog +* Mon Nov 24 2025 systemd maintenance team - 252-62 +- ukify: rstrip and escape binary null characters from 'inspect' output (#38607) (RHEL-109558) +- timer: rebase last_trigger timestamp if needed (RHEL-118215) + * Fri Nov 21 2025 systemd maintenance team - 252-61 - timer: rebase the next elapse timestamp only if timer didn't already run (RHEL-118215) - strv: introduce string_strv_hashmap_remove() (RHEL-14112)