* [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time
@ 2026-05-27 16:41 Breno Leitao
2026-05-27 16:41 ` [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root Breno Leitao
` (4 more replies)
0 siblings, 5 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 16:41 UTC (permalink / raw)
To: Masami Hiramatsu, Andrew Morton, Nathan Chancellor, paulmck,
Nicolas Schier
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, Breno Leitao, kernel-team
The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
already landed; this series wires the rendered cmdline into the kernel.
Motivation: today the embedded bootconfig is parsed at runtime, after
parse_early_param() has already run, so early_param() handlers can't
see embedded values. Folding the kernel.* subtree into the cmdline at
build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
users without forcing them to maintain two cmdline sources.
Behaviorally, the "kernel" subtree is rendered to a flat string at
build time and stashed in .init.rodata. setup_arch() prepends it to
boot_command_line before parse_early_param() runs. Overflow is a soft
error: the helper logs and leaves boot_command_line untouched rather
than panicking, so an oversized embedded bconf cannot brick a boot.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Breno Leitao (4):
bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
bootconfig: render embedded bootconfig as a kernel cmdline at build time
bootconfig: add xbc_prepend_embedded_cmdline() helper
x86/setup: prepend embedded bootconfig cmdline before parse_early_param
Makefile | 5 ++++
arch/x86/Kconfig | 1 +
arch/x86/kernel/setup.c | 3 +++
include/linux/bootconfig.h | 7 ++++++
init/Kconfig | 33 ++++++++++++++++++++++++++
init/main.c | 19 ++++++++++++---
lib/Makefile | 16 +++++++++++++
lib/bootconfig.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++
lib/embedded-cmdline.S | 16 +++++++++++++
tools/bootconfig/Makefile | 2 +-
10 files changed, 156 insertions(+), 4 deletions(-)
---
base-commit: e7e28506af98ce4e1059e5ec59334b335c00a246
change-id: 20260508-bootconfig_using_tools-cfa7aa9d6a5a
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
@ 2026-05-27 16:41 ` Breno Leitao
2026-05-27 17:05 ` sashiko-bot
2026-05-27 16:41 ` [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time Breno Leitao
` (3 subsequent siblings)
4 siblings, 1 reply; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 16:41 UTC (permalink / raw)
To: Masami Hiramatsu, Andrew Morton, Nathan Chancellor, paulmck,
Nicolas Schier
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, Breno Leitao, kernel-team
Returning -EINVAL when @root has no descendant key nodes is a quirky
result for a renderer: "nothing to render" is not an error. The only
existing caller, xbc_make_cmdline(), papers over it with a `len <= 0`
check, so the misbehavior is harmless today. The new -C user in
tools/bootconfig added by the follow-up patches propagates the error
and turns an empty "kernel {}" subtree into a build failure.
Short-circuit the leaf-root case and return 0 so the rendered length
matches the rendered content.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
lib/bootconfig.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index f445b7703fdd..3a102c9122f7 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -431,6 +431,16 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
const char *val, *q;
int ret;
+ /*
+ * A leaf @root (e.g. an empty "kernel {}" subtree, or a key whose
+ * only child is a value node) has no descendant key/value pairs to
+ * render. The leaf-finding iterator below would otherwise return
+ * @root itself, which xbc_node_compose_key_after() rejects with
+ * -EINVAL.
+ */
+ if (root && xbc_node_is_leaf(root))
+ return 0;
+
xbc_node_for_each_key_value(root, knode, val) {
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
2026-05-27 16:41 ` [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root Breno Leitao
@ 2026-05-27 16:41 ` Breno Leitao
2026-05-27 17:30 ` sashiko-bot
2026-05-27 16:41 ` [PATCH 3/4] bootconfig: add xbc_prepend_embedded_cmdline() helper Breno Leitao
` (2 subsequent siblings)
4 siblings, 1 reply; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 16:41 UTC (permalink / raw)
To: Masami Hiramatsu, Andrew Morton, Nathan Chancellor, paulmck,
Nicolas Schier
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, Breno Leitao, kernel-team
Add the build-time pipeline that renders the "kernel" subtree of
CONFIG_BOOT_CONFIG_EMBED_FILE into a flat cmdline string and stashes
it in .init.rodata as embedded_kernel_cmdline[]. A follow-up patch
adds the runtime helper that prepends this string to boot_command_line
during early architecture setup so parse_early_param() sees the values.
The build wires up:
tools/bootconfig -C kernel - userspace tool already shared with
lib/bootconfig.c, used here in -C mode
to render a bootconfig file to a cmdline
lib/embedded-cmdline.S - .incbin's the rendered text plus a NUL
lib/Makefile rule - runs tools/bootconfig at build time
Makefile prepare dep - ensures tools/bootconfig is built first,
same pattern as tools/objtool and
tools/bpf/resolve_btfids
Drop the test target from tools/bootconfig/Makefile's default 'all'
recipe so that hooking the binary into the kernel build does not run
test-bootconfig.sh on every prepare. The tests stay available as
'make -C tools/bootconfig test', matching the convention of
tools/objtool and tools/bpf/resolve_btfids whose 'all' targets only
build the binary.
Require BOOT_CONFIG_EMBED_FILE to be non-empty before the new option
can be enabled, otherwise tools/bootconfig -C runs against an empty
file and prints a parse error on every kernel build.
The feature gates on CONFIG_ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG, a
silent symbol arches select once they've wired the prepend call into
setup_arch(). No arch selects it in this patch, so the user-visible
CONFIG_BOOT_CONFIG_EMBED_CMDLINE is not yet enableable; when an arch
later opts in, the runtime behavior is added by the follow-up patches.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Makefile | 5 +++++
init/Kconfig | 33 +++++++++++++++++++++++++++++++++
lib/Makefile | 16 ++++++++++++++++
lib/embedded-cmdline.S | 16 ++++++++++++++++
tools/bootconfig/Makefile | 2 +-
5 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index d59f703f9797..3ee259d00a9a 100644
--- a/Makefile
+++ b/Makefile
@@ -1543,6 +1543,11 @@ prepare: tools/bpf/resolve_btfids
endif
endif
+# lib/Makefile invokes tools/bootconfig to render the embedded bconf to cmdline.
+ifdef CONFIG_BOOT_CONFIG_EMBED_CMDLINE
+prepare: tools/bootconfig
+endif
+
# The tools build system is not a part of Kbuild and tends to introduce
# its own unique issues. If you need to integrate a new tool into Kbuild,
# please consider locating that tool outside the tools/ tree and using the
diff --git a/init/Kconfig b/init/Kconfig
index ca35184532dc..5f491a5ac4b8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1569,6 +1569,39 @@ config BOOT_CONFIG_EMBED_FILE
This bootconfig will be used if there is no initrd or no other
bootconfig in the initrd.
+config ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG
+ bool
+ help
+ Selected by architectures whose setup_arch() prepends the
+ build-time-rendered embedded bootconfig cmdline to
+ boot_command_line before parse_early_param() runs.
+
+config BOOT_CONFIG_EMBED_CMDLINE
+ bool "Render embedded bootconfig as kernel cmdline at build time"
+ depends on BOOT_CONFIG_EMBED
+ depends on BOOT_CONFIG_EMBED_FILE != ""
+ depends on ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG
+ default n
+ help
+ Render the "kernel" subtree of the embedded bootconfig file into a
+ flat cmdline string at kernel build time and prepend it to
+ boot_command_line during early architecture setup. This makes
+ early_param() handlers (e.g. mem=, earlycon=, loglevel=) see the
+ values supplied via the embedded bootconfig.
+
+ The runtime bootconfig parser is unaffected, so tree-structured
+ consumers such as ftrace boot-time tracing keep working.
+
+ Note: when an initrd also carries a bootconfig, its "kernel"
+ subtree is still parsed at runtime, but the embedded "kernel"
+ keys remain in boot_command_line for parse_early_param() and
+ end up later than the initrd keys in saved_command_line, so
+ parse_args() last-wins favors the embedded values. If you need
+ initrd to override embedded kernel.* keys, leave this option
+ off.
+
+ If unsure, say N.
+
config CMDLINE_LOG_WRAP_IDEAL_LEN
int "Length to try to wrap the cmdline when logged at boot"
default 1021
diff --git a/lib/Makefile b/lib/Makefile
index 6e72d2c1cce7..9de0ac7732a2 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -273,6 +273,22 @@ filechk_defbconf = cat $(or $(real-prereqs), /dev/null)
$(obj)/default.bconf: $(CONFIG_BOOT_CONFIG_EMBED_FILE) FORCE
$(call filechk,defbconf)
+obj-$(CONFIG_BOOT_CONFIG_EMBED_CMDLINE) += embedded-cmdline.o
+$(obj)/embedded-cmdline.o: $(obj)/embedded_cmdline.bin
+
+# Render the bootconfig "kernel" subtree to a flat cmdline string using
+# the userspace tools/bootconfig parser (-C mode). The runtime prepend
+# helper enforces COMMAND_LINE_SIZE at boot, so no build-time size
+# check is performed here (COMMAND_LINE_SIZE is an arch header
+# constant, not a Kconfig value).
+quiet_cmd_render_cmdline = BCONF2C $@
+ cmd_render_cmdline = \
+ $(objtree)/tools/bootconfig/bootconfig -C $< > $@
+
+targets += embedded_cmdline.bin
+$(obj)/embedded_cmdline.bin: $(obj)/default.bconf $(objtree)/tools/bootconfig/bootconfig FORCE
+ $(call if_changed,render_cmdline)
+
obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o
obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o
diff --git a/lib/embedded-cmdline.S b/lib/embedded-cmdline.S
new file mode 100644
index 000000000000..7e2e1d81af96
--- /dev/null
+++ b/lib/embedded-cmdline.S
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Embed the build-time-rendered bootconfig "kernel" subtree as a flat
+ * cmdline string. setup_arch() prepends this to boot_command_line on
+ * architectures that select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG.
+ *
+ * Copyright (c) 2026 Meta Platforms, Inc. and affiliates
+ * Copyright (c) 2026 Breno Leitao <leitao@debian.org>
+ */
+ .section .init.rodata, "aw"
+ .global embedded_kernel_cmdline
+embedded_kernel_cmdline:
+ .incbin "lib/embedded_cmdline.bin"
+ .byte 0
+ .global embedded_kernel_cmdline_end
+embedded_kernel_cmdline_end:
diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile
index 90eb47c9d8de..4e82fd9553cd 100644
--- a/tools/bootconfig/Makefile
+++ b/tools/bootconfig/Makefile
@@ -15,7 +15,7 @@ override CFLAGS += -Wall -g -I$(CURDIR)/include
ALL_TARGETS := bootconfig
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
-all: $(ALL_PROGRAMS) test
+all: $(ALL_PROGRAMS)
$(OUTPUT)bootconfig: main.c include/linux/bootconfig.h $(LIBSRC)
$(CC) $(filter %.c,$^) $(CFLAGS) $(LDFLAGS) -o $@
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/4] bootconfig: add xbc_prepend_embedded_cmdline() helper
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
2026-05-27 16:41 ` [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root Breno Leitao
2026-05-27 16:41 ` [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time Breno Leitao
@ 2026-05-27 16:41 ` Breno Leitao
2026-05-27 16:41 ` [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param Breno Leitao
2026-05-28 15:15 ` [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Masami Hiramatsu
4 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 16:41 UTC (permalink / raw)
To: Masami Hiramatsu, Andrew Morton, Nathan Chancellor, paulmck,
Nicolas Schier
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, Breno Leitao, kernel-team
Add a helper that prepends the build-time-rendered embedded bootconfig
"kernel" subtree (embedded_kernel_cmdline[] from embedded-cmdline.S) to
a cmdline buffer with a separating space. Architectures call this from
setup_arch() before parse_early_param() so early_param() handlers
(mem=, earlycon=, loglevel=, ...) see values supplied via the embedded
bootconfig.
On overflow the helper logs an error and leaves the cmdline untouched
rather than panicking. Booting without the embedded values is better
than refusing to boot, and the error tells the user why their embedded
keys are missing.
When CONFIG_BOOT_CONFIG_EMBED_CMDLINE=n, the public declaration in
<linux/bootconfig.h> resolves to a no-op stub so callers compile
unchanged.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/bootconfig.h | 7 +++++++
lib/bootconfig.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h
index 1c7f3b74ffcf..dcb0c86cbc54 100644
--- a/include/linux/bootconfig.h
+++ b/include/linux/bootconfig.h
@@ -308,4 +308,11 @@ static inline const char *xbc_get_embedded_bootconfig(size_t *size)
}
#endif
+/* Build-time-rendered bootconfig cmdline prepended in setup_arch() */
+#ifdef CONFIG_BOOT_CONFIG_EMBED_CMDLINE
+void __init xbc_prepend_embedded_cmdline(char *dst, size_t size);
+#else
+static inline void xbc_prepend_embedded_cmdline(char *dst, size_t size) { }
+#endif
+
#endif
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index 3a102c9122f7..10c62c8600c8 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/printk.h>
#include <linux/sprintf.h>
#include <linux/memblock.h>
#include <linux/string.h>
@@ -34,6 +35,53 @@ const char * __init xbc_get_embedded_bootconfig(size_t *size)
return (*size) ? embedded_bootconfig_data : NULL;
}
#endif
+
+#ifdef CONFIG_BOOT_CONFIG_EMBED_CMDLINE
+/* embedded_kernel_cmdline is defined in embedded-cmdline.S */
+extern __visible const char embedded_kernel_cmdline[];
+extern __visible const char embedded_kernel_cmdline_end[];
+
+/**
+ * xbc_prepend_embedded_cmdline() - Prepend embedded bootconfig cmdline
+ * @dst: cmdline buffer to prepend into (must already contain a NUL byte)
+ * @size: total capacity of @dst in bytes
+ *
+ * Prepend the build-time-rendered "kernel" subtree of the embedded
+ * bootconfig to @dst. The rendered string already ends with a single
+ * space (the xbc_snprint_cmdline() invariant), which serves as the
+ * separator between the embedded keys and any existing content of @dst.
+ * On overflow, log an error and leave @dst untouched rather than
+ * silently truncating: booting without the embedded values is better
+ * than refusing to boot, and the error message tells the user why
+ * their embedded keys are missing.
+ *
+ * Intended to be called from setup_arch() before parse_early_param() so
+ * that early_param() handlers see the embedded values.
+ */
+void __init xbc_prepend_embedded_cmdline(char *dst, size_t size)
+{
+ size_t embed_len = embedded_kernel_cmdline_end - embedded_kernel_cmdline;
+ size_t dst_len;
+
+ if (!size || embed_len <= 1) /* trailing NUL only */
+ return;
+ embed_len--; /* exclude trailing NUL byte */
+
+ dst_len = strnlen(dst, size);
+ if (embed_len + dst_len + 1 > size) {
+ pr_err("embedded bootconfig cmdline (%zu bytes) does not fit in COMMAND_LINE_SIZE with %zu bytes already used; ignoring embedded values\n",
+ embed_len, dst_len);
+ return;
+ }
+
+ if (dst_len)
+ memmove(dst + embed_len, dst, dst_len + 1);
+ else
+ dst[embed_len] = '\0';
+ memcpy(dst, embedded_kernel_cmdline, embed_len);
+}
+#endif
+
#endif
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
` (2 preceding siblings ...)
2026-05-27 16:41 ` [PATCH 3/4] bootconfig: add xbc_prepend_embedded_cmdline() helper Breno Leitao
@ 2026-05-27 16:41 ` Breno Leitao
2026-05-27 18:07 ` sashiko-bot
2026-05-28 15:15 ` [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Masami Hiramatsu
4 siblings, 1 reply; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 16:41 UTC (permalink / raw)
To: Masami Hiramatsu, Andrew Morton, Nathan Chancellor, paulmck,
Nicolas Schier
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, Breno Leitao, kernel-team
Call xbc_prepend_embedded_cmdline() in setup_arch() right after the
CONFIG_CMDLINE merge and before strscpy(command_line, ...) so the
build-time-rendered embedded bootconfig "kernel" subtree is part of
boot_command_line by the time parse_early_param() runs. early_param()
handlers (mem=, earlycon=, loglevel=, ...) now see values supplied via
CONFIG_BOOT_CONFIG_EMBED_FILE without parsing bootconfig at runtime.
Select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG so the user-visible
CONFIG_BOOT_CONFIG_EMBED_CMDLINE option becomes selectable on x86.
With this select in place, setup_boot_config() in init/main.c would
otherwise render the embedded "kernel" subtree a second time via
xbc_make_cmdline("kernel") and prepend it to saved_command_line /
static_command_line through extra_command_line, duplicating every
embedded kernel.* key in /proc/cmdline and causing accumulating
handlers (console=, earlycon=, ...) to register the same value twice.
Track whether the bootconfig data came from the embedded source and
skip the duplicate render in that case.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
arch/x86/Kconfig | 1 +
arch/x86/kernel/setup.c | 3 +++
init/main.c | 19 ++++++++++++++++---
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f24810015234..f839795692b4 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -126,6 +126,7 @@ config X86
select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096
select ARCH_SUPPORTS_CFI if X86_64
+ select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG
select ARCH_USES_CFI_TRAPS if X86_64 && CFI
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 46882ce79c3a..592c4c79c974 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -6,6 +6,7 @@
* parts of early kernel initialization.
*/
#include <linux/acpi.h>
+#include <linux/bootconfig.h>
#include <linux/console.h>
#include <linux/cpu.h>
#include <linux/crash_dump.h>
@@ -924,6 +925,8 @@ void __init setup_arch(char **cmdline_p)
builtin_cmdline_added = true;
#endif
+ xbc_prepend_embedded_cmdline(boot_command_line, COMMAND_LINE_SIZE);
+
strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
diff --git a/init/main.c b/init/main.c
index e363232b428b..8264bfa97aa2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -378,12 +378,15 @@ static void __init setup_boot_config(void)
int pos, ret;
size_t size;
char *err;
+ bool from_embedded = false;
/* Cut out the bootconfig data even if we have no bootconfig option */
data = get_boot_config_from_initrd(&size);
/* If there is no bootconfig in initrd, try embedded one. */
- if (!data)
+ if (!data) {
data = xbc_get_embedded_bootconfig(&size);
+ from_embedded = true;
+ }
strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL,
@@ -421,8 +424,18 @@ static void __init setup_boot_config(void)
} else {
xbc_get_info(&ret, NULL);
pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret);
- /* keys starting with "kernel." are passed via cmdline */
- extra_command_line = xbc_make_cmdline("kernel");
+ /*
+ * keys starting with "kernel." are passed via cmdline. When
+ * BOOT_CONFIG_EMBED_CMDLINE is enabled and this bootconfig
+ * came from the embedded source, setup_arch() already
+ * prepended the rendered "kernel" subtree to
+ * boot_command_line; rendering again here would duplicate
+ * the keys in saved_command_line / static_command_line and
+ * cause accumulating handlers (console=, earlycon=, ...) to
+ * re-register the same value.
+ */
+ if (!IS_ENABLED(CONFIG_BOOT_CONFIG_EMBED_CMDLINE) || !from_embedded)
+ extra_command_line = xbc_make_cmdline("kernel");
/* Also, "init." keys are init arguments */
extra_init_args = xbc_make_cmdline("init");
}
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
2026-05-27 16:41 ` [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root Breno Leitao
@ 2026-05-27 17:05 ` sashiko-bot
2026-06-01 17:46 ` Breno Leitao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-27 17:05 UTC (permalink / raw)
To: Breno Leitao; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The early return incorrectly assumes `xbc_node_is_leaf(root)` means there are no descendant key/value pairs, causing it to silently skip rendering valid subkeys if the root node has both a value and subkeys.
--
commit 7fe40e4bc583f53fe486de6d90af68f475369ee3
Author: Breno Leitao <leitao@debian.org>
bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
This commit changes xbc_snprint_cmdline() to return 0 instead of an error
when the root node is considered a leaf, preventing a build failure for
empty subtrees in the bootconfig tools.
> diff --git a/lib/bootconfig.c b/lib/bootconfig.c
> index f445b7703fdd9..3a102c9122f71 100644
> --- a/lib/bootconfig.c
> +++ b/lib/bootconfig.c
> @@ -431,6 +431,16 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
> const char *val, *q;
> int ret;
>
> + /*
> + * A leaf @root (e.g. an empty "kernel {}" subtree, or a key whose
> + * only child is a value node) has no descendant key/value pairs to
> + * render. The leaf-finding iterator below would otherwise return
> + * @root itself, which xbc_node_compose_key_after() rejects with
> + * -EINVAL.
> + */
> + if (root && xbc_node_is_leaf(root))
> + return 0;
[Severity: High]
This is a pre-existing issue, but does this early return unintentionally
skip valid descendant subkeys?
Looking at include/linux/bootconfig.h, xbc_node_is_leaf() evaluates to true
if a node has no children or its first child is a value node:
static inline __init bool xbc_node_is_leaf(struct xbc_node *node)
{
return xbc_node_is_key(node) &&
(!node->child || xbc_node_is_value(xbc_node_get_child(node)));
}
If a bootconfig contains a root node with both a value and subkeys
(for example, "kernel = val" and "kernel.param = 1"), xbc_node_is_leaf()
will evaluate to true for the root node.
Since this patch changes the behavior to return 0 instead of propagating
the -EINVAL error, will it silently skip rendering these descendant subkeys
and cause missing kernel command line parameters?
Would it be safer to drop this early return and instead add a check like
"if (knode == root) continue;" inside the xbc_node_for_each_key_value() loop
to skip the root's value while continuing to process its subkeys?
> +
> xbc_node_for_each_key_value(root, knode, val) {
> ret = xbc_node_compose_key_after(root, knode,
> xbc_namebuf, XBC_KEYLEN_MAX);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5@debian.org?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time
2026-05-27 16:41 ` [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time Breno Leitao
@ 2026-05-27 17:30 ` sashiko-bot
2026-06-01 17:52 ` Breno Leitao
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-05-27 17:30 UTC (permalink / raw)
To: Breno Leitao; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The `tools/bootconfig` executable is built using the target architecture's compiler instead of the host architecture's compiler, causing an `Exec format error` during cross-compilation.
- [Medium] The read-only data section `.init.rodata` is incorrectly marked as writable (`"aw"`).
- [Medium] Missing 'clean' target hook for tools/bootconfig in the top-level Makefile.
Pre-existing issues:
- [High] Pointer arithmetic on a NULL pointer and passing an invalid pointer to `snprintf()` in `xbc_snprint_cmdline()`.
--
commit d68de9beacfcd22ccb081a670940139845227254
Author: Breno Leitao <leitao@debian.org>
bootconfig: render embedded bootconfig as a kernel cmdline at build time
Add the build-time pipeline that renders the "kernel" subtree of
CONFIG_BOOT_CONFIG_EMBED_FILE into a flat cmdline string and stashes
it in .init.rodata as embedded_kernel_cmdline[].
> diff --git a/Makefile b/Makefile
> index d59f703f9797a..3ee259d00a9ae 100644
> --- a/Makefile
> +++ b/Makefile
[ ... ]
> @@ -1543,6 +1543,11 @@ prepare: tools/bpf/resolve_btfids
> endif
> endif
>
> +# lib/Makefile invokes tools/bootconfig to render the embedded bconf to cmdline.
> +ifdef CONFIG_BOOT_CONFIG_EMBED_CMDLINE
> +prepare: tools/bootconfig
> +endif
[Severity: Medium]
Will this leave stale build artifacts behind? Since tools/bootconfig is
wired into the prepare phase, should there also be a corresponding cleanup
step added to the top-level clean target so that make clean removes the
compiled binary and object files?
> diff --git a/lib/Makefile b/lib/Makefile
> index 6e72d2c1cce71..9de0ac7732a21 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
[ ... ]
> +quiet_cmd_render_cmdline = BCONF2C $@
> + cmd_render_cmdline = \
> + $(objtree)/tools/bootconfig/bootconfig -C $< > $@
> +
> +targets += embedded_cmdline.bin
> +$(obj)/embedded_cmdline.bin: $(obj)/default.bconf $(objtree)/tools/bootconfig/bootconfig FORCE
> + $(call if_changed,render_cmdline)
[Severity: High]
This isn't a bug introduced by this patch, but running bootconfig -C at
build time exposes an issue in xbc_snprint_cmdline().
When calculating the required buffer size, xbc_snprint_cmdline() is initially
called with buf = NULL and size = 0. The first snprintf(NULL, 0, ...)
returns the number of bytes that would be written, and the code then executes
buf += ret. Doing pointer arithmetic on a NULL pointer is undefined behavior.
In the next loop iteration, this invalid pointer is passed as the first
argument to snprintf(), which can trigger host UBSan failures or
FORTIFY_SOURCE aborts during the kernel build.
> diff --git a/lib/embedded-cmdline.S b/lib/embedded-cmdline.S
> new file mode 100644
> index 0000000000000..7e2e1d81af962
> --- /dev/null
> +++ b/lib/embedded-cmdline.S
> @@ -0,0 +1,16 @@
[ ... ]
> + .section .init.rodata, "aw"
[Severity: Medium]
Does this mistakenly mark the read-only section as writable?
The "w" flag instructs the assembler and linker to make the section writable,
violating the expectation for .rodata and potentially bypassing memory
protections. Should this use "a" or the __INITRODATA macro instead?
> diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile
> index 90eb47c9d8de6..4e82fd9553cde 100644
> --- a/tools/bootconfig/Makefile
> +++ b/tools/bootconfig/Makefile
[ ... ]
> -all: $(ALL_PROGRAMS) test
> +all: $(ALL_PROGRAMS)
>
> $(OUTPUT)bootconfig: main.c include/linux/bootconfig.h $(LIBSRC)
> $(CC) $(filter %.c,$^) $(CFLAGS) $(LDFLAGS) -o $@
[Severity: High]
When cross-compiling the kernel, does this build bootconfig for the
target architecture instead of the host?
Kbuild exports CC as the target cross-compiler (e.g., aarch64-linux-gnu-gcc).
Because this uses $(CC) rather than a host override like $(HOSTCC) (which
objtool and resolve_btfids use), the tool is built for the target architecture.
Later, lib/Makefile attempts to execute this tool on the build host to render
the cmdline, which will fail with an Exec format error.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5@debian.org?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param
2026-05-27 16:41 ` [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param Breno Leitao
@ 2026-05-27 18:07 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-05-27 18:07 UTC (permalink / raw)
To: Breno Leitao; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unconditional application of embedded bootconfig `kernel` keys bypasses the `bootconfig` parameter opt-in requirement.
--
commit 571add72b0db9b7dbd9f5c179025b85435fd8e31
Author: Breno Leitao <leitao@debian.org>
x86/setup: prepend embedded bootconfig cmdline before parse_early_param
This commit prepends the embedded bootconfig kernel subtree to the command
line in setup_arch() before parse_early_param() runs. It allows early
parameter handlers to see bootconfig values without runtime parsing, while
avoiding duplicate registrations in setup_boot_config().
> diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
> index 46882ce79c3a4..592c4c79c974b 100644
> --- a/arch/x86/kernel/setup.c
> +++ b/arch/x86/kernel/setup.c
[ ... ]
> @@ -924,6 +925,8 @@ void __init setup_arch(char **cmdline_p)
> builtin_cmdline_added = true;
> #endif
>
> + xbc_prepend_embedded_cmdline(boot_command_line, COMMAND_LINE_SIZE);
> +
[Severity: High]
Does this unconditional call bypass the bootconfig opt-in requirement?
Documentation/admin-guide/bootconfig.rst specifies that embedded bootconfigs
must be explicitly enabled via the bootconfig command-line parameter, unless
CONFIG_BOOT_CONFIG_FORCE is set.
Could this create a semantic inconsistency if a user boots without the
bootconfig parameter? It appears setup_boot_config() would correctly ignore
the embedded init.* keys, but these embedded kernel.* keys would still be
forcefully applied.
Furthermore, does this impact the bootconfig fail-safe recovery mechanism?
If a malformed embedded kernel.* key (such as an invalid console= or mem=)
causes a kernel panic, would an administrator be unable to disable it by
removing bootconfig from the bootloader command line?
> strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
> *cmdline_p = command_line;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5@debian.org?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
` (3 preceding siblings ...)
2026-05-27 16:41 ` [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param Breno Leitao
@ 2026-05-28 15:15 ` Masami Hiramatsu
2026-05-28 16:14 ` Breno Leitao
2026-06-01 17:56 ` Breno Leitao
4 siblings, 2 replies; 13+ messages in thread
From: Masami Hiramatsu @ 2026-05-28 15:15 UTC (permalink / raw)
To: Breno Leitao
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, kernel-team
On Wed, 27 May 2026 09:41:33 -0700
Breno Leitao <leitao@debian.org> wrote:
> The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
> already landed; this series wires the rendered cmdline into the kernel.
>
> Motivation: today the embedded bootconfig is parsed at runtime, after
> parse_early_param() has already run, so early_param() handlers can't
> see embedded values. Folding the kernel.* subtree into the cmdline at
> build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
> users without forcing them to maintain two cmdline sources.
>
> Behaviorally, the "kernel" subtree is rendered to a flat string at
> build time and stashed in .init.rodata. setup_arch() prepends it to
> boot_command_line before parse_early_param() runs. Overflow is a soft
> error: the helper logs and leaves boot_command_line untouched rather
> than panicking, so an oversized embedded bconf cannot brick a boot.
>
Thanks Breno, yes, that is what I think about.
Let me check it. And could you also check Sashiko's comments?
https://sashiko.dev/#/patchset/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5%40debian.org
Thanks,
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> Breno Leitao (4):
> bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
> bootconfig: render embedded bootconfig as a kernel cmdline at build time
> bootconfig: add xbc_prepend_embedded_cmdline() helper
> x86/setup: prepend embedded bootconfig cmdline before parse_early_param
>
> Makefile | 5 ++++
> arch/x86/Kconfig | 1 +
> arch/x86/kernel/setup.c | 3 +++
> include/linux/bootconfig.h | 7 ++++++
> init/Kconfig | 33 ++++++++++++++++++++++++++
> init/main.c | 19 ++++++++++++---
> lib/Makefile | 16 +++++++++++++
> lib/bootconfig.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++
> lib/embedded-cmdline.S | 16 +++++++++++++
> tools/bootconfig/Makefile | 2 +-
> 10 files changed, 156 insertions(+), 4 deletions(-)
> ---
> base-commit: e7e28506af98ce4e1059e5ec59334b335c00a246
> change-id: 20260508-bootconfig_using_tools-cfa7aa9d6a5a
>
> Best regards,
> --
> Breno Leitao <leitao@debian.org>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time
2026-05-28 15:15 ` [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Masami Hiramatsu
@ 2026-05-28 16:14 ` Breno Leitao
2026-06-01 17:56 ` Breno Leitao
1 sibling, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-28 16:14 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, kernel-team
On Fri, May 29, 2026 at 12:15:19AM +0000, Masami Hiramatsu wrote:
> On Wed, 27 May 2026 09:41:33 -0700
> Breno Leitao <leitao@debian.org> wrote:
>
> > The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
> > already landed; this series wires the rendered cmdline into the kernel.
> >
> > Motivation: today the embedded bootconfig is parsed at runtime, after
> > parse_early_param() has already run, so early_param() handlers can't
> > see embedded values. Folding the kernel.* subtree into the cmdline at
> > build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
> > users without forcing them to maintain two cmdline sources.
> >
> > Behaviorally, the "kernel" subtree is rendered to a flat string at
> > build time and stashed in .init.rodata. setup_arch() prepends it to
> > boot_command_line before parse_early_param() runs. Overflow is a soft
> > error: the helper logs and leaves boot_command_line untouched rather
> > than panicking, so an oversized embedded bconf cannot brick a boot.
> >
>
> Thanks Breno, yes, that is what I think about.
> Let me check it. And could you also check Sashiko's comments?
>
> https://sashiko.dev/#/patchset/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5%40debian.org
Ack, I will have a look at them, thanks for confirming the direction is
correct.
--breno
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
2026-05-27 17:05 ` sashiko-bot
@ 2026-06-01 17:46 ` Breno Leitao
0 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-06-01 17:46 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, May 27, 2026 at 05:05:21PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The early return incorrectly assumes `xbc_node_is_leaf(root)` means there are no descendant key/value pairs, causing it to silently skip rendering valid subkeys if the root node has both a value and subkeys.
> --
>
> commit 7fe40e4bc583f53fe486de6d90af68f475369ee3
> Author: Breno Leitao <leitao@debian.org>
>
> bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root
>
> This commit changes xbc_snprint_cmdline() to return 0 instead of an error
> when the root node is considered a leaf, preventing a build failure for
> empty subtrees in the bootconfig tools.
>
> > diff --git a/lib/bootconfig.c b/lib/bootconfig.c
> > index f445b7703fdd9..3a102c9122f71 100644
> > --- a/lib/bootconfig.c
> > +++ b/lib/bootconfig.c
> > @@ -431,6 +431,16 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
> > const char *val, *q;
> > int ret;
> >
> > + /*
> > + * A leaf @root (e.g. an empty "kernel {}" subtree, or a key whose
> > + * only child is a value node) has no descendant key/value pairs to
> > + * render. The leaf-finding iterator below would otherwise return
> > + * @root itself, which xbc_node_compose_key_after() rejects with
> > + * -EINVAL.
> > + */
> > + if (root && xbc_node_is_leaf(root))
> > + return 0;
>
> [Severity: High]
> This is a pre-existing issue, but does this early return unintentionally
> skip valid descendant subkeys?
>
> Looking at include/linux/bootconfig.h, xbc_node_is_leaf() evaluates to true
> if a node has no children or its first child is a value node:
>
> static inline __init bool xbc_node_is_leaf(struct xbc_node *node)
> {
> return xbc_node_is_key(node) &&
> (!node->child || xbc_node_is_value(xbc_node_get_child(node)));
> }
>
> If a bootconfig contains a root node with both a value and subkeys
> (for example, "kernel = val" and "kernel.param = 1"), xbc_node_is_leaf()
> will evaluate to true for the root node.
>
> Since this patch changes the behavior to return 0 instead of propagating
> the -EINVAL error, will it silently skip rendering these descendant subkeys
> and cause missing kernel command line parameters?
>
> Would it be safer to drop this early return and instead add a check like
> "if (knode == root) continue;" inside the xbc_node_for_each_key_value() loop
> to skip the root's value while continuing to process its subkeys?
Good catch, you're right. If @root carries both a value and child keys
(e.g. "kernel = val" together with "kernel.foo = bar"),
xbc_node_is_leaf(root) is true -- root's first child is a value node --
so the early return drops kernel.foo=bar, which the pre-patch code did
render.
For v2 I'll drop the early return and skip @root itself inside the loop,
as you suggest:
xbc_node_for_each_key_value(root, knode, val) {
/*
* An empty or value-only @root yields @root itself here;
* skip it so we still render any real descendant keys
* (and return 0 rather than -EINVAL for an empty subtree).
*/
if (knode == root)
continue;
...
}
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time
2026-05-27 17:30 ` sashiko-bot
@ 2026-06-01 17:52 ` Breno Leitao
0 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-06-01 17:52 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, May 27, 2026 at 05:30:36PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
>
> New issues:
> - [High] The `tools/bootconfig` executable is built using the target architecture's compiler instead of the host architecture's compiler, causing an `Exec format error` during cross-compilation.
> - [Medium] The read-only data section `.init.rodata` is incorrectly marked as writable (`"aw"`).
> - [Medium] Missing 'clean' target hook for tools/bootconfig in the top-level Makefile.
>
> Pre-existing issues:
> - [High] Pointer arithmetic on a NULL pointer and passing an invalid pointer to `snprintf()` in `xbc_snprint_cmdline()`.
> --
>
> commit d68de9beacfcd22ccb081a670940139845227254
> Author: Breno Leitao <leitao@debian.org>
>
> bootconfig: render embedded bootconfig as a kernel cmdline at build time
>
> Add the build-time pipeline that renders the "kernel" subtree of
> CONFIG_BOOT_CONFIG_EMBED_FILE into a flat cmdline string and stashes
> it in .init.rodata as embedded_kernel_cmdline[].
>
> > diff --git a/Makefile b/Makefile
> > index d59f703f9797a..3ee259d00a9ae 100644
> > --- a/Makefile
> > +++ b/Makefile
> [ ... ]
> > @@ -1543,6 +1543,11 @@ prepare: tools/bpf/resolve_btfids
> > endif
> > endif
> >
> > +# lib/Makefile invokes tools/bootconfig to render the embedded bconf to cmdline.
> > +ifdef CONFIG_BOOT_CONFIG_EMBED_CMDLINE
> > +prepare: tools/bootconfig
> > +endif
>
> [Severity: Medium]
> Will this leave stale build artifacts behind? Since tools/bootconfig is
> wired into the prepare phase, should there also be a corresponding cleanup
> step added to the top-level clean target so that make clean removes the
> compiled binary and object files?
Correct, and this is the important one. lib/Makefile runs the binary on
the build host, so it must be built with the host compiler. Plain $(CC)
is the target cross-compiler under an ARCH=... build, so the tool comes
out as a target binary and fails to exec. I'll build it with $(HOSTCC),
matching how tools/objtool and tools/bpf/resolve_btfids do it
(HOST_OVERRIDES := CC="$(HOSTCC)" ...). This also fixes a standalone
cross-build of the tool.
> > diff --git a/lib/Makefile b/lib/Makefile
> > index 6e72d2c1cce71..9de0ac7732a21 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> [ ... ]
> > +quiet_cmd_render_cmdline = BCONF2C $@
> > + cmd_render_cmdline = \
> > + $(objtree)/tools/bootconfig/bootconfig -C $< > $@
> > +
> > +targets += embedded_cmdline.bin
> > +$(obj)/embedded_cmdline.bin: $(obj)/default.bconf $(objtree)/tools/bootconfig/bootconfig FORCE
> > + $(call if_changed,render_cmdline)
>
> [Severity: High]
> This isn't a bug introduced by this patch, but running bootconfig -C at
> build time exposes an issue in xbc_snprint_cmdline().
I will fix it in a different patch.
>
> When calculating the required buffer size, xbc_snprint_cmdline() is initially
> called with buf = NULL and size = 0. The first snprintf(NULL, 0, ...)
> returns the number of bytes that would be written, and the code then executes
> buf += ret. Doing pointer arithmetic on a NULL pointer is undefined behavior.
>
> In the next loop iteration, this invalid pointer is passed as the first
> argument to snprintf(), which can trigger host UBSan failures or
> FORTIFY_SOURCE aborts during the kernel build.
>
> > diff --git a/lib/embedded-cmdline.S b/lib/embedded-cmdline.S
> > new file mode 100644
> > index 0000000000000..7e2e1d81af962
> > --- /dev/null
> > +++ b/lib/embedded-cmdline.S
> > @@ -0,0 +1,16 @@
> [ ... ]
> > + .section .init.rodata, "aw"
>
> [Severity: Medium]
> Does this mistakenly mark the read-only section as writable?
>
> The "w" flag instructs the assembler and linker to make the section writable,
> violating the expectation for .rodata and potentially bypassing memory
> protections. Should this use "a" or the __INITRODATA macro instead?
Agreed -- the "w" flag has no business on rodata. I'll drop it to "a"
(read-only, allocatable) in lib/embedded-cmdline.S.
>
> > diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile
> > index 90eb47c9d8de6..4e82fd9553cde 100644
> > --- a/tools/bootconfig/Makefile
> > +++ b/tools/bootconfig/Makefile
> [ ... ]
> > -all: $(ALL_PROGRAMS) test
> > +all: $(ALL_PROGRAMS)
> >
> > $(OUTPUT)bootconfig: main.c include/linux/bootconfig.h $(LIBSRC)
> > $(CC) $(filter %.c,$^) $(CFLAGS) $(LDFLAGS) -o $@
>
> [Severity: High]
> When cross-compiling the kernel, does this build bootconfig for the
> target architecture instead of the host?
>
> Kbuild exports CC as the target cross-compiler (e.g., aarch64-linux-gnu-gcc).
> Because this uses $(CC) rather than a host override like $(HOSTCC) (which
> objtool and resolve_btfids use), the tool is built for the target architecture.
>
> Later, lib/Makefile attempts to execute this tool on the build host to render
> the cmdline, which will fail with an Exec format error.
Correct, and this is the important one. lib/Makefile runs the binary on
the build host, so it must be built with the host compiler. Plain $(CC)
is the target cross-compiler under an ARCH=... build, so the tool comes
out as a target binary and fails to exec. I'll build it with $(HOSTCC),
matching how tools/objtool and tools/bpf/resolve_btfids do it
(HOST_OVERRIDES := CC="$(HOSTCC)" ...). This also fixes a standalone
cross-build of the tool.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time
2026-05-28 15:15 ` [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Masami Hiramatsu
2026-05-28 16:14 ` Breno Leitao
@ 2026-06-01 17:56 ` Breno Leitao
1 sibling, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-06-01 17:56 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, linux-kernel, linux-trace-kernel, linux-kbuild,
bpf, kernel-team
On Fri, May 29, 2026 at 12:15:19AM +0900, Masami Hiramatsu wrote:
> On Wed, 27 May 2026 09:41:33 -0700
> Breno Leitao <leitao@debian.org> wrote:
>
> > The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
> > already landed; this series wires the rendered cmdline into the kernel.
> >
> > Motivation: today the embedded bootconfig is parsed at runtime, after
> > parse_early_param() has already run, so early_param() handlers can't
> > see embedded values. Folding the kernel.* subtree into the cmdline at
> > build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
> > users without forcing them to maintain two cmdline sources.
> >
> > Behaviorally, the "kernel" subtree is rendered to a flat string at
> > build time and stashed in .init.rodata. setup_arch() prepends it to
> > boot_command_line before parse_early_param() runs. Overflow is a soft
> > error: the helper logs and leaves boot_command_line untouched rather
> > than panicking, so an oversized embedded bconf cannot brick a boot.
> >
>
> Thanks Breno, yes, that is what I think about.
> Let me check it. And could you also check Sashiko's comments?
yes, I've spent some time on them, and it reported some good points, in
fact. I will fix those and resend.
Thanks!
--breno
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-06-01 17:56 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-27 16:41 [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Breno Leitao
2026-05-27 16:41 ` [PATCH 1/4] bootconfig: return 0 from xbc_snprint_cmdline() for a leaf root Breno Leitao
2026-05-27 17:05 ` sashiko-bot
2026-06-01 17:46 ` Breno Leitao
2026-05-27 16:41 ` [PATCH 2/4] bootconfig: render embedded bootconfig as a kernel cmdline at build time Breno Leitao
2026-05-27 17:30 ` sashiko-bot
2026-06-01 17:52 ` Breno Leitao
2026-05-27 16:41 ` [PATCH 3/4] bootconfig: add xbc_prepend_embedded_cmdline() helper Breno Leitao
2026-05-27 16:41 ` [PATCH 4/4] x86/setup: prepend embedded bootconfig cmdline before parse_early_param Breno Leitao
2026-05-27 18:07 ` sashiko-bot
2026-05-28 15:15 ` [PATCH 0/4] bootconfig: embed kernel.* cmdline at build time Masami Hiramatsu
2026-05-28 16:14 ` Breno Leitao
2026-06-01 17:56 ` Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox