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