Version in base suite: 252.39-1~deb12u1 Base version: systemd_252.39-1~deb12u1 Target version: systemd_252.39-1~deb12u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/systemd/systemd_252.39-1~deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/systemd/systemd_252.39-1~deb12u2.dsc changelog | 15 + patches/CVE-2026-29111-1.patch | 170 +++++++++++++++++ patches/CVE-2026-29111-2.patch | 89 ++++++++ patches/CVE-2026-29111-3.patch | 96 +++++++++ patches/CVE-2026-29111-4.patch | 30 +++ patches/CVE-2026-40225.patch | 122 ++++++++++++ patches/CVE-2026-40226-1.patch | 56 +++++ patches/CVE-2026-40226-2.patch | 33 +++ patches/CVE-2026-4105.patch | 28 ++ patches/series | 9 patches/test-cgroup-Ignore-ENOENT-from-cg_create.patch | 28 ++ 11 files changed, 676 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpg9kgsink/systemd_252.39-1~deb12u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpg9kgsink/systemd_252.39-1~deb12u2.dsc: no acceptable signature found diff: /srv/release.debian.org/tmp/y1rhlEx6cC/systemd-252.39/test/testdata: recursive directory loop diff -Nru systemd-252.39/debian/changelog systemd-252.39/debian/changelog --- systemd-252.39/debian/changelog 2025-06-26 14:58:40.000000000 +0000 +++ systemd-252.39/debian/changelog 2026-04-27 19:48:55.000000000 +0000 @@ -1,3 +1,18 @@ +systemd (252.39-1~deb12u2) bookworm; urgency=medium + + [ Arnaud Rebillout ] + * test-cgroup: Ignore ENOENT from cg_create() + * CVE-2026-4105 (A flaw was found in systemd. The systemd-machined service + contains an ...) + * CVE-2026-29111 (systemd, a system and service manager, (as PID 1) hits an + assert and f ...) + * CVE-2026-40225 (In udev in systemd before 260, local root execution can + occur via mali ...) + * CVE-2026-40226 (In nspawn in systemd 233 through 259 before 260, an + escape-to-host act ...) + + -- Tobias Deiminger Mon, 27 Apr 2026 21:48:55 +0200 + systemd (252.39-1~deb12u1) bookworm; urgency=medium * New upstream version 252.39 diff -Nru systemd-252.39/debian/patches/CVE-2026-29111-1.patch systemd-252.39/debian/patches/CVE-2026-29111-1.patch --- systemd-252.39/debian/patches/CVE-2026-29111-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-29111-1.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,170 @@ +From: Lennart Poettering +Date: Mon, 19 May 2025 12:58:52 +0200 +Subject: path-util: add flavour of path_startswith() that leaves a leading + slash in place + +(cherry picked from commit ee19edbb9f3455db3f750089082f3e5a925e3a0c) + +Origin: backport, https://github.com/systemd/systemd/commit/20021e7686426052e3a7505425d7e12085feb2a6 +--- + src/basic/fs-util.c | 2 +- + src/basic/mkdir.c | 4 ++-- + src/basic/path-util.c | 39 ++++++++++++++++++++++++++++----------- + src/basic/path-util.h | 10 ++++++++-- + src/test/test-path-util.c | 16 ++++++++++++++++ + 5 files changed, 55 insertions(+), 16 deletions(-) + +diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c +index d71c07c..9950ff3 100644 +--- a/src/basic/fs-util.c ++++ b/src/basic/fs-util.c +@@ -67,7 +67,7 @@ int rmdir_parents(const char *path, const char *stop) { + assert(*slash == '/'); + *slash = '\0'; + +- if (path_startswith_full(stop, p, /* accept_dot_dot= */ false)) ++ if (path_startswith_full(stop, p, /* flags= */ 0)) + return 0; + + if (rmdir(p) < 0 && errno != ENOENT) +diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c +index c8ff342..478cb69 100644 +--- a/src/basic/mkdir.c ++++ b/src/basic/mkdir.c +@@ -99,7 +99,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui + assert(_mkdirat != mkdirat); + + if (prefix) { +- p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false); ++ p = path_startswith_full(path, prefix, /* flags= */ 0); + if (!p) + return -ENOTDIR; + } else +@@ -144,7 +144,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui + + s[n] = '\0'; + +- if (!prefix || !path_startswith_full(prefix, path, /* accept_dot_dot= */ false)) { ++ if (!prefix || !path_startswith_full(prefix, path, /* flags= */ 0)) { + r = mkdir_safe_internal(path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat); + if (r < 0 && r != -EEXIST) + return r; +diff --git a/src/basic/path-util.c b/src/basic/path-util.c +index 72c0d6b..0c2d08c 100644 +--- a/src/basic/path-util.c ++++ b/src/basic/path-util.c +@@ -399,8 +399,8 @@ char* path_simplify_full(char *path, PathSimplifyFlags flags) { + return path; + } + +-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) { +- assert(path); ++char* path_startswith_full(const char *original_path, const char *prefix, PathStartWithFlags flags) { ++ assert(original_path); + assert(prefix); + + /* Returns a pointer to the start of the first component after the parts matched by +@@ -413,28 +413,45 @@ char* path_startswith_full(const char *path, const char *prefix, bool accept_dot + * Returns NULL otherwise. + */ + ++ const char *path = original_path; ++ + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; + + for (;;) { + const char *p, *q; +- int r, k; ++ int m, n; + +- r = path_find_first_component(&path, accept_dot_dot, &p); +- if (r < 0) ++ m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p); ++ if (m < 0) + return NULL; + +- k = path_find_first_component(&prefix, accept_dot_dot, &q); +- if (k < 0) ++ n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q); ++ if (n < 0) + return NULL; + +- if (k == 0) +- return (char*) (p ?: path); ++ if (n == 0) { ++ if (!p) ++ p = path; ++ ++ if (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) { ++ ++ if (p <= original_path) ++ return NULL; ++ ++ p--; ++ ++ if (*p != '/') ++ return NULL; ++ } ++ ++ return (char*) p; ++ } + +- if (r != k) ++ if (m != n) + return NULL; + +- if (!strneq(p, q, r)) ++ if (!strneq(p, q, m)) + return NULL; + } + } +diff --git a/src/basic/path-util.h b/src/basic/path-util.h +index 09604ba..e083a91 100644 +--- a/src/basic/path-util.h ++++ b/src/basic/path-util.h +@@ -62,9 +62,15 @@ int safe_getcwd(char **ret); + int path_make_absolute_cwd(const char *p, char **ret); + int path_make_relative(const char *from, const char *to, char **ret); + int path_make_relative_parent(const char *from_child, const char *to, char **ret); +-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_; ++ ++typedef enum PathStartWithFlags { ++ PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0, ++ PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1, ++} PathStartWithFlags; ++ ++char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_; + static inline char* path_startswith(const char *path, const char *prefix) { +- return path_startswith_full(path, prefix, true); ++ return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT); + } + int path_compare(const char *a, const char *b) _pure_; + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 7ab9f20..6e495e6 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -671,6 +671,22 @@ TEST(path_startswith) { + test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL); + } + ++static void test_path_startswith_return_leading_slash_one(const char *path, const char *prefix, const char *expected) { ++ const char *p; ++ ++ log_debug("/* %s(%s, %s) */", __func__, path, prefix); ++ ++ p = path_startswith_full(path, prefix, PATH_STARTSWITH_RETURN_LEADING_SLASH); ++ assert_se(streq_ptr(p, expected)); ++} ++ ++TEST(path_startswith_return_leading_slash) { ++ test_path_startswith_return_leading_slash_one("/foo/bar", "/", "/foo/bar"); ++ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo", "/bar"); ++ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo/bar", NULL); ++ test_path_startswith_return_leading_slash_one("/foo/bar/", "/foo/bar", "/"); ++} ++ + static void test_prefix_root_one(const char *r, const char *p, const char *expected) { + _cleanup_free_ char *s = NULL; + const char *t; diff -Nru systemd-252.39/debian/patches/CVE-2026-29111-2.patch systemd-252.39/debian/patches/CVE-2026-29111-2.patch --- systemd-252.39/debian/patches/CVE-2026-29111-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-29111-2.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,89 @@ +From: Lennart Poettering +Date: Fri, 23 May 2025 06:45:40 +0200 +Subject: path-util: invert PATH_STARTSWITH_ACCEPT_DOT_DOT flag + +As requested: https://github.com/systemd/systemd/pull/37572#pullrequestreview-2861928094 + +(cherry picked from commit ceed11e465f1c8efff1931412a85924d9de7c08d) + +Origin: backport, https://github.com/systemd/systemd/commit/7ac3220213690e8a8d6d2a6e81e43bd1dce01d69 +--- + src/basic/fs-util.c | 2 +- + src/basic/mkdir.c | 4 ++-- + src/basic/path-util.c | 4 ++-- + src/basic/path-util.h | 4 ++-- + 4 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c +index 9950ff3..702331a 100644 +--- a/src/basic/fs-util.c ++++ b/src/basic/fs-util.c +@@ -67,7 +67,7 @@ int rmdir_parents(const char *path, const char *stop) { + assert(*slash == '/'); + *slash = '\0'; + +- if (path_startswith_full(stop, p, /* flags= */ 0)) ++ if (path_startswith_full(stop, p, PATH_STARTSWITH_REFUSE_DOT_DOT)) + return 0; + + if (rmdir(p) < 0 && errno != ENOENT) +diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c +index 478cb69..c2ec09e 100644 +--- a/src/basic/mkdir.c ++++ b/src/basic/mkdir.c +@@ -99,7 +99,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui + assert(_mkdirat != mkdirat); + + if (prefix) { +- p = path_startswith_full(path, prefix, /* flags= */ 0); ++ p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT); + if (!p) + return -ENOTDIR; + } else +@@ -144,7 +144,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui + + s[n] = '\0'; + +- if (!prefix || !path_startswith_full(prefix, path, /* flags= */ 0)) { ++ if (!prefix || !path_startswith_full(prefix, path, PATH_STARTSWITH_REFUSE_DOT_DOT)) { + r = mkdir_safe_internal(path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat); + if (r < 0 && r != -EEXIST) + return r; +diff --git a/src/basic/path-util.c b/src/basic/path-util.c +index 0c2d08c..47248c7 100644 +--- a/src/basic/path-util.c ++++ b/src/basic/path-util.c +@@ -422,11 +422,11 @@ char* path_startswith_full(const char *original_path, const char *prefix, PathSt + const char *p, *q; + int m, n; + +- m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p); ++ m = path_find_first_component(&path, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &p); + if (m < 0) + return NULL; + +- n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q); ++ n = path_find_first_component(&prefix, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &q); + if (n < 0) + return NULL; + +diff --git a/src/basic/path-util.h b/src/basic/path-util.h +index e083a91..33f4150 100644 +--- a/src/basic/path-util.h ++++ b/src/basic/path-util.h +@@ -64,13 +64,13 @@ int path_make_relative(const char *from, const char *to, char **ret); + int path_make_relative_parent(const char *from_child, const char *to, char **ret); + + typedef enum PathStartWithFlags { +- PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0, ++ PATH_STARTSWITH_REFUSE_DOT_DOT = 1U << 0, + PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1, + } PathStartWithFlags; + + char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_; + static inline char* path_startswith(const char *path, const char *prefix) { +- return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT); ++ return path_startswith_full(path, prefix, 0); + } + int path_compare(const char *a, const char *b) _pure_; + diff -Nru systemd-252.39/debian/patches/CVE-2026-29111-3.patch systemd-252.39/debian/patches/CVE-2026-29111-3.patch --- systemd-252.39/debian/patches/CVE-2026-29111-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-29111-3.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,96 @@ +From: Mike Yuan +Date: Thu, 26 Feb 2026 11:06:00 +0100 +Subject: core/cgroup: avoid one unnecessary strjoina() + +(cherry picked from commit 42aee39107fbdd7db1ccd402a2151822b2805e9f) +(cherry picked from commit 80acea4ef80a4bb78560ed970c34952299b890d6) +(cherry picked from commit b5fd14693057e5f2c9b4a49603be64ec3608ff6c) + +Origin: backport, https://github.com/systemd/systemd/commit/21167006574d6b83813c7596759b474f56562412 +--- + src/core/cgroup.c | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 89087a2..515debc 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -2268,12 +2268,13 @@ static int unit_update_cgroup( + return 0; + } + +-static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suffix_path) { ++static int unit_attach_pid_to_cgroup_via_bus(Unit *u, const char *cgroup_path, pid_t pid) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char *pp; + int r; + + assert(u); ++ assert(cgroup_path); ++ assert(pid_is_valid(pid)); + + if (MANAGER_IS_SYSTEM(u->manager)) + return -EINVAL; +@@ -2281,17 +2282,13 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf + if (!u->manager->system_bus) + return -EIO; + +- if (!u->cgroup_path) +- return -EINVAL; +- + /* Determine this unit's cgroup path relative to our cgroup root */ +- pp = path_startswith(u->cgroup_path, u->manager->cgroup_root); ++ const char *pp = path_startswith_full(cgroup_path, ++ u->manager->cgroup_root, ++ PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT); + if (!pp) + return -EINVAL; + +- pp = strjoina("/", pp, suffix_path); +- path_simplify(pp); +- + r = bus_call_method(u->manager->system_bus, + bus_systemd_mgr, + "AttachProcessesToUnit", +@@ -2330,8 +2327,10 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { + return r; + + if (isempty(suffix_path)) +- p = u->cgroup_path; ++ p = empty_to_root(u->cgroup_path); + else { ++ assert(path_is_absolute(suffix_path)); ++ + joined = path_join(u->cgroup_path, suffix_path); + if (!joined) + return -ENOMEM; +@@ -2352,7 +2351,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { + + log_unit_full_errno(u, again ? LOG_DEBUG : LOG_INFO, r, + "Couldn't move process "PID_FMT" to%s requested cgroup '%s': %m", +- pid, again ? " directly" : "", empty_to_root(p)); ++ pid, again ? " directly" : "", p); + + if (again) { + int z; +@@ -2362,9 +2361,9 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { + * Since it's more privileged it might be able to move the process across the + * leaves of a subtree whose top node is not owned by us. */ + +- z = unit_attach_pid_to_cgroup_via_bus(u, pid, suffix_path); ++ z = unit_attach_pid_to_cgroup_via_bus(u, p, pid); + if (z < 0) +- log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid, empty_to_root(p)); ++ log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid, p); + else { + if (ret >= 0) + ret++; /* Count successful additions */ +@@ -2408,7 +2407,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { + continue; /* Success! */ + + log_unit_debug_errno(u, r, "Failed to attach PID " PID_FMT " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m", +- pid, empty_to_root(p), cgroup_controller_to_string(c)); ++ pid, p, cgroup_controller_to_string(c)); + } + + /* So this controller is either not delegate or realized, or something else weird happened. In diff -Nru systemd-252.39/debian/patches/CVE-2026-29111-4.patch systemd-252.39/debian/patches/CVE-2026-29111-4.patch --- systemd-252.39/debian/patches/CVE-2026-29111-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-29111-4.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,30 @@ +From: Mike Yuan +Date: Thu, 26 Feb 2026 11:06:34 +0100 +Subject: [PATCH] core: validate input cgroup path more prudently + +(cherry picked from commit efa6ba2ab625aaa160ac435a09e6482fc63bdbe8) +(cherry picked from commit 3cee294fe8cf4fa0eff933ab21416d099942cabd) +(cherry picked from commit 1d22f706bd04f45f8422e17fbde3f56ece17758a) + +Origin: upstream, https://github.com/systemd/systemd/commit/54588d2dedff54bfb6036670820650e4ea74628f +--- + src/core/dbus-manager.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 9df3153..ac51a49 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -644,6 +644,12 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd + if (r < 0) + return r; + ++ if (!path_is_absolute(cgroup)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not absolute: %s", cgroup); ++ ++ if (!path_is_normalized(cgroup)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not normalized: %s", cgroup); ++ + u = manager_get_unit_by_cgroup(m, cgroup); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, diff -Nru systemd-252.39/debian/patches/CVE-2026-40225.patch systemd-252.39/debian/patches/CVE-2026-40225.patch --- systemd-252.39/debian/patches/CVE-2026-40225.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-40225.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,122 @@ +From: Luca Boccassi +Date: Fri, 6 Mar 2026 19:32:35 +0000 +Subject: [PATCH] udev: check for invalid chars in various fields received + from the kernel + +(cherry picked from commit 16325b35fa6ecb25f66534a562583ce3b96d52f3) +(cherry picked from commit 3513862eabe9ec4a6a095d7266e98f998f289ed2) +(cherry picked from commit c20d21e0da293e715db468f9f4a15a5c8fbf8273) + +Origin: backport, https://github.com/systemd/systemd/commit/03bb697b8df0339c37f4b845025320b261aeb7cc +--- + src/udev/dmi_memory_id/dmi_memory_id.c | 3 ++- + src/udev/scsi_id/scsi_id.c | 3 ++- + src/udev/udev-builtin-net_id.c | 15 ++++++++++++++- + src/udev/v4l_id/v4l_id.c | 5 ++++- + 4 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c +index 4793c0f..8f170d6 100644 +--- a/src/udev/dmi_memory_id/dmi_memory_id.c ++++ b/src/udev/dmi_memory_id/dmi_memory_id.c +@@ -51,6 +51,7 @@ + #include "udev-util.h" + #include "unaligned.h" + #include "version.h" ++#include "utf8.h" + + #define SUPPORTED_SMBIOS_VER 0x030300 + +@@ -185,7 +186,7 @@ static void dmi_memory_device_string( + + str = strdupa_safe(dmi_string(h, s)); + str = strstrip(str); +- if (!isempty(str)) ++ if (!isempty(str) && utf8_is_valid(str) && !string_has_cc(str, /* ok= */ NULL)) + printf("MEMORY_DEVICE_%u_%s=%s\n", slot_num, attr_suffix, str); + } + +diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c +index 364d567..f689582 100644 +--- a/src/udev/scsi_id/scsi_id.c ++++ b/src/udev/scsi_id/scsi_id.c +@@ -27,6 +27,7 @@ + #include "strxcpyx.h" + #include "udev-util.h" + #include "version.h" ++#include "utf8.h" + + static const struct option options[] = { + { "device", required_argument, NULL, 'd' }, +@@ -441,7 +442,7 @@ static int scsi_id(char *maj_min_dev) { + } + if (dev_scsi.tgpt_group[0] != '\0') + printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group); +- if (dev_scsi.unit_serial_number[0] != '\0') ++ if (dev_scsi.unit_serial_number[0] != '\0' && utf8_is_valid(dev_scsi.unit_serial_number) && !string_has_cc(dev_scsi.unit_serial_number, /* ok= */ NULL)) + printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); + goto out; + } +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 6425494..3587a1d 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -39,6 +39,7 @@ + #include "strv.h" + #include "strxcpyx.h" + #include "udev-builtin.h" ++#include "utf8.h" + + #define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1) + #define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1) +@@ -220,7 +221,13 @@ static int dev_pci_onboard(sd_device *dev, const LinkInfo *info, NetNames *names + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_onboard)); + + if (sd_device_get_sysattr_value(names->pcidev, "label", &names->pci_onboard_label) >= 0) +- log_device_debug(dev, "Onboard label from PCI device: %s", names->pci_onboard_label); ++ { ++ if (!utf8_is_valid(names->pci_onboard_label) || string_has_cc(names->pci_onboard_label, /* ok= */ NULL)) { ++ names->pci_onboard_label = NULL; ++ log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid label"); ++ } else ++ log_device_debug(dev, "Onboard label from PCI device: %s", names->pci_onboard_label); ++ } + else + names->pci_onboard_label = NULL; + +@@ -1083,6 +1090,12 @@ static int get_link_info(sd_device *dev, LinkInfo *info) { + return r; + + (void) sd_device_get_sysattr_value(dev, "phys_port_name", &info->phys_port_name); ++ if (!isempty(info->phys_port_name)) { ++ if (!utf8_is_valid(info->phys_port_name) || string_has_cc(info->phys_port_name, /* ok= */ NULL)) { ++ info->phys_port_name = NULL; ++ log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid phys_port_name"); ++ } ++ } + + r = sd_device_get_sysattr_value(dev, "address", &s); + if (r < 0 && r != -ENOENT) +diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c +index c2312c7..f363441 100644 +--- a/src/udev/v4l_id/v4l_id.c ++++ b/src/udev/v4l_id/v4l_id.c +@@ -28,6 +28,8 @@ + + #include "fd-util.h" + #include "util.h" ++#include "string-util.h" ++#include "utf8.h" + + int main(int argc, char *argv[]) { + static const struct option options[] = { +@@ -66,7 +68,8 @@ int main(int argc, char *argv[]) { + if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) { + int capabilities; + printf("ID_V4L_VERSION=2\n"); +- printf("ID_V4L_PRODUCT=%s\n", v2cap.card); ++ if (utf8_is_valid((char *)v2cap.card) && !string_has_cc((char *)v2cap.card, /* ok= */ NULL)) ++ printf("ID_V4L_PRODUCT=%s\n", v2cap.card); + printf("ID_V4L_CAPABILITIES=:"); + if (v2cap.capabilities & V4L2_CAP_DEVICE_CAPS) + capabilities = v2cap.device_caps; diff -Nru systemd-252.39/debian/patches/CVE-2026-40226-1.patch systemd-252.39/debian/patches/CVE-2026-40226-1.patch --- systemd-252.39/debian/patches/CVE-2026-40226-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-40226-1.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,56 @@ +From: Luca Boccassi +Date: Wed, 11 Mar 2026 12:15:26 +0000 +Subject: [PATCH] nspawn: apply BindUser/Ephemeral from settings file only if + trusted + +Originally reported on yeswehack.com as: +YWH-PGM9780-116 + +Follow-up for 2f8930449079403b26c9164b8eeac78d5af2c8df +Follow-up for a2f577fca0be79b23f61f033229b64884e7d840a + +(cherry picked from commit 61bceb1bff4b1f9c126b18dc971ca3e6d8c71c40) +(cherry picked from commit 718711ed876c870a72149eea279b819cdab14e91) +(cherry picked from commit e4db9c12957d315c0ed22c6ca87a816d0927d6dc) + +Origin: upstream, https://github.com/systemd/systemd/commit/773fd3b6e72e6c83cbb1cfc1cb20f3793db8649a +--- + src/nspawn/nspawn.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 0e27c6d..cd12042 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -4329,8 +4329,13 @@ static int merge_settings(Settings *settings, const char *path) { + } + + if ((arg_settings_mask & SETTING_EPHEMERAL) == 0 && +- settings->ephemeral >= 0) +- arg_ephemeral = settings->ephemeral; ++ settings->ephemeral >= 0) { ++ ++ if (!arg_settings_trusted) ++ log_warning("Ignoring ephemeral setting, file %s is not trusted.", path); ++ else ++ arg_ephemeral = settings->ephemeral; ++ } + + if ((arg_settings_mask & SETTING_DIRECTORY) == 0 && + settings->root) { +@@ -4498,8 +4503,13 @@ static int merge_settings(Settings *settings, const char *path) { + } + + if ((arg_settings_mask & SETTING_BIND_USER) == 0 && +- !strv_isempty(settings->bind_user)) +- strv_free_and_replace(arg_bind_user, settings->bind_user); ++ !strv_isempty(settings->bind_user)) { ++ ++ if (!arg_settings_trusted) ++ log_warning("Ignoring bind user setting, file %s is not trusted.", path); ++ else ++ strv_free_and_replace(arg_bind_user, settings->bind_user); ++ } + + if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0 && + settings->notify_ready >= 0) diff -Nru systemd-252.39/debian/patches/CVE-2026-40226-2.patch systemd-252.39/debian/patches/CVE-2026-40226-2.patch --- systemd-252.39/debian/patches/CVE-2026-40226-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-40226-2.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,33 @@ +From: Luca Boccassi +Date: Wed, 11 Mar 2026 13:27:14 +0000 +Subject: [PATCH] nspawn: normalize pivot_root paths + +Originally reported on yeswehack.com as: +YWH-PGM9780-116 + +Follow-up for b53ede699cdc5233041a22591f18863fb3fe2672 + +(cherry picked from commit 7b85f5498a958e5bb660c703b8f4a71cceed3373) +(cherry picked from commit 6566dc1451089e07090f5a114ae2eb43ed39188d) +(cherry picked from commit 1c55a0a5e26a07df828f72092ad1203e221b60db) + +Origin: upstream, https://github.com/systemd/systemd/commit/bfa0a842822c4f79da9d47f8a773fd128d8f8a0a +--- + src/nspawn/nspawn-mount.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c +index 63f59fe..0a4da9f 100644 +--- a/src/nspawn/nspawn-mount.c ++++ b/src/nspawn/nspawn-mount.c +@@ -1244,7 +1244,9 @@ int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s + + if (!path_is_absolute(root_new)) + return -EINVAL; +- if (root_old && !path_is_absolute(root_old)) ++ if (!path_is_normalized(root_new)) ++ return -EINVAL; ++ if (root_old && (!path_is_absolute(root_old) || !path_is_normalized(root_old))) + return -EINVAL; + + free_and_replace(*pivot_root_new, root_new); diff -Nru systemd-252.39/debian/patches/CVE-2026-4105.patch systemd-252.39/debian/patches/CVE-2026-4105.patch --- systemd-252.39/debian/patches/CVE-2026-4105.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/CVE-2026-4105.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,28 @@ +From: Luca Boccassi +Date: Sun, 8 Mar 2026 14:30:52 +0000 +Subject: machined: reject invalid class types when registering machines + +Follow-up for fbe550738d03b178bb004a1390e74115e904118a + +(cherry picked from commit 6df5f80bd374be1b45c52d740e88f0236da922c7) +(cherry picked from commit 497d0172416cbb5b70f96b95399d041407c223bd) +(cherry picked from commit 749e2eaf7086c91598cf7043a31919854b1c2dfe) + +Origin: backport, https://github.com/systemd/systemd/commit/6941d92dc299667036cbe264435971cec59ebc76 +--- + src/machine/machined-dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c +index 1e16046..9fb955f 100644 +--- a/src/machine/machined-dbus.c ++++ b/src/machine/machined-dbus.c +@@ -270,7 +270,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m + c = _MACHINE_CLASS_INVALID; + else { + c = machine_class_from_string(class); +- if (c < 0) ++ if (c < 0 || !IN_SET(c, MACHINE_CONTAINER, MACHINE_VM)) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter"); + } + diff -Nru systemd-252.39/debian/patches/series systemd-252.39/debian/patches/series --- systemd-252.39/debian/patches/series 2025-06-26 14:57:46.000000000 +0000 +++ systemd-252.39/debian/patches/series 2026-04-27 19:48:55.000000000 +0000 @@ -18,3 +18,12 @@ debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch debian/Downgrade-a-couple-of-warnings-to-debug.patch debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch +test-cgroup-Ignore-ENOENT-from-cg_create.patch +CVE-2026-4105.patch +CVE-2026-29111-1.patch +CVE-2026-29111-2.patch +CVE-2026-29111-3.patch +CVE-2026-29111-4.patch +CVE-2026-40225.patch +CVE-2026-40226-1.patch +CVE-2026-40226-2.patch diff -Nru systemd-252.39/debian/patches/test-cgroup-Ignore-ENOENT-from-cg_create.patch systemd-252.39/debian/patches/test-cgroup-Ignore-ENOENT-from-cg_create.patch --- systemd-252.39/debian/patches/test-cgroup-Ignore-ENOENT-from-cg_create.patch 1970-01-01 00:00:00.000000000 +0000 +++ systemd-252.39/debian/patches/test-cgroup-Ignore-ENOENT-from-cg_create.patch 2026-04-27 19:48:55.000000000 +0000 @@ -0,0 +1,28 @@ +From: Solar Designer +Date: Fri, 11 Jul 2025 00:28:14 +0200 +Subject: [PATCH] test-cgroup: Ignore ENOENT from cg_create() + +which was the only test failure building systemd-252-51.el9 in a +container, also previously reported against 252-rc1 under Gentoo +in #25015 + +(cherry picked from commit 470da651109e2636c624ac27257a7a64472192f6) + +Origin: upstream, https://github.com/systemd/systemd/commit/2fb0cb64c346e464b7189328146f7d003dc0f714 +--- + src/test/test-cgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c +index 8b86c60..f77b9f6 100644 +--- a/src/test/test-cgroup.c ++++ b/src/test/test-cgroup.c +@@ -66,7 +66,7 @@ TEST(cg_create) { + (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, test_b, /* delete_root= */ true); + + r = cg_create(SYSTEMD_CGROUP_CONTROLLER, test_a); +- if (IN_SET(r, -EPERM, -EACCES, -EROFS)) { ++ if (IN_SET(r, -EPERM, -EACCES, -EROFS, -ENOENT)) { + log_info_errno(r, "Skipping %s: %m", __func__); + return; + }