mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/2] x86: stop handing boot-stage parameters to init
@ 2026-10-05 17:13 sayo
  2026-10-05 17:13 ` [PATCH v3 1/2] init: claim parameters consumed before the main kernel sayo
  2026-10-05 17:13 ` [PATCH v3 2/2] x86: claim the parameters consumed by the boot stub and decompressor sayo
  0 siblings, 2 replies; 3+ messages in thread
From: sayo @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H . Peter Anvin
  Cc: x86, linux-kernel, m.younesbadr, nir

Some kernel parameters are consumed before the main kernel is running: the
boot stub, the decompressor and the EFI stub read the command line directly
and act on options that the main kernel never registers, because they
describe things that are already decided by then - the kernel's load
address, the paging mode, the memory encryption mode. parse_args() cannot
know they were eaten, so unknown_bootoption() hands them to init: valueless
options in argv, "key=value" ones in the environment.

On x86 that is nokaslr [KNL,EARLY], no5lvl [X86-64,RISCV,EARLY],
mem_encrypt= [X86-64] and edd= [EDD] - all documented kernel parameters.

That collides with init's own argument convention: busybox init does
"if (argv[1]) xsetenv("RUNLEVEL", argv[1]);", openrc-init takes the
runlevel from argv[1], and a shell used as init treats the argument as a
script name and exits, so a plain "nokaslr" boot reaches userspace as a
bogus RUNLEVEL.

Earlier attempts at this (2024-03, 2024-10, 2025-01) added a stub handler
for "nokaslr" alone; Boris preferred the generic version over per-parameter
stubs that only silence a warning. So patch 1 adds the hook and patch 2
fills in the x86 list. Nothing changes for parameters that are genuinely
unknown - they still reach init, and the notice names only those again.

Link: https://lore.kernel.org/all/20240331200546.869343-1-m.younesbadr@gmail.com/
Link: https://lore.kernel.org/all/20250114145521.GDZ4Z62dOwYffaUrsr@fat_crate.local/

sayo (2):
  init: claim parameters consumed before the main kernel
  x86: claim the parameters consumed by the boot stub and decompressor

 arch/x86/kernel/setup.c | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/init.h    | 12 ++++++++++++
 init/main.c             | 16 ++++++++++++++++
 3 files changed, 68 insertions(+)


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v3 1/2] init: claim parameters consumed before the main kernel
  2026-10-05 17:13 [PATCH v3 0/2] x86: stop handing boot-stage parameters to init sayo
@ 2026-10-05 17:13 ` sayo
  2026-10-05 17:13 ` [PATCH v3 2/2] x86: claim the parameters consumed by the boot stub and decompressor sayo
  1 sibling, 0 replies; 3+ messages in thread
From: sayo @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H . Peter Anvin
  Cc: x86, linux-kernel, m.younesbadr, nir

Some kernel parameters are consumed before the main kernel is running: the
boot stub, the decompressor and the EFI stub all read the command line
directly (cmdline_find_option*()) and act on options that the main kernel
never registers, because they describe things that are already decided by
then - the kernel's load address, 5-level paging setup, the memory
encryption mode, and so on.

Such parameters are not in any __setup()/early_param() table in the main
kernel, so parse_args() cannot know that they were eaten and
unknown_bootoption() classifies them as unknown: valueless ones end up in
init's argv, "key=value" ones end up in init's environment. On x86 that
list currently contains nokaslr, no5lvl, mem_encrypt= and edd=, all of them
documented parameter names in
Documentation/admin-guide/kernel-parameters.txt.

Inits that look at their arguments are affected: openrc-init takes the
runlevel from argv[1] and therefore reports "nokaslr is an invalid
runlevel", while a shell used as init treats the argument as a script name
and exits, which panics the kernel.

Adding a stub handler for each such parameter on each architecture does not
scale: arm64, loongarch and s390 each carry one for "nokaslr" alone. Let
architectures list the parameters their boot code consumed instead, and
have unknown_bootoption() drop those before they are classified: they are
then neither reported as unknown nor handed to init, while genuinely
unknown parameters keep reaching init exactly as before.

Signed-off-by: sayo <rg32@ciallo.tech>
---
 include/linux/init.h | 12 ++++++++++++
 init/main.c          | 16 ++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/include/linux/init.h b/include/linux/init.h
index 6326c61e2332..90c77d6d8cb7 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -375,6 +375,18 @@ extern const struct obs_kernel_param __setup_start[], __setup_end[];
 /* Relies on boot_command_line being set */
 void __init parse_early_param(void);
 void __init parse_early_options(char *cmdline);
+
+/*
+ * Parameters consumed before the main kernel started - by the boot stub, the
+ * decompressor or the EFI stub. They cannot be matched against the
+ * __setup()/early_param() tables in the main kernel, so architectures list
+ * them in an override of boot_param_consumed() to keep them from being
+ * reported as unknown and handed to init.
+ *
+ * @param is the parameter as it appeared on the command line, including
+ * "=value" for parameters that had one.
+ */
+bool boot_param_consumed(const char *param);
 #endif /* __ASSEMBLY__ */
 
 #else /* MODULE */
diff --git a/init/main.c b/init/main.c
index 31f2bf54976a..1230ac77029d 100644
--- a/init/main.c
+++ b/init/main.c
@@ -506,6 +506,18 @@ static int __init set_init_arg(char *param, char *val,
 	return 0;
 }
 
+/*
+ * Did the boot stub, the decompressor or the EFI stub consume this parameter
+ * before the main kernel started? Such parameters are not in any parameter
+ * table here, so nothing else can tell that they were eaten - without this
+ * they are reported as unknown and handed to init. Architectures override
+ * this to list them; see also boot_param_consumed().
+ */
+bool __init __weak boot_param_consumed(const char *param)
+{
+	return false;
+}
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * unused parameters (modprobe will find them in /proc/cmdline).
@@ -527,6 +539,10 @@ static int __init unknown_bootoption(char *param, char *val,
 
 	repair_env_string(param, val);
 
+	/* Eaten by the boot stub/decompressor before the main kernel ran? */
+	if (boot_param_consumed(param))
+		return 0;
+
 	/* Handle bootloader identifier */
 	for (int i = 0; bootloader[i]; i++) {
 		if (strstarts(param, bootloader[i]))

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v3 2/2] x86: claim the parameters consumed by the boot stub and decompressor
  2026-10-05 17:13 [PATCH v3 0/2] x86: stop handing boot-stage parameters to init sayo
  2026-10-05 17:13 ` [PATCH v3 1/2] init: claim parameters consumed before the main kernel sayo
@ 2026-10-05 17:13 ` sayo
  1 sibling, 0 replies; 3+ messages in thread
From: sayo @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H . Peter Anvin
  Cc: x86, linux-kernel, m.younesbadr, nir

List the parameters that arch/x86/boot/ and the decompressor consume before
the main kernel is running, so that unknown_bootoption() no longer forwards
them to init:

  nokaslr	arch/x86/boot/compressed/kaslr.c
  no5lvl	arch/x86/boot/compressed/pgtable_64.c
  mem_encrypt=	arch/x86/boot/compressed/misc.c
  edd=		arch/x86/boot/edd.c
  forcepae	32-bit only: its __setup() is compiled out on x86-64

Booted with "nokaslr no5lvl edd=off forcepae mem_encrypt=off foo=bar --
extra1" (plus the usual console=), before:

  Unknown kernel command line parameters "nokaslr no5lvl forcepae edd=off
  mem_encrypt=off foo=bar", will be passed to user space.
  argv: {"/init", "nokaslr", "no5lvl", "forcepae", "extra1"}
  envp: {"HOME=/", "TERM=linux", "edd=off", "mem_encrypt=off", "foo=bar"}

and after:

  Unknown kernel command line parameters "foo=bar", will be passed to
  user space.
  argv: {"/init", "extra1"}
  envp: {"HOME=/", "TERM=linux", "foo=bar"}

which is also what makes the notice useful again: it now only names
parameters that really are unknown.

Signed-off-by: sayo <rg32@ciallo.tech>
---
 arch/x86/kernel/setup.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index cda6adb9f69c..34f7add84243 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1325,3 +1325,43 @@ bool arch_cpu_is_hotpluggable(int cpu)
 	return cpu > 0;
 }
 #endif /* CONFIG_HOTPLUG_CPU */
+
+/*
+ * Parameters that the boot code consumes before the main kernel is running.
+ * They are deliberately not registered with early_param()/__setup() here:
+ * what they configure has already been decided by the time this code runs,
+ * and the decompressor (a separate program, arch/x86/boot/compressed/) does
+ * not contribute to any section in this image.
+ *
+ * Without being claimed, they are treated as unknown parameters and handed
+ * to init - valueless ones as arguments, "key=value" ones as environment
+ * variables. openrc-init, for instance, reads the runlevel from argv[1] and
+ * then complains that "nokaslr is an invalid runlevel"; a shell used as init
+ * treats the argument as a script name and exits, which panics the kernel.
+ *
+ * Keep this in sync with the cmdline_find_option*() calls in
+ * arch/x86/boot/ and drivers/firmware/efi/libstub/.
+ */
+static const char * const boot_consumed_params[] __initconst = {
+	"nokaslr",		/* arch/x86/boot/compressed/kaslr.c */
+	"no5lvl",		/* arch/x86/boot/compressed/pgtable_64.c */
+	"mem_encrypt",		/* arch/x86/boot/compressed/misc.c */
+	"edd",			/* arch/x86/boot/edd.c */
+	"forcepae",		/* 32-bit only: __setup() is compiled out on x86-64 */
+};
+
+bool __init boot_param_consumed(const char *param)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(boot_consumed_params); i++) {
+		const char *name = boot_consumed_params[i];
+		size_t len = strlen(name);
+
+		if (!strncmp(param, name, len) &&
+		    (param[len] == '\0' || param[len] == '='))
+			return true;
+	}
+
+	return false;
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-05 17:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-05 17:13 [PATCH v3 0/2] x86: stop handing boot-stage parameters to init sayo
2026-10-05 17:13 ` [PATCH v3 1/2] init: claim parameters consumed before the main kernel sayo
2026-10-05 17:13 ` [PATCH v3 2/2] x86: claim the parameters consumed by the boot stub and decompressor sayo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®