diff --git a/backport-busctl-validate-argvs-on-get-property-set-property-t.patch b/backport-busctl-validate-argvs-on-get-property-set-property-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..0de8c5400e74c9fac1a3eeb3edaec2779e82edbb --- /dev/null +++ b/backport-busctl-validate-argvs-on-get-property-set-property-t.patch @@ -0,0 +1,73 @@ +From e26ba16ed64c43dd310fc9deaa86a0205eaaffc0 Mon Sep 17 00:00:00 2001 +From: Luca Boccassi +Date: Wed, 30 Apr 2025 15:24:20 +0100 +Subject: [PATCH] busctl: validate argvs on get-property/set-property too + +Otherwise passing invalid data means asserts get hit instead of +handling it gracefully. Other verbs already do the same checks. + +busctl get-property org.freedesktop.systemd1 '*' org.freedesktop.systemd1.Manager Version +Assertion 'object_path_is_valid(path)' failed at src/libsystemd/sd-bus/bus-message.c:562, function sd_bus_message_new_method_call(). Aborting. +Aborted (core dumped) + +(cherry picked from commit b16e6fd76788e74ce7424404445e822655abd6c9) +(cherry picked from commit 6961d8ac6e0cc8d81c20c7de07595834ffabd556) +(cherry picked from commit da7c0fc714a015dd9d7e8c1d622aa10f2f016111) + +--- + src/busctl/busctl.c | 14 ++++++++++++++ + test/units/testsuite-74.busctl.sh | 9 +++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c +index a436f88..2da6c16 100644 +--- a/src/busctl/busctl.c ++++ b/src/busctl/busctl.c +@@ -2131,6 +2131,13 @@ static int get_property(int argc, char **argv, void *userdata) { + char **i; + int r; + ++ if (!service_name_is_valid(argv[1])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]); ++ if (!object_path_is_valid(argv[2])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]); ++ if (!interface_name_is_valid(argv[3])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]); ++ + r = acquire_bus(false, &bus); + if (r < 0) + return r; +@@ -2200,6 +2207,13 @@ static int set_property(int argc, char **argv, void *userdata) { + char **p; + int r; + ++ if (!service_name_is_valid(argv[1])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]); ++ if (!object_path_is_valid(argv[2])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]); ++ if (!interface_name_is_valid(argv[3])) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]); ++ + r = acquire_bus(false, &bus); + if (r < 0) + return r; +diff --git a/test/units/testsuite-74.busctl.sh b/test/units/testsuite-74.busctl.sh +index 44d8032..c9eeff7 100755 +--- a/test/units/testsuite-74.busctl.sh ++++ b/test/units/testsuite-74.busctl.sh +@@ -100,3 +100,12 @@ busctl get-property -j \ + # Invalid argument + (! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ + KExecWatchdogUSec t "foo") ++ ++# Invalid destination ++(! busctl get-property '*' /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Version) ++ ++# Invalid object ++(! busctl get-property org.freedesktop.systemd1 '*' org.freedesktop.systemd1.Manager Version) ++ ++# Invalid interface ++(! busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 '*' Version) +-- +2.43.0 + diff --git a/backport-compress-prevent-divide-by-zero-when-no-data-is-read.patch b/backport-compress-prevent-divide-by-zero-when-no-data-is-read.patch new file mode 100644 index 0000000000000000000000000000000000000000..e8ecfc242f49f13fa82356a15e75aa56678ff066 --- /dev/null +++ b/backport-compress-prevent-divide-by-zero-when-no-data-is-read.patch @@ -0,0 +1,44 @@ +From 93f677fdb61d348e56c6c85b1564908800104a9e Mon Sep 17 00:00:00 2001 +From: Alex +Date: Mon, 2 Jun 2025 21:51:00 -0400 +Subject: [PATCH] compress: prevent divide-by-zero when no data is read + (#37706) + +If the first call to `loop_read()` returns 0 (no input), `total_in` +remains 0, causing `total_out/total_in` to potential divide by zero. + +We add a check before logging the compression ratio to skip the +percentage calculation when total_in is zero. + +Co-authored-by: jinyaoguo +(cherry picked from commit 2584f745e0509472e68449bd81c60c26056d514a) +(cherry picked from commit 18a42e321d699e7f3ae46930fa070228d02774ed) +(cherry picked from commit eaffe6679b6bcf6d5ba4d468332079a9ac82da43) + +--- + src/libsystemd/sd-journal/compress.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-journal/compress.c b/src/libsystemd/sd-journal/compress.c +index cb2e826..993d4d1 100644 +--- a/src/libsystemd/sd-journal/compress.c ++++ b/src/libsystemd/sd-journal/compress.c +@@ -706,9 +706,12 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_unco + if (ret_uncompressed_size) + *ret_uncompressed_size = total_in; + +- log_debug("LZ4 compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)", +- total_in, total_out, +- (double) total_out / total_in * 100); ++ if (total_in == 0) ++ log_debug("LZ4 compression finished (no input data)"); ++ else ++ log_debug("LZ4 compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)", ++ total_in, total_out, ++ (double) total_out / total_in * 100); + + return 0; + #else +-- +2.43.0 + diff --git a/backport-core-introduce-Unit.dependency_generation-counter-an.patch b/backport-core-introduce-Unit.dependency_generation-counter-an.patch new file mode 100644 index 0000000000000000000000000000000000000000..d57d23b537a4baf45fe0180abc6ac1c5c1063848 --- /dev/null +++ b/backport-core-introduce-Unit.dependency_generation-counter-an.patch @@ -0,0 +1,242 @@ +From 9316f1b11089d5a47073ccca8f4b48f548b4f1fe Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 15 May 2025 12:34:35 +0900 +Subject: [PATCH] core: introduce Unit.dependency_generation counter and + restart loop when dependency is updated in the loop + +When starting unit A, a dependent unit B may be loaded if it is not +loaded yet, and the dependencies in unit A may be updated. +As Hashmap does not allow a new entry to be added in a loop, we need to +restart loop in such case. + +Fixes a bug introduced by cda667722c2218cf1a0185284d2a87f8a25f1b2d. +Fixes #36031. + +(cherry picked from commit b7777d08846033859c5b734317fbbbfcca4cafcb) +(cherry picked from commit 4dc4fdcfe051b10aa4f7fe4d3ab220c27084eaf5) +(cherry picked from commit 01f34bf5df4c42bdd0e3622d0823a54f91316f61) + +--- + src/core/transaction.c | 16 ++++++++-------- + src/core/unit.c | 11 ++++++++++- + src/core/unit.h | 31 ++++++++++++++++++++++++++----- + 3 files changed, 44 insertions(+), 14 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 2d22524..528a02d 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -888,7 +888,7 @@ void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, + assert(tr); + assert(unit); + +- UNIT_FOREACH_DEPENDENCY(dep, unit, UNIT_ATOM_PROPAGATES_RELOAD_TO) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, unit, UNIT_ATOM_PROPAGATES_RELOAD_TO) { + nt = job_type_collapse(JOB_TRY_RELOAD, dep); + if (nt == JOB_NOP) + continue; +@@ -1008,7 +1008,7 @@ int transaction_add_job_and_dependencies( + + /* Finally, recursively add in all dependencies. */ + if (IN_SET(type, JOB_START, JOB_RESTART)) { +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, UNIT_ATOM_PULL_IN_START) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, UNIT_ATOM_PULL_IN_START) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) /* job type not applicable */ +@@ -1018,7 +1018,7 @@ int transaction_add_job_and_dependencies( + } + } + +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, UNIT_ATOM_PULL_IN_START_IGNORED) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, UNIT_ATOM_PULL_IN_START_IGNORED) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e); + if (r < 0) { + /* unit masked, job type not applicable and unit not found are not considered as errors. */ +@@ -1030,7 +1030,7 @@ int transaction_add_job_and_dependencies( + } + } + +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, UNIT_ATOM_PULL_IN_VERIFY) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, UNIT_ATOM_PULL_IN_VERIFY) { + r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) /* job type not applicable */ +@@ -1040,7 +1040,7 @@ int transaction_add_job_and_dependencies( + } + } + +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, UNIT_ATOM_PULL_IN_STOP) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, UNIT_ATOM_PULL_IN_STOP) { + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) /* job type not applicable */ +@@ -1050,7 +1050,7 @@ int transaction_add_job_and_dependencies( + } + } + +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, UNIT_ATOM_PULL_IN_STOP_IGNORED) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, UNIT_ATOM_PULL_IN_STOP_IGNORED) { + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e); + if (r < 0) { + log_unit_warning(dep, +@@ -1075,7 +1075,7 @@ int transaction_add_job_and_dependencies( + atom = UNIT_ATOM_PROPAGATE_STOP; + } + +- UNIT_FOREACH_DEPENDENCY(dep, ret->unit, atom) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(dep, ret->unit, atom) { + JobType nt; + + nt = job_type_collapse(ptype, dep); +@@ -1165,7 +1165,7 @@ int transaction_add_triggering_jobs(Transaction *tr, Unit *u) { + assert(tr); + assert(u); + +- UNIT_FOREACH_DEPENDENCY(trigger, u, UNIT_ATOM_TRIGGERED_BY) { ++ UNIT_FOREACH_DEPENDENCY_SAFE(trigger, u, UNIT_ATOM_TRIGGERED_BY) { + + /* No need to stop inactive jobs */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(trigger)) && !trigger->job) +diff --git a/src/core/unit.c b/src/core/unit.c +index ae08b84..d19c114 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -620,12 +620,14 @@ static void unit_clear_dependencies(Unit *u) { + hashmap_remove(other_deps, u); + + unit_add_to_gc_queue(other); ++ other->dependency_generation++; + } + + hashmap_free(deps); + } + + u->dependencies = hashmap_free(u->dependencies); ++ u->dependency_generation++; + } + + static void unit_remove_transient(Unit *u) { +@@ -1119,6 +1121,9 @@ static void unit_merge_dependencies(Unit *u, Unit *other) { + } + + other->dependencies = hashmap_free(other->dependencies); ++ ++ u->dependency_generation++; ++ other->dependency_generation++; + } + + int unit_merge(Unit *u, Unit *other) { +@@ -3127,6 +3132,7 @@ static int unit_add_dependency_impl( + return r; + + flags = NOTIFY_DEPENDENCY_UPDATE_FROM; ++ u->dependency_generation++; + } + + if (other_info.data != other_info_old.data) { +@@ -3143,6 +3149,7 @@ static int unit_add_dependency_impl( + } + + flags |= NOTIFY_DEPENDENCY_UPDATE_TO; ++ other->dependency_generation++; + } + + return flags; +@@ -5254,7 +5261,9 @@ void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) { + } + + unit_add_to_gc_queue(other); +- ++ u->dependency_generation++; ++ other->dependency_generation++; ++ + done = false; + break; + } +diff --git a/src/core/unit.h b/src/core/unit.h +index 16c65d9..5e7fba8 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -142,6 +142,7 @@ typedef struct Unit { + * and whose value encodes why the dependency exists, using the UnitDependencyInfo type. i.e. a + * Hashmap(UnitDependency → Hashmap(Unit* → UnitDependencyInfo)) */ + Hashmap *dependencies; ++ uint64_t dependency_generation; + + /* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the + * UnitDependencyInfo type */ +@@ -1042,27 +1043,44 @@ CollectMode collect_mode_from_string(const char *s) _pure_; + typedef struct UnitForEachDependencyData { + /* Stores state for the FOREACH macro below for iterating through all deps that have any of the + * specified dependency atom bits set */ ++ const Unit *unit; + UnitDependencyAtom match_atom; + Hashmap *by_type, *by_unit; + void *current_type; + Iterator by_type_iterator, by_unit_iterator; + Unit **current_unit; ++ uint64_t generation; ++ unsigned n_restart; ++ bool restart_on_generation_change; + } UnitForEachDependencyData; + ++/* Let's not restart the loop infinitely. */ ++#define MAX_FOREACH_DEPENDENCY_RESTART 100000 ++ + /* Iterates through all dependencies that have a specific atom in the dependency type set. This tries to be + * smart: if the atom is unique, we'll directly go to right entry. Otherwise we'll iterate through the + * per-dependency type hashmap and match all dep that have the right atom set. */ +-#define _UNIT_FOREACH_DEPENDENCY(other, u, ma, data) \ ++#define _UNIT_FOREACH_DEPENDENCY(other, u, ma, restart, data) \ + for (UnitForEachDependencyData data = { \ ++ .unit = (u), \ + .match_atom = (ma), \ +- .by_type = (u)->dependencies, \ +- .by_type_iterator = ITERATOR_FIRST, \ + .current_unit = &(other), \ ++ .restart_on_generation_change = (restart), \ + }; \ + ({ \ + UnitDependency _dt = _UNIT_DEPENDENCY_INVALID; \ + bool _found; \ + \ ++ if (data.generation == 0 || \ ++ (data.restart_on_generation_change && \ ++ data.generation != data.unit->dependency_generation)) { \ ++ data.generation = data.unit->dependency_generation; \ ++ data.by_type = data.unit->dependencies; \ ++ data.by_type_iterator = ITERATOR_FIRST; \ ++ assert_se(data.n_restart++ < MAX_FOREACH_DEPENDENCY_RESTART); \ ++ } else \ ++ assert(data.generation == data.unit->dependency_generation); \ ++ \ + if (data.by_type && ITERATOR_IS_FIRST(data.by_type_iterator)) { \ + _dt = unit_dependency_from_unique_atom(data.match_atom); \ + if (_dt >= 0) { \ +@@ -1075,12 +1093,13 @@ typedef struct UnitForEachDependencyData { + if (_dt < 0) \ + _found = hashmap_iterate(data.by_type, \ + &data.by_type_iterator, \ +- (void**)&(data.by_unit), \ ++ (void**) &(data.by_unit), \ + (const void**) &(data.current_type)); \ + _found; \ + }); ) \ + if ((unit_dependency_to_atom(UNIT_DEPENDENCY_FROM_PTR(data.current_type)) & data.match_atom) != 0) \ + for (data.by_unit_iterator = ITERATOR_FIRST; \ ++ data.generation == data.unit->dependency_generation && \ + hashmap_iterate(data.by_unit, \ + &data.by_unit_iterator, \ + NULL, \ +@@ -1088,4 +1107,6 @@ typedef struct UnitForEachDependencyData { + + /* Note: this matches deps that have *any* of the atoms specified in match_atom set */ + #define UNIT_FOREACH_DEPENDENCY(other, u, match_atom) \ +- _UNIT_FOREACH_DEPENDENCY(other, u, match_atom, UNIQ_T(data, UNIQ)) ++ _UNIT_FOREACH_DEPENDENCY(other, u, match_atom, false, UNIQ_T(data, UNIQ)) ++#define UNIT_FOREACH_DEPENDENCY_SAFE(other, u, match_atom) \ ++ _UNIT_FOREACH_DEPENDENCY(other, u, match_atom, true, UNIQ_T(data, UNIQ)) +-- +2.43.0 + diff --git a/backport-core-transaction-do-not-override-unit-load-state-whe.patch b/backport-core-transaction-do-not-override-unit-load-state-whe.patch new file mode 100644 index 0000000000000000000000000000000000000000..46862bffa6841e3e2f38b0ef20a37ddcf23b386c --- /dev/null +++ b/backport-core-transaction-do-not-override-unit-load-state-whe.patch @@ -0,0 +1,49 @@ +From 87aea85c2ab984b689614f69d544dfdc489cbff8 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 21 May 2025 04:38:07 +0900 +Subject: [PATCH] core/transaction: do not override unit load state when + unit_load() failed + +When unit_load() failed for some reasons, previously we overrided the +load state with UNIT_NOT_FOUND, but we did not update the +Unit.fragment_not_found_timestamp_hash. So, the unit may be loaded +multiple times when the unit is in a dependency list of another unit, +as manager_unit_cache_should_retry_load() will be true again even on +next call. +Let's not override the unit state set by unit_load(). + +Note, after unit_load(), the unit state should not be UNIT_STUB. +Let's also add the assertion about that. + +This change is important when combined with the next commit, as with the +next commit we will restart the FOREACH_UNIT_DEPENDENCY() loop if an unit +is reloaded, hence overriding load state with UNIT_NOT_FOUND may cause +infinit loop. + +(cherry picked from commit 9b6aa9e443859f1eb69cfe37ca755ac4db31c475) +(cherry picked from commit 0e5fc0a29c4a98f781d4d4911b5f589f31c9f10e) +(cherry picked from commit 7dfa163cecb3e79daf35ad9858d0e9b725cb2234) +--- + src/core/transaction.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index 46c3c3b863..9ebf3c5408 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -976,9 +976,9 @@ int transaction_add_job_and_dependencies( + if (manager_unit_cache_should_retry_load(unit)) { + assert(unit->load_state == UNIT_NOT_FOUND); + unit->load_state = UNIT_STUB; +- r = unit_load(unit); +- if (r < 0 || unit->load_state == UNIT_STUB) +- unit->load_state = UNIT_NOT_FOUND; ++ unit->load_error = 0; ++ (void) unit_load(unit); ++ assert(unit->load_state != UNIT_STUB); + } + + r = bus_unit_validate_load_state(unit, e); +-- +2.43.0 + diff --git a/backport-core-transaction-drop-redundant-call-of-bus_unit_val.patch b/backport-core-transaction-drop-redundant-call-of-bus_unit_val.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf606440990c3358cf69cf10078d6f0c056224cf --- /dev/null +++ b/backport-core-transaction-drop-redundant-call-of-bus_unit_val.patch @@ -0,0 +1,53 @@ +From eae4a19d43e08501e8687ae4d866a923f02484df Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 21 May 2025 04:32:09 +0900 +Subject: [PATCH] core/transaction: drop redundant call of + bus_unit_validate_load_state() + +The function manager_unit_cache_should_retry_load() reutrns true only +when the unit state is UNIT_NOT_FOUND. Hence, it is not necessary to +call bus_unit_validate_load_state() before checking +manager_unit_cache_should_retry_load(). + +(cherry picked from commit 7ad2e660802be989d8ae8d0166c4fe1b7be0eb21) +(cherry picked from commit 915ffa770f3d65e28cf4ed8811140e9933eff242) +(cherry picked from commit cca17f069bdc72bcb1a9d9d9e3b8d4b2064037e9) + +--- + src/core/transaction.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index a1441c1..8911aea 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -940,7 +940,6 @@ int transaction_add_job_and_dependencies( + return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); + + if (type != JOB_STOP) { +- r = bus_unit_validate_load_state(unit, e); + /* The time-based cache allows to start new units without daemon-reload, + * but if they are already referenced (because of dependencies or ordering) + * then we have to force a load of the fragment. As an optimization, check +@@ -953,14 +952,15 @@ int transaction_add_job_and_dependencies( + * + * Given building up the transaction is a synchronous operation, attempt + * to load the unit immediately. */ +- if (r < 0 && manager_unit_cache_should_retry_load(unit)) { +- sd_bus_error_free(e); ++ if (manager_unit_cache_should_retry_load(unit)) { ++ assert(unit->load_state == UNIT_NOT_FOUND); + unit->load_state = UNIT_STUB; + r = unit_load(unit); + if (r < 0 || unit->load_state == UNIT_STUB) + unit->load_state = UNIT_NOT_FOUND; +- r = bus_unit_validate_load_state(unit, e); + } ++ ++ r = bus_unit_validate_load_state(unit, e); + if (r < 0) + return r; + } +-- +2.43.0 + diff --git a/backport-flush_ports-flush-POSIX-message-queues-properly.patch b/backport-flush_ports-flush-POSIX-message-queues-properly.patch new file mode 100644 index 0000000000000000000000000000000000000000..ee984009144737614bc1ba2eddbccedc840e9d83 --- /dev/null +++ b/backport-flush_ports-flush-POSIX-message-queues-properly.patch @@ -0,0 +1,122 @@ +From c1581f686244313ead56b0be8aa5d3567437265d Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Tue, 6 May 2025 16:39:14 -0600 +Subject: [PATCH] flush_ports: flush POSIX message queues properly + +On Linux, read() on a message queue descriptor returns the message +queue statistics, not the actual message queue data. We need to use +mq_receive() to drain the queues instead. + +Fixes a problem where a POSIX message queue socket unit with messages +in the queue at shutdown time could result in a hang on reboot/shutdown. + +(cherry picked from commit ffb6adb76367d5ab7d43937ccaac5947717b5b78) +(cherry picked from commit 4ab235b029f2107ed53f6580a7b57a48b63b4035) +(cherry picked from commit 5ac9982bda6429bceb64358f84f5174d4dd0a1b8) +--- + src/basic/socket-util.c | 49 +++++++++++++++++++++++++++++++++++++++++ + src/basic/socket-util.h | 1 + + src/core/socket.c | 8 +++++-- + 3 files changed, 56 insertions(+), 2 deletions(-) + +diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c +index beb64d8e6c..ad75b3708b 100644 +--- a/src/basic/socket-util.c ++++ b/src/basic/socket-util.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1281,6 +1282,54 @@ int flush_accept(int fd) { + } + } + ++ssize_t flush_mqueue(int fd) { ++ _cleanup_free_ char *buf = NULL; ++ struct mq_attr attr; ++ ssize_t count = 0; ++ int r; ++ ++ assert(fd >= 0); ++ ++ /* Similar to flush_fd() but flushes all messages from a POSIX message queue. */ ++ ++ for (;;) { ++ ssize_t l; ++ ++ r = fd_wait_for_event(fd, POLLIN, /* timeout= */ 0); ++ if (r < 0) { ++ if (r == -EINTR) ++ continue; ++ ++ return r; ++ } ++ if (r == 0) ++ return count; ++ ++ if (!buf) { ++ /* Buffer must be at least as large as mq_msgsize. */ ++ if (mq_getattr(fd, &attr) < 0) ++ return -errno; ++ ++ buf = malloc(attr.mq_msgsize); ++ if (!buf) ++ return -ENOMEM; ++ } ++ ++ l = mq_receive(fd, buf, attr.mq_msgsize, /* msg_prio = */ NULL); ++ if (l < 0) { ++ if (errno == EINTR) ++ continue; ++ ++ if (errno == EAGAIN) ++ return count; ++ ++ return -errno; ++ } ++ ++ count += l; ++ } ++} ++ + struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) { + struct cmsghdr *cmsg; + +diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h +index 9a11df834d..b3f2e3641a 100644 +--- a/src/basic/socket-util.h ++++ b/src/basic/socket-util.h +@@ -195,6 +195,7 @@ int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_ar + ssize_t next_datagram_size_fd(int fd); + + int flush_accept(int fd); ++ssize_t flush_mqueue(int fd); + + #define CMSG_FOREACH(cmsg, mh) \ + for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) +diff --git a/src/core/socket.c b/src/core/socket.c +index 9adae16b00..23bc8ceb71 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -2269,8 +2269,12 @@ static void flush_ports(Socket *s) { + if (p->fd < 0) + continue; + +- (void) flush_accept(p->fd); +- (void) flush_fd(p->fd); ++ if (p->type == SOCKET_MQUEUE) ++ (void) flush_mqueue(p->fd); ++ else { ++ (void) flush_accept(p->fd); ++ (void) flush_fd(p->fd); ++ } + } + } + +-- +2.43.0 + diff --git a/backport-initctl-fix-error-handling.patch b/backport-initctl-fix-error-handling.patch new file mode 100644 index 0000000000000000000000000000000000000000..12df777cff7bdae34df9f2437271c830fd13ac46 --- /dev/null +++ b/backport-initctl-fix-error-handling.patch @@ -0,0 +1,31 @@ +From a5bea0c25b52a711f07837d18e9989fcb7c3ed14 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Wed, 19 Mar 2025 01:32:12 +0900 +Subject: [PATCH] initctl: fix error handling + +Fixes a bug introduced by cc090ca7fec93cd6b41bd7a756cd5fe32df44764 (v246). + +(cherry picked from commit 59cb9b12abc7efb714d15d357c96bd86ef2ddafc) +(cherry picked from commit 8e6fa4e7c61f928510ba176c2d3e05f6c7d0a895) +(cherry picked from commit 7e7c3bdf9cee7226ff9c5fd8b1dd474bcb8127d0) +--- + src/initctl/initctl.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c +index d1b7c30562..1c86e20b3b 100644 +--- a/src/initctl/initctl.c ++++ b/src/initctl/initctl.c +@@ -318,8 +318,7 @@ static int run(int argc, char *argv[]) { + + n = sd_listen_fds(true); + if (n < 0) +- return log_error_errno(errno, +- "Failed to read listening file descriptors from environment: %m"); ++ return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); + + if (n <= 0 || n > SERVER_FD_MAX) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), +-- +2.43.0 + diff --git a/backport-io-util-protect-against-INT_MAX-overflow-in-flush_fd.patch b/backport-io-util-protect-against-INT_MAX-overflow-in-flush_fd.patch new file mode 100644 index 0000000000000000000000000000000000000000..324c944146044160ee7399c85e69e30b4a0bbc44 --- /dev/null +++ b/backport-io-util-protect-against-INT_MAX-overflow-in-flush_fd.patch @@ -0,0 +1,53 @@ +From 57aaba3e8e1bc0b2e2b4f7155f208b961ee16d69 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 4 Jun 2025 16:05:41 +0200 +Subject: [PATCH] io-util: protect against INT_MAX overflow in flush_fd() + +(cherry picked from commit 874c4beb24ade904589bf672685752727cbb791e) +(cherry picked from commit 93fc50ec2b3f505e20774dda45b37f1b594a4226) +(cherry picked from commit a332cc7f6a444e8f738476c2cc12d93ef286cf24) +--- + src/basic/io-util.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/basic/io-util.c b/src/basic/io-util.c +index 6bcbef3413..b1ac7bc809 100644 +--- a/src/basic/io-util.c ++++ b/src/basic/io-util.c +@@ -25,12 +25,10 @@ int flush_fd(int fd) { + int r; + + r = fd_wait_for_event(fd, POLLIN, 0); +- if (r < 0) { +- if (r == -EINTR) +- continue; +- ++ if (r == -EINTR) ++ continue; ++ if (r < 0) + return r; +- } + if (r == 0) + return count; + +@@ -38,7 +36,6 @@ int flush_fd(int fd) { + if (l < 0) { + if (errno == EINTR) + continue; +- + if (errno == EAGAIN) + return count; + +@@ -46,6 +43,9 @@ int flush_fd(int fd) { + } else if (l == 0) + return count; + ++ if (l > INT_MAX-count) /* On overflow terminate */ ++ return INT_MAX; ++ + count += (int) l; + } + } +-- +2.43.0 + diff --git a/backport-locale-util-fix-argument-for-munmap.patch b/backport-locale-util-fix-argument-for-munmap.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1c7420e29c7029772a7fddf201216ca6068e4d5 --- /dev/null +++ b/backport-locale-util-fix-argument-for-munmap.patch @@ -0,0 +1,40 @@ +From 4c4d6537539d60254d8fcee5f20072a1485b3209 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 11 Apr 2025 09:11:05 +0900 +Subject: [PATCH] locale-util: fix argument for munmap() + +(cherry picked from commit 90abb64fd508e8efd937178b3379a62ac97b49ec) +(cherry picked from commit 445b4931807089bb7c7b12a8b09f3a580f63f643) +(cherry picked from commit 7aba5ce344592df9bb59c36695a35fcab580df34) + +--- + src/basic/locale-util.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c +index 7441fe1..fa5697a 100644 +--- a/src/basic/locale-util.c ++++ b/src/basic/locale-util.c +@@ -98,7 +98,6 @@ static int add_locales_from_archive(Set *locales) { + const struct namehashent *e; + const void *p = MAP_FAILED; + _cleanup_close_ int fd = -1; +- size_t sz = 0; + struct stat st; + int r; + +@@ -155,9 +154,9 @@ static int add_locales_from_archive(Set *locales) { + + r = 0; + +- finish: ++finish: + if (p != MAP_FAILED) +- munmap((void*) p, sz); ++ munmap((void*) p, st.st_size); + + return r; + } +-- +2.43.0 + diff --git a/backport-sd-daemon-add-fd-array-size-safety-check-to-sd_notif.patch b/backport-sd-daemon-add-fd-array-size-safety-check-to-sd_notif.patch new file mode 100644 index 0000000000000000000000000000000000000000..db97f577cd88255b0efaf620635249e4b7fd1e58 --- /dev/null +++ b/backport-sd-daemon-add-fd-array-size-safety-check-to-sd_notif.patch @@ -0,0 +1,72 @@ +From 67347ca20c17c695786d42e3f754b25b02d5c0fc Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 4 Nov 2024 11:18:29 +0100 +Subject: [PATCH] sd-daemon: add fd array size safety check to + sd_notify_with_fds() + +The previous commit removed the UINT_MAX check for the fd array. Let's +now re-add one, but at a better place, and with a more useful limit. As +it turns out the kernel does not allow passing more than 253 fds at the +same time, hence use that as limit. And do so immediately before +calculating the control buffer size, so that we catch multiplication +overflows. + +(cherry picked from commit cb42df5310e701b751331ae62432e3fb0df2f660) +(cherry picked from commit 3fe78b02280d11746afc979dfed561dbc3fc2554) + +--- + src/basic/missing_socket.h | 7 +++++++ + src/libsystemd/sd-daemon/sd-daemon.c | 8 ++++++++ + src/notify/notify.c | 2 ++ + 3 files changed, 17 insertions(+) + +diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h +index 30ac297..c4b124c 100644 +--- a/src/basic/missing_socket.h ++++ b/src/basic/missing_socket.h +@@ -79,3 +79,10 @@ struct sockaddr_vm { + #ifndef SIOCGSKNS + #define SIOCGSKNS 0x894C + #endif ++ ++/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant, but very much ++ * useful for userspace too. It's documented in unix(7) these days, hence should be fairly reliable to define ++ * here. */ ++#ifndef SCM_MAX_FD ++#define SCM_MAX_FD 253U ++#endif +diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c +index b373c17..701d678 100644 +--- a/src/libsystemd/sd-daemon/sd-daemon.c ++++ b/src/libsystemd/sd-daemon/sd-daemon.c +@@ -466,6 +466,14 @@ _public_ int sd_pid_notify_with_fds( + r = -EINVAL; + goto finish; + } ++ ++ /* Let's make sure the multiplications below don't overflow, and also return a recognizable error in ++ * case the caller tries to send more fds than the kernel limit. The kernel would return EINVAL which ++ * is not too useful I'd say. */ ++ if (n_fds > SCM_MAX_FD){ ++ r = -E2BIG; ++ goto finish; ++ } + + e = getenv("NOTIFY_SOCKET"); + if (!e) +diff --git a/src/notify/notify.c b/src/notify/notify.c +index ad0ae89..758d7a6 100644 +--- a/src/notify/notify.c ++++ b/src/notify/notify.c +@@ -407,6 +407,8 @@ static int run(int argc, char* argv[]) { + r = sd_pid_notify_with_fds(source_pid, /* unset_environment= */ false, n, a, k); + + } ++ if (r == -E2BIG) ++ return log_error_errno(r, "Too many file descriptors passed."); + if (r < 0) + return log_error_errno(r, "Failed to notify init system: %m"); + if (r == 0) +-- +2.43.0 + diff --git a/backport-shared-calendarspec-fix-normalization-when-DST-is-ne.patch b/backport-shared-calendarspec-fix-normalization-when-DST-is-ne.patch new file mode 100644 index 0000000000000000000000000000000000000000..6849fefefa53085d9709a72c4de46fd02a2e4c2e --- /dev/null +++ b/backport-shared-calendarspec-fix-normalization-when-DST-is-ne.patch @@ -0,0 +1,184 @@ +From f3dc34ec87344f796836ef3b4a98d5e2e099fa14 Mon Sep 17 00:00:00 2001 +From: kmeaw +Date: Sun, 30 Mar 2025 13:08:38 +0100 +Subject: [PATCH] shared/calendarspec: fix normalization when DST is negative + +When trying to calculate the next firing of 'hourly', we'd lose the +tm_isdst value on the next iteration. + +On most systems in Europe/Dublin it would cause a 100% cpu hang due to +timers restarting. + +This happens in Europe/Dublin because Ireland defines the Irish Standard Time +as UTC+1, so winter time is encoded in tzdata as negative 1 hour of daylight +saving. + +Before this patch: +$ env TZ=IST-1GMT-0,M10.5.0/1,M3.5.0/1 systemd-analyze calendar --base-time='Sat 2025-03-29 22:00:00 UTC' --iterations=5 'hourly' + Original form: hourly +Normalized form: *-*-* *:00:00 + Next elapse: Sat 2025-03-29 23:00:00 GMT + (in UTC): Sat 2025-03-29 23:00:00 UTC + From now: 13h ago + Iteration #2: Sun 2025-03-30 00:00:00 GMT + (in UTC): Sun 2025-03-30 00:00:00 UTC + From now: 12h ago + Iteration #3: Sun 2025-03-30 00:00:00 GMT <-- note every next iteration having the same firing time + (in UTC): Sun 2025-03-30 00:00:00 UTC + From now: 12h ago +... + +With this patch: +$ env TZ=IST-1GMT-0,M10.5.0/1,M3.5.0/1 systemd-analyze calendar --base-time='Sat 2025-03-29 22:00:00 UTC' --iterations=5 'hourly' + Original form: hourly +Normalized form: *-*-* *:00:00 + Next elapse: Sat 2025-03-29 23:00:00 GMT + (in UTC): Sat 2025-03-29 23:00:00 UTC + From now: 13h ago + Iteration #2: Sun 2025-03-30 00:00:00 GMT + (in UTC): Sun 2025-03-30 00:00:00 UTC + From now: 12h ago + Iteration #3: Sun 2025-03-30 02:00:00 IST <-- the expected 1 hour jump + (in UTC): Sun 2025-03-30 01:00:00 UTC + From now: 11h ago +... + +This bug isn't reproduced on Debian and Ubuntu because they mitigate it by +using the rearguard version of tzdata. ArchLinux and NixOS don't, so it would +cause pid1 to spin during DST transition. + +This is how the affected tzdata looks like: +$ zdump -V -c 2024,2025 Europe/Dublin +Europe/Dublin Sun Mar 31 00:59:59 2024 UT = Sun Mar 31 00:59:59 2024 GMT isdst=1 gmtoff=0 +Europe/Dublin Sun Mar 31 01:00:00 2024 UT = Sun Mar 31 02:00:00 2024 IST isdst=0 gmtoff=3600 +Europe/Dublin Sun Oct 27 00:59:59 2024 UT = Sun Oct 27 01:59:59 2024 IST isdst=0 gmtoff=3600 +Europe/Dublin Sun Oct 27 01:00:00 2024 UT = Sun Oct 27 01:00:00 2024 GMT isdst=1 gmtoff=0 + +Compare it to Europe/London: +$ zdump -V -c 2024,2025 Europe/London +Europe/London Sun Mar 31 00:59:59 2024 UT = Sun Mar 31 00:59:59 2024 GMT isdst=0 gmtoff=0 +Europe/London Sun Mar 31 01:00:00 2024 UT = Sun Mar 31 02:00:00 2024 BST isdst=1 gmtoff=3600 +Europe/London Sun Oct 27 00:59:59 2024 UT = Sun Oct 27 01:59:59 2024 BST isdst=1 gmtoff=3600 +Europe/London Sun Oct 27 01:00:00 2024 UT = Sun Oct 27 01:00:00 2024 GMT isdst=0 gmtoff=0 + +Fixes #32039. + +(cherry picked from commit e4bb033e2fcea504f7496df90be7a3556fcea44b) +(cherry picked from commit 07c01efc82d4a239ef0d14da54d36053294ad203) + +There were some conflicts related to the skipping of +6f5cf41570776f489967d1a7de18260b2bc9acf9, but the tests pass with and the +example output above also looks good, so I think the backport is correct. + +(cherry picked from commit 1568dea89ebb84ed2c9cf8c45aaf90c07858cbc0) + +--- + src/shared/calendarspec.c | 48 +++++++++++++++++++++++++++++++++--- + src/test/test-calendarspec.c | 5 ++-- + 2 files changed, 48 insertions(+), 5 deletions(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index 238766c..724ba1e 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -1237,14 +1237,43 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { + return (weekdays_bits & (1 << k)); + } + ++static int tm_compare(const struct tm *t1, const struct tm *t2) { ++ int r; ++ ++ assert(t1); ++ assert(t2); ++ ++ r = CMP(t1->tm_year, t2->tm_year); ++ if (r != 0) ++ return r; ++ ++ r = CMP(t1->tm_mon, t2->tm_mon); ++ if (r != 0) ++ return r; ++ ++ r = CMP(t1->tm_mday, t2->tm_mday); ++ if (r != 0) ++ return r; ++ ++ r = CMP(t1->tm_hour, t2->tm_hour); ++ if (r != 0) ++ return r; ++ ++ r = CMP(t1->tm_min, t2->tm_min); ++ if (r != 0) ++ return r; ++ ++ return CMP(t1->tm_sec, t2->tm_sec); ++} ++ + /* A safety valve: if we get stuck in the calculation, return an error. + * C.f. https://bugzilla.redhat.com/show_bug.cgi?id=1941335. */ + #define MAX_CALENDAR_ITERATIONS 1000 + + static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + struct tm c; +- int tm_usec; +- int r; ++ int tm_usec, r; ++ bool invalidate_dst = false; + + /* Returns -ENOENT if the expression is not going to elapse anymore */ + +@@ -1257,7 +1286,8 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + for (unsigned iteration = 0; iteration < MAX_CALENDAR_ITERATIONS; iteration++) { + /* Normalize the current date */ + (void) mktime_or_timegm(&c, spec->utc); +- c.tm_isdst = spec->dst; ++ if (!invalidate_dst) ++ c.tm_isdst = spec->dst; + + c.tm_year += 1900; + r = find_matching_component(spec, spec->year, &c, &c.tm_year); +@@ -1347,6 +1377,18 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { + if (r == 0) + continue; + ++ r = tm_compare(tm, &c); ++ if (r == 0) { ++ assert(tm_usec + 1 <= 1000000); ++ r = CMP(*usec, (usec_t) tm_usec + 1); ++ } ++ if (r >= 0) { ++ /* We're stuck - advance, let mktime determine DST transition and try again. */ ++ invalidate_dst = true; ++ c.tm_hour++; ++ continue; ++ } ++ + *tm = c; + *usec = tm_usec; + return 0; +diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c +index bc5e56a..2e3147d 100644 +--- a/src/test/test-calendarspec.c ++++ b/src/test/test-calendarspec.c +@@ -44,7 +44,7 @@ static void _test_next(int line, const char *input, const char *new_tz, usec_t a + if (old_tz) + old_tz = strdupa(old_tz); + +- if (!isempty(new_tz)) ++ if (!isempty(new_tz) && !strchr(new_tz, ',')) + new_tz = strjoina(":", new_tz); + + assert_se(set_unset_env("TZ", new_tz, true) == 0); +@@ -219,7 +219,8 @@ int main(int argc, char* argv[]) { + /* Check that we don't start looping if mktime() moves us backwards */ + test_next("Sun *-*-* 01:00:00 Europe/Dublin", "", 1616412478000000, 1617494400000000); + test_next("Sun *-*-* 01:00:00 Europe/Dublin", "IST", 1616412478000000, 1617494400000000); +- ++ /* Europe/Dublin TZ that moves DST backwards */ ++ test_next("hourly", "IST-1GMT-0,M10.5.0/1,M3.5.0/1", 1743292800000000, 1743296400000000); + assert_se(calendar_spec_from_string("test", &c) < 0); + assert_se(calendar_spec_from_string(" utc", &c) < 0); + assert_se(calendar_spec_from_string(" ", &c) < 0); +-- +2.43.0 + diff --git a/backport-shutdown-handle-gracefully-if-a-device-disappears-wh.patch b/backport-shutdown-handle-gracefully-if-a-device-disappears-wh.patch new file mode 100644 index 0000000000000000000000000000000000000000..90665683afe5b10d75a36e89d32de5d78019d04d --- /dev/null +++ b/backport-shutdown-handle-gracefully-if-a-device-disappears-wh.patch @@ -0,0 +1,121 @@ +From 9ffa0a596cd3ecde490def862adc8bcf3ad804c9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 17 Apr 2025 14:39:34 +0200 +Subject: [PATCH] shutdown: handle gracefully if a device disappears while we + detach it + +Let's gracefully handle cases where a device disappears in the time we +between our discovery and when we want to detach it, due to "auto-clear" +or a similar logic. + +The loopback case already handled this quite OK, do the same for MD and +swap too. + +Switch to ERRNO_IS_DEVICE_ABSENT() for all checks, just in case. + +Also improve debug logging for all these cases, so we know exactly what +is going on. + +This is inspired by #37160, but shouldn't really fix anything there, I +am pretty sure the ENODEV seen in that output stems from the STOP_ARRAY +call, not from the open(). + +Note that this does not change anything for the device mapper case, +because the DM subsystem does not return useful error codes to +userspace, hence everything is a complete mess there. + +(cherry picked from commit 2791b2bc3d84efe674d05e45fa85333eea05ad6f) +(cherry picked from commit 4f0a4976dfe64399bc5a3c6b8f00675e2548b067) +(cherry picked from commit fc1d80f5b31f629ee03cfd0c0cabaa67aa646dd8) + +--- + src/shutdown/umount.c | 38 ++++++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 12 deletions(-) + +diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c +index eed9c31..6eb206d 100644 +--- a/src/shutdown/umount.c ++++ b/src/shutdown/umount.c +@@ -406,8 +406,12 @@ static int delete_loopback(const char *device) { + + fd = open(device, O_RDONLY|O_CLOEXEC); + if (fd < 0) { +- log_debug_errno(errno, "Failed to open loopback device %s: %m", device); +- return errno == ENOENT ? 0 : -errno; ++ if (ERRNO_IS_DEVICE_ABSENT(errno)) { ++ log_debug_errno(errno, "Tried to open loopback device '%s', but device disappeared by now, ignoring: %m", device); ++ return 0; ++ } ++ ++ return log_debug_errno(errno, "Failed to open loopback device '%s': %m", device); + } + + /* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly +@@ -513,15 +517,21 @@ static int delete_md(MountPoint *m) { + assert(m->path); + + fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL); +- if (fd < 0) +- return -errno; ++ if (fd < 0) { ++ if (ERRNO_IS_DEVICE_ABSENT(errno)) { ++ log_debug_errno(errno, "Tried to open MD device '%s', but device disappeared by now, ignoring: %m", m->path); ++ return 0; ++ } ++ ++ return log_debug_errno(errno, "Failed to open MD device '%s': %m", m->path); ++ } + + (void) sync_with_progress(fd); + + if (ioctl(fd, STOP_ARRAY, NULL) < 0) +- return -errno; ++ return log_debug_errno(errno, "Failed to issue STOP_ARRAY on MD device '%s': %m", m->path); + +- return 0; ++ return 1; + } + + static bool nonunmountable_path(const char *path) { +@@ -663,20 +673,23 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, int umount + + static int swap_points_list_off(MountPoint **head, bool *changed) { + MountPoint *m, *n; +- int n_failed = 0; ++ int n_failed = 0, r; + + assert(head); + assert(changed); + + LIST_FOREACH_SAFE(mount_point, m, n, *head) { + log_info("Deactivating swap %s.", m->path); +- if (swapoff(m->path) < 0) { +- log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path); ++ r = RET_NERRNO(swapoff(m->path)); ++ if (IN_SET(r, -ENODEV, -ENXIO, -ENOENT)) ++ log_debug_errno(r, "Tried to deactivate swap '%s', but swap disappeared by now, ignoring: %m", m->path); ++ else if (r < 0) { ++ log_warning_errno(r, "Could not deactivate swap %s: %m", m->path); + n_failed++; + continue; +- } ++ } else ++ *changed = true; + +- *changed = true; + mount_point_free(head, m); + } + +@@ -770,7 +783,8 @@ static int md_points_list_detach(MountPoint **head, bool *changed, int umount_lo + continue; + } + +- *changed = true; ++ if (r > 0) ++ *changed = true; + mount_point_free(head, m); + } + +-- +2.43.0 + diff --git a/backport-test-add-a-couple-of-tests-for-busctl.patch b/backport-test-add-a-couple-of-tests-for-busctl.patch new file mode 100644 index 0000000000000000000000000000000000000000..c5b3203436fe3117041e6968844245b9692e8622 --- /dev/null +++ b/backport-test-add-a-couple-of-tests-for-busctl.patch @@ -0,0 +1,121 @@ +From 16600a86617eee46f4e65c9fb0feda08cee74da6 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 7 Mar 2023 18:44:20 +0100 +Subject: [PATCH] test: add a couple of tests for busctl + +--- + test/units/testsuite-74.busctl.sh | 102 ++++++++++++++++++++++++++++++ + 1 file changed, 102 insertions(+) + create mode 100755 test/units/testsuite-74.busctl.sh + +diff --git a/test/units/testsuite-74.busctl.sh b/test/units/testsuite-74.busctl.sh +new file mode 100755 +index 0000000000..44d8032d8b +--- /dev/null ++++ b/test/units/testsuite-74.busctl.sh +@@ -0,0 +1,102 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -eux ++set -o pipefail ++ ++# Unset $PAGER so we don't have to use --no-pager everywhere ++export PAGER= ++ ++busctl --help ++busctl help ++busctl --version ++busctl ++busctl list --no-pager --allow-interactive-authorization=no ++busctl list ++busctl list --unique --show-machine --full ++# Pass the JSON output (-j) through jq to check if it's valid ++busctl list --acquired --activatable --no-legend -j | jq ++busctl status ++busctl status --machine=.host --augment-creds=no ++busctl status --user --machine=testuser@.host ++busctl status org.freedesktop.systemd1 ++busctl tree ++busctl tree org.freedesktop.login1 ++busctl tree --list org.freedesktop.login1 ++busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd1 ++busctl introspect --watch-bind=yes --xml-interface org.freedesktop.systemd1 /org/freedesktop/LogControl1 ++busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ++ ++busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ GetDefaultTarget ++# Pass both JSON outputs through jq to check if the response JSON is valid ++busctl call --json=pretty \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ListUnitsByNames as 2 "systemd-journald.service" "systemd-logind.service" | jq ++busctl call --json=short \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ListUnitsByNames as 2 "systemd-journald.service" "systemd-logind.service" | jq ++busctl call --verbose --timeout=60 --expect-reply=yes \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ListUnitsByPatterns asas 1 "active" 2 "systemd-*.socket" "*.mount" ++ ++busctl emit /org/freedesktop/login1 org.freedesktop.login1.Manager \ ++ PrepareForSleep b false ++busctl emit --auto-start=no --destination=systemd-logind.service \ ++ /org/freedesktop/login1 org.freedesktop.login1.Manager \ ++ PrepareForShutdown b false ++ ++busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ Version ++busctl get-property --verbose \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ LogLevel LogTarget SystemState Version ++# Pass both JSON outputs through jq to check if the response JSON is valid ++busctl get-property --json=pretty \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ LogLevel LogTarget SystemState Version | jq ++busctl get-property --json=short \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ LogLevel LogTarget SystemState Version | jq ++ ++# Set a property and check if it was indeed set ++busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ KExecWatchdogUSec t 666 ++busctl get-property -j \ ++ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ KExecWatchdogUSec | jq -e '.data == 666' ++ ++(! busctl status org.freedesktop.systemd2) ++(! busctl tree org.freedesktop.systemd2) ++(! busctl introspect org.freedesktop.systemd1) ++(! busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd2) ++(! busctl introspect org.freedesktop.systemd2 /org/freedesktop/systemd1) ++ ++# Invalid method ++(! busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ThisMethodDoesntExist) ++# Invalid signature ++(! busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ListUnitsByNames ab 1 false) ++# Invalid arguments ++(! busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ GetUnitByPID u "hello") ++(! busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ -- ListUnitsByNames as -1 "systemd-journald.service") ++# Not enough arguments ++(! busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ ListUnitsByNames as 99 "systemd-journald.service") ++ ++(! busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ NonexistentProperty) ++(! busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ Version NonexistentProperty Version) ++ ++# Invalid property ++(! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ NonexistentProperty t 666) ++# Invalid signature ++(! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ KExecWatchdogUSec s 666) ++# Invalid argument ++(! busctl set-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ++ KExecWatchdogUSec t "foo") +-- +2.43.0 + diff --git a/backport-test-add-test-case-for-issue-36031.patch b/backport-test-add-test-case-for-issue-36031.patch new file mode 100644 index 0000000000000000000000000000000000000000..e845f49e287d2c6cbfb644b06b3d9cfeb6583539 --- /dev/null +++ b/backport-test-add-test-case-for-issue-36031.patch @@ -0,0 +1,94 @@ +From ad5812a16c9d06fd61aa27ab05fecd84caee8b78 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 15 May 2025 13:45:13 +0900 +Subject: [PATCH] test: add test case for issue #36031 + +(cherry picked from commit 7824e70a074316ff799cbbc98af4f9ba944d6535) +(cherry picked from commit 0846c1414402fc67080c90d235c543ec54576315) +(cherry picked from commit b756d7d74e9d352a11c6e0041f8832f84797bca4) +--- + .../testsuite-23.start-stop-no-reload.sh | 64 ++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/test/units/testsuite-23.start-stop-no-reload.sh b/test/units/testsuite-23.start-stop-no-reload.sh +index 9c4f17d7a2..6039f15424 100755 +--- a/test/units/testsuite-23.start-stop-no-reload.sh ++++ b/test/units/testsuite-23.start-stop-no-reload.sh +@@ -10,7 +10,14 @@ set -o pipefail + at_exit() { + set +e + +- rm -f /run/systemd/system/testsuite-23-no-reload.{service,target} ++ rm -f /run/systemd/system/testsuite-23-no-reload.target ++ rm -f /run/systemd/system/testsuite-23-no-reload.service ++ rm -f /run/systemd/system/testsuite-23-no-reload-2.service ++ rm -f /run/systemd/system/testsuite-23-no-reload-3.service ++ systemctl stop testsuite-23-no-reload.target ++ systemctl stop testsuite-23-no-reload.service ++ systemctl stop testsuite-23-no-reload-2.service ++ systemctl stop testsuite-23-no-reload-3.service + } + + trap at_exit EXIT +@@ -91,3 +98,58 @@ EOF + systemctl restart testsuite-23-no-reload.target + + systemctl is-active testsuite-23-no-reload.service ++ ++# Stop and remove, and try again to exercise https://github.com/systemd/systemd/issues/36031 ++systemctl stop testsuite-23-no-reload.service testsuite-23-no-reload.target ++rm -f /run/systemd/system/testsuite-23-no-reload.service /run/systemd/system/testsuite-23-no-reload.target ++systemctl daemon-reload ++ ++sleep 3.1 ++ ++cat >/run/systemd/system/testsuite-23-no-reload.target </run/systemd/system/testsuite-23-no-reload.service </run/systemd/system/testsuite-23-no-reload-2.service </run/systemd/system/testsuite-23-no-reload-3.service < +Date: Tue, 16 May 2023 20:41:35 +0200 +Subject: [PATCH] test: merge TEST-48-START-STOP-NO-RELOAD into + TEST-23-UNIT-FILE + +--- + test/TEST-48-START-STOP-NO-RELOAD/Makefile | 1 - + test/TEST-48-START-STOP-NO-RELOAD/test.sh | 11 ---- + ...h => testsuite-23.start-stop-no-reload.sh} | 59 +++++++++++-------- + test/units/testsuite-48.service | 7 --- + 4 files changed, 33 insertions(+), 45 deletions(-) + delete mode 120000 test/TEST-48-START-STOP-NO-RELOAD/Makefile + delete mode 100755 test/TEST-48-START-STOP-NO-RELOAD/test.sh + rename test/units/{testsuite-48.sh => testsuite-23.start-stop-no-reload.sh} (51%) + delete mode 100644 test/units/testsuite-48.service + +diff --git a/test/TEST-48-START-STOP-NO-RELOAD/Makefile b/test/TEST-48-START-STOP-NO-RELOAD/Makefile +deleted file mode 120000 +index e9f93b1..0000000 +--- a/test/TEST-48-START-STOP-NO-RELOAD/Makefile ++++ /dev/null +@@ -1 +0,0 @@ +-../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-48-START-STOP-NO-RELOAD/test.sh b/test/TEST-48-START-STOP-NO-RELOAD/test.sh +deleted file mode 100755 +index d1abc8a..0000000 +--- a/test/TEST-48-START-STOP-NO-RELOAD/test.sh ++++ /dev/null +@@ -1,11 +0,0 @@ +-#!/usr/bin/env bash +-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +-# ex: ts=8 sw=4 sts=4 et filetype=sh +-set -e +- +-TEST_DESCRIPTION="test StartStopNoReload" +- +-# shellcheck source=test/test-functions +-. "${TEST_BASE_DIR:?}/test-functions" +- +-do_test "$@" +diff --git a/test/units/testsuite-48.sh b/test/units/testsuite-23.start-stop-no-reload.sh +similarity index 51% +rename from test/units/testsuite-48.sh +rename to test/units/testsuite-23.start-stop-no-reload.sh +index 147f6fa..62a6584 100755 +--- a/test/units/testsuite-48.sh ++++ b/test/units/testsuite-23.start-stop-no-reload.sh +@@ -2,44 +2,55 @@ + # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- + # ex: ts=8 sw=4 sts=4 et filetype=sh + set -eux ++set -o pipefail + +-cat >/run/systemd/system/testservice-48.target </run/systemd/system/testsuite-23-no-reload.target </run/systemd/system/testservice-48.service </run/systemd/system/testsuite-23-no-reload.service </run/systemd/system/testservice-48.service </run/systemd/system/testsuite-23-no-reload.service </run/systemd/system/testservice-48.target </run/systemd/system/testsuite-23-no-reload.target </run/systemd/system/testservice-48.service </run/systemd/system/testsuite-23-no-reload.service </testok ++systemctl restart testsuite-23-no-reload.target + +-exit 0 ++systemctl is-active testsuite-23-no-reload.service +diff --git a/test/units/testsuite-48.service b/test/units/testsuite-48.service +deleted file mode 100644 +index 9dc50ab..0000000 +--- a/test/units/testsuite-48.service ++++ /dev/null +@@ -1,7 +0,0 @@ +-[Unit] +-Description=TEST-48-START-STOP-NO-RELOAD +- +-[Service] +-ExecStartPre=rm -f /failed /testok +-ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +-Type=oneshot +-- +2.43.0 + diff --git a/systemd.spec b/systemd.spec index 83f5733b3c44177d1aa512a25972207929168774..19e0f4405912f053a0294d659171f73369a8bb0d 100644 --- a/systemd.spec +++ b/systemd.spec @@ -25,7 +25,7 @@ Name: systemd Url: https://systemd.io/ Version: 249 -Release: 104 +Release: 105 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -749,6 +749,22 @@ Patch6695: backport-0001-coredump-get-rid-of-a-bogus-assertion.patch #fix ISSUE[#ICVCYY] Patch6696: backport-systemctl-fix-memleak.patch +Patch6697: backport-sd-daemon-add-fd-array-size-safety-check-to-sd_notif.patch +Patch6698: backport-flush_ports-flush-POSIX-message-queues-properly.patch +Patch6699: backport-initctl-fix-error-handling.patch +Patch6700: backport-locale-util-fix-argument-for-munmap.patch +Patch6701: backport-test-add-a-couple-of-tests-for-busctl.patch +Patch6702: backport-busctl-validate-argvs-on-get-property-set-property-t.patch +Patch6703: backport-shared-calendarspec-fix-normalization-when-DST-is-ne.patch +Patch6704: backport-io-util-protect-against-INT_MAX-overflow-in-flush_fd.patch +Patch6705: backport-compress-prevent-divide-by-zero-when-no-data-is-read.patch +Patch6706: backport-core-transaction-drop-redundant-call-of-bus_unit_val.patch +Patch6707: backport-core-transaction-do-not-override-unit-load-state-whe.patch +Patch6708: backport-core-introduce-Unit.dependency_generation-counter-an.patch +Patch6709: backport-test-merge-TEST-48-START-STOP-NO-RELOAD-into-TEST-23.patch +Patch6710: backport-test-add-test-case-for-issue-36031.patch +Patch6711: backport-shutdown-handle-gracefully-if-a-device-disappears-wh.patch + Patch9001: update-rtc-with-system-clock-when-shutdown.patch Patch9002: udev-add-actions-while-rename-netif-failed.patch Patch9003: fix-two-VF-virtual-machines-have-same-mac-address.patch @@ -2264,6 +2280,9 @@ grep -q -E '^KEYMAP="?fi-latin[19]"?' /etc/vconsole.conf 2>/dev/null && /usr/bin/systemd-cryptenroll %changelog +* Wed Oct 22 2025 Linux_zhang - 249-105 +- sync patch from systemd community + * Wed Sep 03 2025 Linux_zhang - 249-104 - sync patch from systemd community