From 70f3eff233e230c520228040e74516c26a179b1a Mon Sep 17 00:00:00 2001 From: Kai Lueke Date: Wed, 20 Dec 2023 11:20:39 +0100 Subject: [PATCH 1/5] SELinux: Label /usr and sysext image contents So far we did not correctly label /usr because it broke certain things like Docker. With the sysext Docker and new policies we should try again. First generate the policy before branching off the base squashfs (which already misses a lot of things because they the most postprocessing is done late in finish_image!). Then label /usr and also the sysext contents in their folder - not in the overlay mount because this would operate on the whole image. Signed-off-by: James Le Cuirot --- .../workflows/portage-stable-packages-list | 1 + build_library/build_image_util.sh | 23 +++++++++++-------- build_library/dev_container_util.sh | 3 +++ build_library/prod_image_util.sh | 3 +++ build_sysext | 10 +++++++- ...1-r321.ebuild => coreos-0.0.1-r322.ebuild} | 0 .../coreos-base/coreos/coreos-0.0.1.ebuild | 1 + 7 files changed, 31 insertions(+), 10 deletions(-) rename sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/{coreos-0.0.1-r321.ebuild => coreos-0.0.1-r322.ebuild} (100%) diff --git a/.github/workflows/portage-stable-packages-list b/.github/workflows/portage-stable-packages-list index 0949ca56b16..585579004ba 100644 --- a/.github/workflows/portage-stable-packages-list +++ b/.github/workflows/portage-stable-packages-list @@ -592,6 +592,7 @@ sec-policy/selinux-base sec-policy/selinux-base-policy sec-policy/selinux-container sec-policy/selinux-dbus +sec-policy/selinux-docker sec-policy/selinux-policykit sec-policy/selinux-sssd sec-policy/selinux-unconfined diff --git a/build_library/build_image_util.sh b/build_library/build_image_util.sh index b7795ade839..2eae88fa615 100755 --- a/build_library/build_image_util.sh +++ b/build_library/build_image_util.sh @@ -518,6 +518,18 @@ start_image() { --board="${BOARD}" } +# Actions common to the dev container and the image +# but which should be run before the image branches off +# the base squashfs (used for systemd-sysext image building) +finish_image_common() { + local root_fs_dir="$1" + + # Build the selinux policy + if pkg_use_enabled coreos-base/coreos selinux; then + sudo semodule -n -s mcs -p "${root_fs_dir}" -i "${root_fs_dir}"/usr/share/selinux/mcs/*.pp + fi +} + finish_image() { local image_name="$1" local disk_layout="$2" @@ -634,11 +646,6 @@ EOF "${BUILD_DIR}/${image_kconfig}" fi - # Build the selinux policy - if pkg_use_enabled coreos-base/coreos selinux; then - sudo semodule -n -s mcs -p "${root_fs_dir}" -i "${root_fs_dir}"/usr/share/selinux/mcs/*.pp - fi - # Run tmpfiles once to make sure that /etc has everything in place before # we freeze it in /usr/share/flatcar/etc as lowerdir in the overlayfs. @@ -674,10 +681,8 @@ EOF # setfiles from version 3.11 requires the passed path to have no symlinks local real_root_fs_dir real_root_fs_dir=$(realpath "${root_fs_dir}") - # TODO: Breaks the system: - # sudo setfiles -Dv -r "${real_root_fs_dir}" "${real_root_fs_dir}"/etc/selinux/mcs/contexts/files/file_contexts "${real_root_fs_dir}" - # sudo setfiles -Dv -r "${real_root_fs_dir}" "${real_root_fs_dir}"/etc/selinux/mcs/contexts/files/file_contexts "${real_root_fs_dir}"/usr - # For now we only try it with /etc + sudo setfiles -Dv -r "${real_root_fs_dir}" "${real_root_fs_dir}"/etc/selinux/mcs/contexts/files/file_contexts "${real_root_fs_dir}" + sudo setfiles -Dv -r "${real_root_fs_dir}" "${real_root_fs_dir}"/etc/selinux/mcs/contexts/files/file_contexts "${real_root_fs_dir}"/usr sudo setfiles -Dv -r "${real_root_fs_dir}" "${real_root_fs_dir}"/etc/selinux/mcs/contexts/files/file_contexts "${real_root_fs_dir}"/etc fi diff --git a/build_library/dev_container_util.sh b/build_library/dev_container_util.sh index 5bee2889e55..c885e269572 100755 --- a/build_library/dev_container_util.sh +++ b/build_library/dev_container_util.sh @@ -99,6 +99,9 @@ create_dev_container() { # The remount services are provided by coreos-base/coreos-init systemd_enable "${root_fs_dir}" "multi-user.target" "remount-usr.service" + finish_image_common \ + "${root_fs_dir}" + finish_image "${image_name}" "${disk_layout}" "${root_fs_dir}" "${image_contents}" "${image_contents_wtd}" declare -a files_to_evaluate diff --git a/build_library/prod_image_util.sh b/build_library/prod_image_util.sh index 0ea886b9a00..0a392fd94c2 100755 --- a/build_library/prod_image_util.sh +++ b/build_library/prod_image_util.sh @@ -101,6 +101,9 @@ create_prod_image() { ROOT="${root_fs_dir}" PORTAGE_CONFIGROOT="${BUILD_DIR}"/configroot \ test_image_content "${root_fs_dir}" + finish_image_common \ + "${root_fs_dir}" + local root_with_everything="${root_fs_dir}" # Call helper script for adding sysexts to the base OS. diff --git a/build_sysext b/build_sysext index 6ecbdb5f500..f637efbfb07 100755 --- a/build_sysext +++ b/build_sysext @@ -244,7 +244,6 @@ export SOURCE_DATE_EPOCH=$(stat -c '%Y' "${BUILD_DIR}/fs-root/usr/lib/os-release # Unmount in order to get rid of the overlay umount "${BUILD_DIR}/${FLAGS_install_root_basename}" -umount "${BUILD_DIR}/fs-root" if [[ "$FLAGS_generate_pkginfo" = "${FLAGS_TRUE}" ]] ; then info " Creating pkginfo squashfs '${BUILD_DIR}/${SYSEXT_ID}_pkginfo.raw'" @@ -305,6 +304,15 @@ EOF info "Removing opaque directory markers to always merge all contents" find "${BUILD_DIR}/${FLAGS_install_root_basename}" -xdev -type d -exec sh -c 'if [ "$(attr -R -q -g overlay.opaque {} 2>/dev/null)" = y ]; then attr -R -r overlay.opaque {}; fi' \; +if pkg_use_enabled coreos-base/coreos selinux; then + # setfiles from version 3.11 requires the passed path to have no symlinks + real_install_root=$(realpath "${BUILD_DIR}/${FLAGS_install_root_basename}") + real_fs_root=$(realpath "${BUILD_DIR}/fs-root") + sudo setfiles -Dv -r "${real_install_root}" "${real_fs_root}/etc/selinux/mcs/contexts/files/file_contexts" "${real_install_root}/usr" +fi + +umount "${BUILD_DIR}/fs-root" + info "Checking for invalid file ownership" invalid_files=$(find "${BUILD_DIR}/${FLAGS_install_root_basename}" -user sdk -or -group sdk) if [[ -n "${invalid_files}" ]]; then diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1-r321.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1-r322.ebuild similarity index 100% rename from sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1-r321.ebuild rename to sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1-r322.ebuild diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild index b6e64960492..e58e45a82d0 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos/coreos-0.0.1.ebuild @@ -148,6 +148,7 @@ RDEPEND="${RDEPEND} sec-policy/selinux-base-policy sec-policy/selinux-container sec-policy/selinux-dbus + sec-policy/selinux-docker sec-policy/selinux-policykit sec-policy/selinux-unconfined sys-apps/acl From 10e48aedf6d15ab9dfa5ee1660850ccebe771b1b Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Wed, 11 Nov 2026 16:26:33 +0000 Subject: [PATCH 2/5] sys-apps/systemd: Backport EXTENSION_RESTART_UNITS feature from 262 We need this to fix the zfs sysext. Signed-off-by: James Le Cuirot --- ...re-start-units-from-extension-releas.patch | 337 ++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-sysext-Allow-to-re-start-units-from-extension-releas.patch diff --git a/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-sysext-Allow-to-re-start-units-from-extension-releas.patch b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-sysext-Allow-to-re-start-units-from-extension-releas.patch new file mode 100644 index 00000000000..f4cef59863b --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos/user-patches/sys-apps/systemd/0009-sysext-Allow-to-re-start-units-from-extension-releas.patch @@ -0,0 +1,337 @@ +From 347f35cf42013acf2d324ac1299907d19051beed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kai=20L=C3=BCke?= +Date: Thu, 28 May 2026 22:07:16 +0900 +Subject: [PATCH] sysext: Allow to (re)start units from extension-release + metadata file + +Up to now we recommended to use TARGET.upholds/ symlinks to start units +when an extension is loaded. However, this has some drawbacks. First, +for services that should not be tried to be started all the time we have +to resort to hiding them through a target that gets uphold and then +uses regular .wants/ for the actual service. Second, we actually leak +services on extension unload even if the unit has disappeared with the +extension. Third, to affect a service through a drop-in or a config +change from a confext/sysext and that service is already running, we +need a way to restart/reload it instead of just starting it. + +Similar to EXTENSION_RELOAD_MANAGER=1, add a EXTENSION_RESTART_UNITS= +and a EXTENSION_RELOAD_OR_RESTART_UNITS= setting to the +extension-release metadata file, carrying a whitespace-separated list +of units to restart/reload on merge/refresh/unmerge after the daemon +reload. Also detect when the unit has vanished which is normally the +case when the unit was part of the unmerged extension, and stop it +explicitly to prevent it leaking. When the extension itself ships the +binary it should use EXTENSION_RESTART_UNITS= to make sure the new +binary is picked up. Since starting through this setting does not work +when the extension is mounted from the initrd, extensions should still +ship at least a .wants/ symlink to start at boot but can also continue +to ship a .upholds/ symlink for backwards compatibility without any +drawback and still benefit from the unit stopping triggered by the new +setting. While there are cases where one could want to set +EXTENSION_RESTART_UNITS= without requiring a daemon reload (e.g., an +env var file change instead of a unit drop-in), we now do an implicit +daemon reload when we have to restart units so that we know we work on +the right state and we spare users remembering to set this setting in +addition to prevent running into this issue. +--- a/src/sysext/sysext.c ++++ b/src/sysext/sysext.c +@@ -15,9 +15,12 @@ + #include "blkid-util.h" + #include "blockdev-util.h" + #include "build.h" ++#include "bus-common-errors.h" ++#include "bus-locator.h" + #include "bus-polkit.h" + #include "bus-unit-util.h" + #include "bus-util.h" ++#include "bus-wait-for-jobs.h" + #include "capability-util.h" + #include "chase.h" + #include "conf-parser.h" +@@ -57,12 +60,14 @@ + #include "rm-rf.h" + #include "runtime-scope.h" + #include "selinux-util.h" ++#include "set.h" + #include "sort-util.h" + #include "stat-util.h" + #include "string-table.h" + #include "string-util.h" + #include "strv.h" + #include "time-util.h" ++#include "unit-name.h" + #include "varlink-io.systemd.sysext.h" + #include "varlink-util.h" + #include "verbs.h" +@@ -289,16 +294,60 @@ static int is_our_mount_point( + return true; + } + +-static int need_reload( ++static int split_unit_string(const char *s, const char *field, const char *extension, Set **units) { ++ _cleanup_strv_free_ char **split = NULL; ++ int r; ++ ++ assert(field); ++ assert(extension); ++ assert(units); ++ ++ if (isempty(s)) ++ return 0; ++ ++ split = strv_split(s, /* separators= whitespace */ NULL); ++ if (!split) ++ return log_oom(); ++ ++ STRV_FOREACH(u, split) { ++ if (!unit_name_is_valid(*u, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { ++ log_warning("Invalid unit name '%s' in %s= of %s, ignoring.", *u, field, extension); ++ continue; ++ } ++ ++ r = set_put_strdup(units, *u); ++ if (r < 0) ++ return log_oom(); ++ } ++ ++ return 0; ++} ++ ++static int get_extension_release_metadata( + ImageClass image_class, + char **hierarchies, +- bool no_reload) { +- +- /* Parse the mounted images to find out if we need to reload the daemon. */ ++ bool no_reload, ++ bool *ret_need_reload, ++ Set **ret_restart_units, ++ Set **ret_reload_or_restart_units) { ++ ++ /* Parse the mounted images to find out if we need to reload the daemon, and which units to ++ * restart or reload-or-restart afterwards. */ ++ _cleanup_set_free_ Set *restart_units = NULL, *reload_or_restart_units = NULL; ++ bool need_to_reload = false; + int r; + +- if (no_reload) +- return false; ++ if (no_reload || !isempty(arg_root)) { ++ /* With --root= we'd be talking to the host service manager about extensions merged ++ * into a foreign root, which is never what we want. */ ++ if (ret_need_reload) ++ *ret_need_reload = false; ++ if (ret_restart_units) ++ *ret_restart_units = NULL; ++ if (ret_reload_or_restart_units) ++ *ret_reload_or_restart_units = NULL; ++ return 0; ++ } + + STRV_FOREACH(p, hierarchies) { + _cleanup_free_ char *f = NULL, *buf = NULL, *resolved = NULL; +@@ -334,8 +383,7 @@ static int need_reload( + + STRV_FOREACH(extension, mounted_extensions) { + _cleanup_strv_free_ char **extension_release = NULL; +- const char *extension_reload_manager = NULL; +- int b; ++ const char *value; + + r = load_extension_release_pairs(arg_root, image_class, *extension, /* relax_extension_release_check= */ true, &extension_release); + if (r < 0) { +@@ -343,23 +391,50 @@ static int need_reload( + continue; + } + +- extension_reload_manager = strv_env_pairs_get(extension_release, "EXTENSION_RELOAD_MANAGER"); +- if (isempty(extension_reload_manager)) +- continue; ++ value = strv_env_pairs_get(extension_release, "EXTENSION_RELOAD_MANAGER"); ++ if (!isempty(value)) { ++ int b = parse_boolean(value); ++ if (b < 0) ++ log_warning_errno(b, "Failed to parse EXTENSION_RELOAD_MANAGER= of %s, ignoring: %m", *extension); ++ else if (b) ++ need_to_reload = true; ++ } + +- b = parse_boolean(extension_reload_manager); +- if (b < 0) { +- log_warning_errno(b, "Failed to parse the extension metadata to know if the manager needs to be reloaded, ignoring: %m"); +- continue; ++ if (ret_restart_units) { ++ value = strv_env_pairs_get(extension_release, "EXTENSION_RESTART_UNITS"); ++ r = split_unit_string(value, "EXTENSION_RESTART_UNITS", *extension, &restart_units); ++ if (r < 0) ++ return r; ++ if (!isempty(value)) ++ /* Listing units to restart implies a manager reload because a unit ++ * shipped (and later removed) by the extension would otherwise not ++ * be visible to the manager when RestartUnit/StopUnit is issued. */ ++ need_to_reload = true; + } + +- if (b) +- /* If at least one extension wants a reload, we reload. */ +- return true; ++ if (ret_reload_or_restart_units) { ++ value = strv_env_pairs_get(extension_release, "EXTENSION_RELOAD_OR_RESTART_UNITS"); ++ r = split_unit_string(value, "EXTENSION_RELOAD_OR_RESTART_UNITS", *extension, &reload_or_restart_units); ++ if (r < 0) ++ return r; ++ if (!isempty(value)) ++ need_to_reload = true; ++ } + } + } + +- return false; ++ /* If a unit is listed in both, restart takes precedence over reload-or-restart. */ ++ const char *u; ++ SET_FOREACH(u, restart_units) ++ free(set_remove(reload_or_restart_units, u)); ++ ++ if (ret_need_reload) ++ *ret_need_reload = need_to_reload; ++ if (ret_restart_units) ++ *ret_restart_units = TAKE_PTR(restart_units); ++ if (ret_reload_or_restart_units) ++ *ret_reload_or_restart_units = TAKE_PTR(reload_or_restart_units); ++ return 0; + } + + static int move_submounts(const char *src, const char *dst) { +@@ -425,6 +500,77 @@ static int daemon_reload(void) { + return bus_service_manager_reload(bus); + } + ++static int dispatch_unit_method(sd_bus *bus, BusWaitForJobs *w, Set *units, const char *method) { ++ const char *unit; ++ int r; ++ ++ assert(bus); ++ assert(w); ++ assert(method); ++ ++ /* Issue the given method for each unit and wait for the jobs to complete. Fall back to StopUnit ++ * when the call reports that the unit's file is gone, e.g., on unmerge when the unit was part of ++ * the extension, because otherwise the running service is leaked. */ ++ ++ SET_FOREACH(unit, units) { ++ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ++ const char *m = method, *job; ++ ++ r = bus_call_method(bus, bus_systemd_mgr, m, &error, &reply, "ss", unit, "replace"); ++ if (r < 0 && sd_bus_error_has_names(&error, BUS_ERROR_NO_SUCH_UNIT, BUS_ERROR_LOAD_FAILED)) { ++ sd_bus_error_free(&error); ++ m = "StopUnit"; ++ r = bus_call_method(bus, bus_systemd_mgr, m, &error, &reply, "ss", unit, "replace"); ++ if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT)) { ++ log_debug("Unit '%s' is already gone, nothing to stop.", unit); ++ continue; ++ } ++ } ++ if (r < 0) { ++ log_warning("Failed to %s unit '%s': %s", m, unit, bus_error_message(&error, r)); ++ continue; ++ } ++ ++ r = sd_bus_message_read(reply, "o", &job); ++ if (r < 0) ++ return bus_log_parse_error(r); ++ ++ r = bus_wait_for_jobs_one(w, job, BUS_WAIT_JOBS_LOG_ERROR, /* extra_args= */ NULL); ++ if (r < 0) ++ log_warning_errno(r, "Failed to wait for %s job of unit '%s', ignoring: %m", m, unit); ++ } ++ ++ return 0; ++} ++ ++static int restart_units(Set *restart_units, Set *reload_or_restart_units) { ++ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; ++ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; ++ int r; ++ ++ if (set_isempty(restart_units) && set_isempty(reload_or_restart_units)) ++ return 0; ++ ++ r = bus_connect_system_systemd(&bus); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get D-Bus connection: %m"); ++ ++ r = bus_wait_for_jobs_new(bus, &w); ++ if (r < 0) ++ return log_error_errno(r, "Failed to set up job watcher: %m"); ++ ++ r = dispatch_unit_method(bus, w, restart_units, "RestartUnit"); ++ if (r < 0) ++ return r; ++ ++ r = dispatch_unit_method(bus, w, reload_or_restart_units, "ReloadOrRestartUnit"); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + static int append_overlayfs_path_option( + char **options, + const char *separator, +@@ -1673,15 +1819,15 @@ static int unmerge( + char **hierarchies, + bool no_reload) { + ++ _cleanup_set_free_ Set *units_to_restart = NULL, *units_to_reload_or_restart = NULL; + bool need_to_reload; + int r; + + (void) DLOPEN_LIBMOUNT(LOG_DEBUG, SD_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED); + +- r = need_reload(image_class, hierarchies, no_reload); ++ r = get_extension_release_metadata(image_class, hierarchies, no_reload, &need_to_reload, &units_to_restart, &units_to_reload_or_restart); + if (r < 0) + return r; +- need_to_reload = r > 0; + + r = pidref_safe_fork( + "(sd-unmerge)", +@@ -1706,6 +1852,11 @@ static int unmerge( + return r; + } + ++ /* The sets will be empty when opted out */ ++ r = restart_units(units_to_restart, units_to_reload_or_restart); ++ if (r < 0) ++ return r; ++ + return 0; + } + +@@ -2293,15 +2444,22 @@ static int merge(ImageClass image_class, + if (r > 0) + return log_error_errno(SYNTHETIC_ERRNO(EPROTO), "Failed to merge hierarchies"); + +- r = need_reload(image_class, hierarchies, no_reload); ++ _cleanup_set_free_ Set *units_to_restart = NULL, *units_to_reload_or_restart = NULL; ++ bool need_to_reload; ++ r = get_extension_release_metadata(image_class, hierarchies, no_reload, &need_to_reload, &units_to_restart, &units_to_reload_or_restart); + if (r < 0) + return r; +- if (r > 0) { ++ if (need_to_reload) { + r = daemon_reload(); + if (r < 0) + return r; + } + ++ /* The sets will be empty when opted out */ ++ r = restart_units(units_to_restart, units_to_reload_or_restart); ++ if (r < 0) ++ return r; ++ + return 1; + } + From 9ef77a503316009f2a963f393b470bb21d8c7d66 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Wed, 11 Nov 2026 14:53:34 +0000 Subject: [PATCH 3/5] build_sysext: Only reload systemd when actually necessary No need to prod it if the sysext doesn't include any systemd units. Signed-off-by: James Le Cuirot --- build_sysext | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_sysext b/build_sysext index f637efbfb07..25376b13cee 100755 --- a/build_sysext +++ b/build_sysext @@ -289,11 +289,14 @@ for entry in "${BUILD_DIR}/${FLAGS_install_root_basename}"/*; do rm -rf "${entry}" done +EXTENSION_RELOAD_MANAGER=0 +[[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/systemd ]] && EXTENSION_RELOAD_MANAGER=1 + grep . < Date: Wed, 11 Nov 2026 14:54:40 +0000 Subject: [PATCH 4/5] build_sysext: Trigger udev when sysext includes udev rules This fixes the zfs sysext, which tried to delay udevd until after the sysext is merged, but that recently broke. We probably can't order things that way round any more. Signed-off-by: James Le Cuirot --- build_library/sysext_mangle_flatcar-zfs | 7 +------ build_sysext | 4 ++++ .../coreos/config/env/sys-apps/systemd | 12 ++++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/build_library/sysext_mangle_flatcar-zfs b/build_library/sysext_mangle_flatcar-zfs index e9ffdb11861..0bf2b8b1a27 100755 --- a/build_library/sysext_mangle_flatcar-zfs +++ b/build_library/sysext_mangle_flatcar-zfs @@ -35,13 +35,8 @@ d /etc/zfs 0755 root root - L /etc/zfs/zed.d - - - - /usr/share/zfs/etc/zfs/zed.d L /etc/zfs/zfs-functions - - - - /usr/share/zfs/etc/zfs/zfs-functions L /etc/zfs/zpool.d - - - - /usr/share/zfs/etc/zfs/zpool.d -C /etc/systemd/system/systemd-udevd.service.d/10-zfs.conf - - - - /usr/lib/systemd/system/systemd-udevd.service.d/10-zfs.conf +r /etc/systemd/system/systemd-udevd.service.d/10-zfs.conf - - - - - EOF -mkdir -p ./usr/lib/systemd/system/systemd-udevd.service.d -cat <./usr/lib/systemd/system/systemd-udevd.service.d/10-zfs.conf -[Unit] -After=systemd-sysext.service -EOF configure_modprobe flatcar-zfs popd diff --git a/build_sysext b/build_sysext index 25376b13cee..efbe203c608 100755 --- a/build_sysext +++ b/build_sysext @@ -292,11 +292,15 @@ done EXTENSION_RELOAD_MANAGER=0 [[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/systemd ]] && EXTENSION_RELOAD_MANAGER=1 +EXTENSION_RESTART_UNITS=() +[[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/udev/rules.d ]] && EXTENSION_RESTART_UNITS+=( systemd-udev-trigger.service ) + grep . < Date: Thu, 12 Nov 2026 14:11:04 +0000 Subject: [PATCH 5/5] build_sysext: Trigger tmpfiles.d processing when sysext includes config A new systemd unit is needed for this because the one that systemd ships is only suitable for use at boot time. Signed-off-by: James Le Cuirot --- build_sysext | 1 + .../coreos/config/env/sys-apps/systemd | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/build_sysext b/build_sysext index efbe203c608..e0f6115805d 100755 --- a/build_sysext +++ b/build_sysext @@ -293,6 +293,7 @@ EXTENSION_RELOAD_MANAGER=0 [[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/systemd ]] && EXTENSION_RELOAD_MANAGER=1 EXTENSION_RESTART_UNITS=() +[[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/tmpfiles.d ]] && EXTENSION_RESTART_UNITS+=( systemd-tmpfiles-setup-again.service ) [[ -d ${BUILD_DIR}/${FLAGS_install_root_basename}/usr/lib/udev/rules.d ]] && EXTENSION_RESTART_UNITS+=( systemd-udev-trigger.service ) grep . <