diff --git a/SPECS/systemd-bootstrap/CVE-2026-29111.patch b/SPECS/systemd-bootstrap/CVE-2026-29111.patch new file mode 100644 index 00000000000..550e26c3ca3 --- /dev/null +++ b/SPECS/systemd-bootstrap/CVE-2026-29111.patch @@ -0,0 +1,404 @@ +From 3ef7a9471fa40209e0ea7252e944f5fd667eec3e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 19 May 2025 12:58:52 +0200 +Subject: [PATCH 1/4] path-util: add flavour of path_startswith() that leaves a + leading slash in place + +(cherry picked from commit ee19edbb9f3455db3f750089082f3e5a925e3a0c) +(cherry picked from 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 552986f..8b2f6cc 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 6e2b94d..4547396 100644 +--- a/src/basic/mkdir.c ++++ b/src/basic/mkdir.c +@@ -92,7 +92,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 +@@ -137,7 +137,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, _mkdirat); + if (r < 0 && r != -EEXIST) + return r; +diff --git a/src/basic/path-util.c b/src/basic/path-util.c +index 4c952d8..9b44d57 100644 +--- a/src/basic/path-util.c ++++ b/src/basic/path-util.c +@@ -424,8 +424,8 @@ int path_simplify_and_warn( + return 0; + } + +-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 +@@ -438,28 +438,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 518f334..763d1fe 100644 +--- a/src/basic/path-util.h ++++ b/src/basic/path-util.h +@@ -57,9 +57,15 @@ char* path_make_absolute(const char *p, const char *prefix); + 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); +-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 b9c4ef4..c979424 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -541,6 +541,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(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; +-- +2.45.4 + + +From 11e05cddd5739731070b72db78a06e9b5b28ec17 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 23 May 2025 06:45:40 +0200 +Subject: [PATCH 2/4] 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) +(cherry picked from 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 8b2f6cc..5e853a8 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 4547396..361c142 100644 +--- a/src/basic/mkdir.c ++++ b/src/basic/mkdir.c +@@ -92,7 +92,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 +@@ -137,7 +137,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, _mkdirat); + if (r < 0 && r != -EEXIST) + return r; +diff --git a/src/basic/path-util.c b/src/basic/path-util.c +index 9b44d57..47266b8 100644 +--- a/src/basic/path-util.c ++++ b/src/basic/path-util.c +@@ -447,11 +447,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 763d1fe..c16c525 100644 +--- a/src/basic/path-util.h ++++ b/src/basic/path-util.h +@@ -59,13 +59,13 @@ int path_make_absolute_cwd(const char *p, char **ret); + int path_make_relative(const char *from, 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_; + +-- +2.45.4 + + +From 577010bcf18d0bfab1a2798a9ea6bf3fc5e8b34c Mon Sep 17 00:00:00 2001 +From: Mike Yuan +Date: Thu, 26 Feb 2026 11:06:00 +0100 +Subject: [PATCH 3/4] core/cgroup: avoid one unnecessary strjoina() + +(cherry picked from commit 42aee39107fbdd7db1ccd402a2151822b2805e9f) +(cherry picked from commit 80acea4ef80a4bb78560ed970c34952299b890d6) +(cherry picked from commit b5fd14693057e5f2c9b4a49603be64ec3608ff6c) +(cherry picked from commit 21167006574d6b83813c7596759b474f56562412) +--- + src/core/cgroup.c | 29 ++++++++++++++--------------- + 1 file changed, 14 insertions(+), 15 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index f58de95..5b8591c 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -2221,12 +2221,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; +@@ -2234,17 +2235,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 = sd_bus_call_method(u->manager->system_bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", +@@ -2284,9 +2281,11 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { + return r; + + if (isempty(suffix_path)) +- p = u->cgroup_path; +- else ++ p = empty_to_root(u->cgroup_path); ++ else { ++ assert(path_is_absolute(suffix_path)); + p = prefix_roota(u->cgroup_path, suffix_path); ++ } + + delegated_mask = unit_get_delegate_mask(u); + +@@ -2301,7 +2300,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; +@@ -2311,9 +2310,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 */ +@@ -2351,7 +2350,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 +-- +2.45.4 + + +From f27f67a7bc10ad8c4d86c20ab43f2f2a395eb90d Mon Sep 17 00:00:00 2001 +From: Mike Yuan +Date: Thu, 26 Feb 2026 11:06:34 +0100 +Subject: [PATCH 4/4] core: validate input cgroup path more prudently + +(cherry picked from commit efa6ba2ab625aaa160ac435a09e6482fc63bdbe8) +(cherry picked from commit 3cee294fe8cf4fa0eff933ab21416d099942cabd) +(cherry picked from commit 1d22f706bd04f45f8422e17fbde3f56ece17758a) +(cherry picked from commit 54588d2dedff54bfb6036670820650e4ea74628f) +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://raw.githubusercontent.com/microsoft/azurelinux/refs/heads/main/SPECS/systemd/ipc-0001-path-util-add-flavour-of-path_startswith-that-leaves.patch https://raw.githubusercontent.com/microsoft/azurelinux/refs/heads/main/SPECS/systemd/ipc-0002-path-util-invert-PATH_STARTSWITH_ACCEPT_DOT_DOT-flag.patch https://raw.githubusercontent.com/microsoft/azurelinux/refs/heads/main/SPECS/systemd/ipc-0003-core-cgroup-avoid-one-unnecessary-strjoina.patch https://raw.githubusercontent.com/microsoft/azurelinux/refs/heads/main/SPECS/systemd/ipc-0004-core-validate-input-cgroup-path-more-prudently.patch +--- + 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 9b64a80..a9aee2d 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -584,6 +584,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, +-- +2.45.4 + diff --git a/SPECS/systemd-bootstrap/systemd-bootstrap.spec b/SPECS/systemd-bootstrap/systemd-bootstrap.spec index 49463a72c49..b03f1231fad 100644 --- a/SPECS/systemd-bootstrap/systemd-bootstrap.spec +++ b/SPECS/systemd-bootstrap/systemd-bootstrap.spec @@ -1,7 +1,7 @@ Summary: Bootstrap version of systemd. Workaround for systemd circular dependency. Name: systemd-bootstrap Version: 250.3 -Release: 18%{?dist} +Release: 19%{?dist} License: LGPLv2+ AND GPLv2+ AND MIT Vendor: Microsoft Corporation Distribution: Azure Linux @@ -49,6 +49,7 @@ Patch7: update-cifs-for-kernel-headers-6.1.patch # 6. Build both systemd and systemd-bootstrap, validate the contents of systemd-rpm-macros and system-bootstrap-rpm-macros are identical Patch8: use-255-macros.patch Patch9: CVE-2023-7008.patch +Patch10: CVE-2026-29111.patch BuildRequires: docbook-dtd-xml BuildRequires: docbook-style-xsl BuildRequires: gettext @@ -286,6 +287,9 @@ fi %{_datadir}/pkgconfig/udev.pc %changelog +* Mon Mar 30 2026 Azure Linux Security Servicing Account - 250.3-19 +- Patch for CVE-2026-29111 + * Fri May 23 2025 Akhila Guruju - 250.3-18 - Patch CVE-2023-7008 diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index e262f089595..cd181dd1523 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -580,11 +580,11 @@ sqlite-devel-3.44.0-2.azl3.aarch64.rpm sqlite-libs-3.44.0-2.azl3.aarch64.rpm swig-4.2.1-1.azl3.aarch64.rpm swig-debuginfo-4.2.1-1.azl3.aarch64.rpm -systemd-bootstrap-250.3-18.azl3.aarch64.rpm -systemd-bootstrap-debuginfo-250.3-18.azl3.aarch64.rpm -systemd-bootstrap-devel-250.3-18.azl3.aarch64.rpm -systemd-bootstrap-libs-250.3-18.azl3.aarch64.rpm -systemd-bootstrap-rpm-macros-250.3-18.azl3.noarch.rpm +systemd-bootstrap-250.3-19.azl3.aarch64.rpm +systemd-bootstrap-debuginfo-250.3-19.azl3.aarch64.rpm +systemd-bootstrap-devel-250.3-19.azl3.aarch64.rpm +systemd-bootstrap-libs-250.3-19.azl3.aarch64.rpm +systemd-bootstrap-rpm-macros-250.3-19.azl3.noarch.rpm tar-1.35-2.azl3.aarch64.rpm tar-debuginfo-1.35-2.azl3.aarch64.rpm tdnf-3.5.8-8.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index de9fea830d3..ee32ff7c912 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -588,11 +588,11 @@ sqlite-devel-3.44.0-2.azl3.x86_64.rpm sqlite-libs-3.44.0-2.azl3.x86_64.rpm swig-4.2.1-1.azl3.x86_64.rpm swig-debuginfo-4.2.1-1.azl3.x86_64.rpm -systemd-bootstrap-250.3-18.azl3.x86_64.rpm -systemd-bootstrap-debuginfo-250.3-18.azl3.x86_64.rpm -systemd-bootstrap-devel-250.3-18.azl3.x86_64.rpm -systemd-bootstrap-libs-250.3-18.azl3.x86_64.rpm -systemd-bootstrap-rpm-macros-250.3-18.azl3.noarch.rpm +systemd-bootstrap-250.3-19.azl3.x86_64.rpm +systemd-bootstrap-debuginfo-250.3-19.azl3.x86_64.rpm +systemd-bootstrap-devel-250.3-19.azl3.x86_64.rpm +systemd-bootstrap-libs-250.3-19.azl3.x86_64.rpm +systemd-bootstrap-rpm-macros-250.3-19.azl3.noarch.rpm tar-1.35-2.azl3.x86_64.rpm tar-debuginfo-1.35-2.azl3.x86_64.rpm tdnf-3.5.8-8.azl3.x86_64.rpm