From f778f08fae814ccd68444393a11e1c5bc82dcc48 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 18 Mar 2026 15:46:01 +0100 Subject: [PATCH 1/3] NEWS: fix sysext/confext configuration file names in v259 /etc/systemd/systemd-{confext,sysext}.conf are likely just leftovers from an older in-development version of the feature. --- NEWS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 71ad345523..573afc9bb7 100644 --- a/NEWS +++ b/NEWS @@ -689,9 +689,9 @@ CHANGES WITH 259: systemd-sysext/systemd-confext: * systemd-sysext and systemd-confext now support configuration files - /etc/systemd/systemd-sysext.conf and /etc/systemd/systemd-confext.conf, - which can be used to configure mutability or the image policy to - apply to DDI images. + /etc/systemd/sysext.conf and /etc/systemd/confext.conf, which can be + used to configure mutability or the image policy to apply to DDI + images. * systemd-sysext's and systemd-confext's --mutable= switch now accepts a new value "help" for listing available mutability modes. From c70b17daad3a2186e2cbdcb80896cb638c1d9f40 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 18 Mar 2026 17:09:24 +0100 Subject: [PATCH 2/3] sysext: provide systemd-{sysext,confext}-sysroot.service services The new services are used to activate system and configuration extensions for the main system from the initrd, this allows to overcome the limitation that sysext/confext cannot be used to update the resources which are required in the earliest boot of the system (before systemd-sysext/systemd-confext start). --- NEWS | 9 ++++++ TODO | 5 ++- man/rules/meson.build | 2 ++ man/systemd-sysext.xml | 44 ++++++++++++++++++--------- presets/90-systemd-initrd.preset | 2 ++ presets/90-systemd.preset | 2 ++ units/meson.build | 8 +++++ units/systemd-confext-initrd.service | 2 +- units/systemd-confext-sysroot.service | 32 +++++++++++++++++++ units/systemd-sysext-initrd.service | 2 +- units/systemd-sysext-sysroot.service | 31 +++++++++++++++++++ 11 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 units/systemd-confext-sysroot.service create mode 100644 units/systemd-sysext-sysroot.service diff --git a/NEWS b/NEWS index 573afc9bb7..dc205e6a47 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,15 @@ CHANGES WITH 261 in spe: require direct IMDS access. The new meson option "-Dimds-network=" can be used to change the default mode to "locked" at build-time. + Changes in systemd-sysext/systemd-confext: + + * New initrd services systemd-sysext-sysroot.service and + systemd-confext-sysroot.service are provided. These services are + used to merge system and configuration extensions for the main system + from the initrd. This overcomes the limitation that system and + configuration extensions merged from the main system itself cannot be + used to modify the resources which are used in the early boot. + CHANGES WITH 260: Feature Removals and Incompatible Changes: diff --git a/TODO b/TODO index 378d318122..aca06755c0 100644 --- a/TODO +++ b/TODO @@ -119,6 +119,8 @@ Deprecations and removals: similar "devices" Features: +* sysext: make systemd-{sys,conf}ext-sysroot.service work in the split '/var' + configuration. * sd-varlink: add fully async modes of the protocol upgrade stuff @@ -1769,9 +1771,6 @@ Features: * in sd-id128: also parse UUIDs in RFC4122 URN syntax (i.e. chop off urn:uuid: prefix) -* systemd-sysext: optionally, run it in initrd already, before transitioning - into host, to open up possibility for services shipped like that. - * whenever we receive fds via SCM_RIGHTS make sure none got dropped due to the reception limit the kernel silently enforces. diff --git a/man/rules/meson.build b/man/rules/meson.build index 911a68543e..aa2653ce0d 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -1197,8 +1197,10 @@ manpages = [ '8', ['systemd-confext', 'systemd-confext-initrd.service', + 'systemd-confext-sysroot.service', 'systemd-confext.service', 'systemd-sysext-initrd.service', + 'systemd-sysext-sysroot.service', 'systemd-sysext.service'], 'ENABLE_SYSEXT'], ['systemd-system-update-generator', '8', [], ''], diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml index c9a8f1ed01..49cfee8668 100644 --- a/man/systemd-sysext.xml +++ b/man/systemd-sysext.xml @@ -20,9 +20,11 @@ systemd-sysext systemd-sysext.service systemd-sysext-initrd.service + systemd-sysext-sysroot.service systemd-confext systemd-confext.service systemd-confext-initrd.service + systemd-confext-sysroot.service Activates System Extension Images @@ -114,22 +116,36 @@ systemd-stub7 with extension images found in the system's EFI System Partition. - During boot OS extension images are activated automatically, if the - systemd-sysext.service is enabled. Note that this service runs only after the - underlying file systems where system extensions may be located have been mounted. This means they are not - suitable for shipping resources that are processed by subsystems running in earliest boot. Specifically, - OS extension images are not suitable for shipping system services or + During boot, system and configuration extension images are activated automatically if the + systemd-sysext.service and systemd-confext.service services are + enabled. Note that these services run only after the underlying file systems where system and configuration + extensions may be located have been mounted. To make it possible to ship resources that are processed by + subsystems running in the earliest boot stages (for example, system services or systemd-sysusers8 - definitions. See the Portable Services page - for a simple mechanism for shipping system services in disk images, in a similar fashion to OS - extensions. Note the different isolation on these two mechanisms: while system extension directly extend - the underlying OS image with additional files that appear in a way very similar to as if they were - shipped in the OS image itself and thus imply no security isolation, portable services imply service - level sandboxing in one way or another. The systemd-sysext.service service is - guaranteed to finish start-up before basic.target is reached; i.e. at the time + definitions), the systemd-sysext-sysroot.service and + systemd-confext-sysroot.service initrd services are provided. Currently, these + services cannot be used to merge system extensions from /sysroot/var/lib/extensions/ + and configuration extensions from /sysroot/var/lib/confexts/ when the + /var/ partition is split off. These extensions are later merged by the + systemd-sysext.service and systemd-confext.service services + during the main OS boot process. + + Also, see the Portable Services + page for a simple mechanism for shipping system services in disk images, in a similar fashion to OS + extensions. Note the differences in isolation between these two mechanisms: while system extensions directly extend + the underlying OS image with additional files that appear as if they were shipped in the OS image itself + and thus imply no security isolation, portable services imply service-level sandboxing in one way or another. + + The systemd-sysext.service and systemd-confext.service + services are guaranteed to finish start-up before basic.target is reached; i.e., by the time regular services initialize (those which do not use DefaultDependencies=no), the files - and directories system extensions provide are available in /usr/ and - /opt/ and may be accessed. + and directories provided by system and configuration extensions are available in /usr/, + /opt/, and /etc/ and may be accessed. + + System and configuration extensions can also be used to extend the initrd, and the + systemd-sysext-initrd.service and systemd-confext-initrd.service + initrd services are provided. Note that some limitations apply: resources that are used in the earliest boot + stages of the initrd (e.g. system services) cannot be updated. Note that there is no concept of enabling/disabling installed system extension images: all installed extension images are automatically activated at boot. However, you can place an empty directory diff --git a/presets/90-systemd-initrd.preset b/presets/90-systemd-initrd.preset index e966a182f1..b7b966daca 100644 --- a/presets/90-systemd-initrd.preset +++ b/presets/90-systemd-initrd.preset @@ -9,12 +9,14 @@ # Settings for systemd units distributed with systemd itself, specific to initrds. +enable systemd-confext-sysroot.service enable systemd-journald-audit.socket enable systemd-network-generator.service enable systemd-networkd.service enable systemd-networkd-wait-online.service enable systemd-pstore.service enable systemd-resolved.service +enable systemd-sysext-sysroot.service enable systemd-tpm2-clear.service disable console-getty.service diff --git a/presets/90-systemd.preset b/presets/90-systemd.preset index 56f9e93706..cd7afb5df2 100644 --- a/presets/90-systemd.preset +++ b/presets/90-systemd.preset @@ -52,7 +52,9 @@ disable proc-sys-fs-binfmt_misc.mount disable syslog.socket disable systemd-boot-check-no-failures.service +disable systemd-confext-sysroot.service disable systemd-journal-gatewayd.* disable systemd-journal-remote.* disable systemd-journal-upload.* +disable systemd-sysext-sysroot.service disable systemd-time-wait-sync.service diff --git a/units/meson.build b/units/meson.build index 02c2db074c..16c082a623 100644 --- a/units/meson.build +++ b/units/meson.build @@ -311,6 +311,10 @@ units = [ 'conditions' : ['ENABLE_INITRD', 'ENABLE_SYSEXT'], 'symlinks' : ['initrd.target.wants/'], }, + { + 'file' : 'systemd-confext-sysroot.service', + 'conditions' : ['ENABLE_INITRD', 'ENABLE_SYSEXT'], + }, { 'file' : 'systemd-coredump.socket', 'conditions' : ['ENABLE_COREDUMP'], @@ -759,6 +763,10 @@ units = [ 'conditions' : ['ENABLE_INITRD', 'ENABLE_SYSEXT'], 'symlinks' : ['initrd.target.wants/'], }, + { + 'file' : 'systemd-sysext-sysroot.service', + 'conditions' : ['ENABLE_INITRD', 'ENABLE_SYSEXT'], + }, { 'file' : 'systemd-sysext.socket', 'conditions' : ['ENABLE_SYSEXT'], diff --git a/units/systemd-confext-initrd.service b/units/systemd-confext-initrd.service index 073307edcc..67e1b1b8d3 100644 --- a/units/systemd-confext-initrd.service +++ b/units/systemd-confext-initrd.service @@ -8,7 +8,7 @@ # (at your option) any later version. [Unit] -Description=Merge System Configuration Images into /etc/ +Description=Merge System Configuration Images into /etc/ of the initrd Documentation=man:systemd-confext-initrd.service(8) ConditionCapability=CAP_SYS_ADMIN diff --git a/units/systemd-confext-sysroot.service b/units/systemd-confext-sysroot.service new file mode 100644 index 0000000000..2ca6da70aa --- /dev/null +++ b/units/systemd-confext-sysroot.service @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Merge System Configuration Images into /sysroot/etc/ +Documentation=man:systemd-confext-sysroot.service(8) + +ConditionCapability=CAP_SYS_ADMIN +ConditionDirectoryNotEmpty=|/sysroot/var/lib/confexts +ConditionDirectoryNotEmpty=|/sysroot/usr/local/lib/confexts +ConditionDirectoryNotEmpty=|/sysroot/usr/lib/confexts +ConditionPathExists=/etc/initrd-release + +DefaultDependencies=no +Conflicts=shutdown.target +Before=initrd-root-fs.target shutdown.target +Wants=modprobe@loop.service modprobe@dm_mod.service +After=modprobe@loop.service modprobe@dm_mod.service sysroot.mount sysroot-usr.mount systemd-volatile-root.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=systemd-confext --root=/sysroot refresh + +[Install] +WantedBy=initrd.target diff --git a/units/systemd-sysext-initrd.service b/units/systemd-sysext-initrd.service index 4a411bb65e..c6e93a3719 100644 --- a/units/systemd-sysext-initrd.service +++ b/units/systemd-sysext-initrd.service @@ -8,7 +8,7 @@ # (at your option) any later version. [Unit] -Description=Merge System Extension Images into /usr/ and /opt/ +Description=Merge System Extension Images into /usr/ and /opt/ of the initrd Documentation=man:systemd-sysext-initrd.service(8) ConditionCapability=CAP_SYS_ADMIN diff --git a/units/systemd-sysext-sysroot.service b/units/systemd-sysext-sysroot.service new file mode 100644 index 0000000000..11841ebdcd --- /dev/null +++ b/units/systemd-sysext-sysroot.service @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Merge System Extension Images into /sysroot/usr/ and /sysroot/opt/ +Documentation=man:systemd-sysext-sysroot.service(8) + +ConditionCapability=CAP_SYS_ADMIN +ConditionDirectoryNotEmpty=|/sysroot/etc/extensions +ConditionDirectoryNotEmpty=|/sysroot/var/lib/extensions +ConditionPathExists=/etc/initrd-release + +DefaultDependencies=no +Conflicts=shutdown.target +Before=initrd-root-fs.target shutdown.target +Wants=modprobe@loop.service modprobe@dm_mod.service +After=modprobe@loop.service modprobe@dm_mod.service sysroot.mount sysroot-usr.mount systemd-volatile-root.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=systemd-sysext --root=/sysroot refresh + +[Install] +WantedBy=initrd.target From 2299a37e28249edd06fc66bfda2ad36106cf69da Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 19 Mar 2026 16:04:34 +0100 Subject: [PATCH 3/3] sysext: provide a cmdline kill switch for the sysext/confext merging logic While it is possible to disable sysext/confext merging in the main system with 'systemctl disable', sysext/confext are always merged in the initrd, both by systemd-{sys,conf}ext-initrd.service and by systemd-{sys,conf}ext-sysroot.service and especially the latter can be unexpected. Provide kernel cmdline options systemd.{sys,conf}ext=0 and rd.systemd.{sys,conf}ext=0 covering all options. --- man/kernel-command-line.xml | 16 ++++++++++++++++ man/systemd-sysext.xml | 8 +++++++- src/sysext/sysext.c | 17 +++++++++++++++++ units/systemd-confext-initrd.service | 1 + units/systemd-confext-sysroot.service | 1 + units/systemd-confext.service | 1 + units/systemd-sysext-initrd.service | 1 + units/systemd-sysext-sysroot.service | 1 + units/systemd-sysext.service | 1 + 9 files changed, 46 insertions(+), 1 deletion(-) diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 9e24e749b3..0ad3c9c772 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -829,6 +829,22 @@ + + systemd.sysext= + systemd.confext= + rd.systemd.sysext= + rd.systemd.confext= + + Take boolean arguments, default to on. Control whether system and configuration + extensions for the initrd (rd.systemd.sysext=, rd.systemd.confext=) + and for the main system (systemd.sysext=, systemd.confext=) are + merged automatically on boot. See + systemd-sysext8 + for details. + + + + diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml index 49cfee8668..a0e77ad729 100644 --- a/man/systemd-sysext.xml +++ b/man/systemd-sysext.xml @@ -150,7 +150,13 @@ Note that there is no concept of enabling/disabling installed system extension images: all installed extension images are automatically activated at boot. However, you can place an empty directory named like the extension (no .raw) in /etc/extensions/ to "mask" - an extension with the same name in a system folder with lower precedence. + an extension with the same name in a system folder with lower precedence. It is also possible to disable + automatic merging altogether using the rd.systemd.sysext=, rd.systemd.confext=, + systemd.sysext=, and systemd.confext= kernel command line options. + Note that systemd-sysext-sysroot.service and + systemd-confext-sysroot.service are controlled by the systemd.sysext= + and systemd.confext= options, as these services merge system and configuration + extensions for the main system, not for the initrd. A simple mechanism for version compatibility is enforced: a system extension image must carry a /usr/lib/extension-release.d/extension-release.NAME diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 52e6c3be66..0ac35d1b56 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -51,6 +51,7 @@ #include "path-util.h" #include "pidref.h" #include "pretty-print.h" +#include "proc-cmdline.h" #include "process-util.h" #include "rm-rf.h" #include "runtime-scope.h" @@ -3038,6 +3039,22 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; + /* PROC_CMDLINE_STRIP_RD_PREFIX cannot be used here as we need to be able to distinguish between + * rd.systemd.{sysext,confext} and systemd.{sysext,confext} in the initrd where they are both used + * and have different meaning. */ + const char *string_class = image_class_to_string(arg_image_class); + const char *cmdline_opt = strjoina(in_initrd() && !arg_root ? "rd." : "", "systemd.", string_class); + + bool enabled; + r = proc_cmdline_get_bool(cmdline_opt, PROC_CMDLINE_TRUE_WHEN_MISSING, &enabled); + if (r < 0) + log_debug_errno(r, "Failed to check '%s=' kernel command line option, proceeding: %m", cmdline_opt); + else if (!enabled && invoked_by_systemd()) { + /* Kernel command line option should not affect manual invocation. */ + log_notice("Disabled by the kernel command line option '%s=', skipping execution.", cmdline_opt); + return 0; + } + /* Parse configuration file after argv because it needs --root=. * The config entries will not overwrite values set already by * env/argv because we track initialization. */ diff --git a/units/systemd-confext-initrd.service b/units/systemd-confext-initrd.service index 67e1b1b8d3..9984bd7065 100644 --- a/units/systemd-confext-initrd.service +++ b/units/systemd-confext-initrd.service @@ -19,6 +19,7 @@ ConditionDirectoryNotEmpty=|/usr/lib/confexts ConditionDirectoryNotEmpty=|/.extra/confext ConditionDirectoryNotEmpty=|/.extra/global_confext ConditionPathExists=/etc/initrd-release +ConditionKernelCommandLine=!rd.systemd.confext=0 DefaultDependencies=no Before=local-fs-pre.target cryptsetup-pre.target systemd-tmpfiles-setup.service diff --git a/units/systemd-confext-sysroot.service b/units/systemd-confext-sysroot.service index 2ca6da70aa..e30193e17e 100644 --- a/units/systemd-confext-sysroot.service +++ b/units/systemd-confext-sysroot.service @@ -16,6 +16,7 @@ ConditionDirectoryNotEmpty=|/sysroot/var/lib/confexts ConditionDirectoryNotEmpty=|/sysroot/usr/local/lib/confexts ConditionDirectoryNotEmpty=|/sysroot/usr/lib/confexts ConditionPathExists=/etc/initrd-release +ConditionKernelCommandLine=!systemd.confext=0 DefaultDependencies=no Conflicts=shutdown.target diff --git a/units/systemd-confext.service b/units/systemd-confext.service index e509036d03..ffbf8345b8 100644 --- a/units/systemd-confext.service +++ b/units/systemd-confext.service @@ -17,6 +17,7 @@ ConditionDirectoryNotEmpty=|/var/lib/confexts ConditionDirectoryNotEmpty=|/usr/local/lib/confexts ConditionDirectoryNotEmpty=|/usr/lib/confexts ConditionPathExists=!/etc/initrd-release +ConditionKernelCommandLine=!systemd.confext=0 DefaultDependencies=no After=local-fs.target diff --git a/units/systemd-sysext-initrd.service b/units/systemd-sysext-initrd.service index c6e93a3719..2d9fb59cf2 100644 --- a/units/systemd-sysext-initrd.service +++ b/units/systemd-sysext-initrd.service @@ -18,6 +18,7 @@ ConditionDirectoryNotEmpty=|/var/lib/extensions ConditionDirectoryNotEmpty=|/.extra/sysext ConditionDirectoryNotEmpty=|/.extra/global_sysext ConditionPathExists=/etc/initrd-release +ConditionKernelCommandLine=!rd.systemd.sysext=0 DefaultDependencies=no Before=local-fs-pre.target cryptsetup-pre.target systemd-tmpfiles-setup.service diff --git a/units/systemd-sysext-sysroot.service b/units/systemd-sysext-sysroot.service index 11841ebdcd..d68c70da69 100644 --- a/units/systemd-sysext-sysroot.service +++ b/units/systemd-sysext-sysroot.service @@ -15,6 +15,7 @@ ConditionCapability=CAP_SYS_ADMIN ConditionDirectoryNotEmpty=|/sysroot/etc/extensions ConditionDirectoryNotEmpty=|/sysroot/var/lib/extensions ConditionPathExists=/etc/initrd-release +ConditionKernelCommandLine=!systemd.sysext=0 DefaultDependencies=no Conflicts=shutdown.target diff --git a/units/systemd-sysext.service b/units/systemd-sysext.service index f20a076128..3246ea7fb7 100644 --- a/units/systemd-sysext.service +++ b/units/systemd-sysext.service @@ -17,6 +17,7 @@ ConditionDirectoryNotEmpty=|/run/extensions ConditionDirectoryNotEmpty=|/var/lib/extensions ConditionDirectoryNotEmpty=|/var/lib/extensions.mutable ConditionPathExists=!/etc/initrd-release +ConditionKernelCommandLine=!systemd.sysext=0 DefaultDependencies=no After=local-fs.target