* Bootconfig updates for v7.4
@ 2026-10-22 0:14 Masami Hiramatsu
2026-10-22 0:43 ` Masami Hiramatsu
0 siblings, 1 reply; 2+ messages in thread
From: Masami Hiramatsu @ 2026-10-22 0:14 UTC (permalink / raw)
To: Linus Torvalds
Cc: Masami Hiramatsu, Sang-Heon Jeon, Steven Rostedt,
Masami Hiramatsu, linux-kernel
Hi Linus,
Bootconfig updates for v7.4:
- bootconfig: Parser robustness and validation improvements
. Skip printing early params to cmdline from bootconfig: Suppress
early_param keys from /proc/cmdline and warn the user, since bootconfig
does not invoke early_param handlers and silently ignoring them is
misleading.
. Reject unexpected data after null character: Detect and reject non-null
data following an intermediate null character in the bootconfig buffer,
preventing silently ignored configuration after an early termination.
- bootconfig: Code cleanups
. Merge _xbc_exit() into xbc_exit(): Since memblock_free() now handles
late freeing and NULL addresses, the separate _xbc_exit() helper and
its early argument are unnecessary. Inline it into xbc_exit().
. Remove redundant assignment in xbc_parse_array(): The node->child = 0
assignment after the loop duplicates what xbc_init_node() already did.
. Skip internal tree sanity checks in kernel: Move the node index bounds
loop from xbc_verify_tree() into a userspace-only xbc_sanity_check_tree()
to reduce boot-time overhead, since out-of-bounds indices cannot be
produced by malformed input.
. Move BOOTCONFIG_FOOTER_SIZE to include/linux/bootconfig.h: Share the
footer size constant between kernel and user-space tools, replacing the
hardcoded (BOOTCONFIG_MAGIC_LEN + 8) expression in init/main.c.
- tools/bootconfig: Tooling improvements
. Remove unused PAGE_SIZE macro from the bootconfig tool.
. Consolidate xbc_init() to error message wrapper: Use
init_xbc_with_error() for all bootconfig initialization paths in the
tool for simpler and more consistent error handling.
Please pull the latest bootconfig-v7.4 tree, which can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
bootconfig-v7.4
Tag SHA1: 8c84ad1d280719b36079cdd280da8214c3a8013d
Head SHA1: 677f83795fdfc25ddc51b665a9111f5ff199f7ca
Masami Hiramatsu (Google) (5):
bootconfig: Skip printing early params to cmdline from bootconfig
bootconfig: Reject unexpected data after null character
tools/bootconfig: Consolidate xbc_init() to error message wrapper
bootconfig: Skip internal tree sanity checks in kernel
bootconfig: Move BOOTCONFIG_FOOTER_SIZE to include/linux/bootconfig.h
Sang-Heon Jeon (3):
bootconfig: merge _xbc_exit() into xbc_exit()
bootconfig: remove redundant assignment in xbc_parse_array()
tools/bootconfig: remove unused PAGE_SIZE macro
----
include/linux/bootconfig.h | 21 ++++---
init/main.c | 75 ++++++++++++++++++++++---
lib/bootconfig.c | 84 +++++++++++++++++-----------
tools/bootconfig/main.c | 108 +++++++++++++++---------------------
tools/bootconfig/test-bootconfig.sh | 12 ++++
5 files changed, 192 insertions(+), 108 deletions(-)
---------------------------
diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h
index deda507500da..260a6f46042e 100644
--- a/include/linux/bootconfig.h
+++ b/include/linux/bootconfig.h
@@ -27,6 +27,10 @@ bool __init cmdline_has_extra_options(void);
#define BOOTCONFIG_ALIGN (1 << BOOTCONFIG_ALIGN_SHIFT)
#define BOOTCONFIG_ALIGN_MASK (BOOTCONFIG_ALIGN - 1)
+/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */
+#define BOOTCONFIG_FOOTER_SIZE \
+ (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN)
+
/**
* xbc_calc_checksum() - Calculate checksum of bootconfig
* @data: Bootconfig data.
@@ -266,7 +270,15 @@ int __init xbc_node_compose_key_after(struct xbc_node *root,
struct xbc_node *node, char *buf, size_t size);
/* Render key/value pairs under @root as a flat cmdline string */
-int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root);
+typedef bool (*xbc_cmdline_filter_fn)(struct xbc_node *node, const char *key, void *data);
+
+int __init xbc_snprint_cmdline_filter(char *buf, size_t size, struct xbc_node *root,
+ xbc_cmdline_filter_fn filter, void *data);
+
+static inline int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
+{
+ return xbc_snprint_cmdline_filter(buf, size, root, NULL, NULL);
+}
/**
* xbc_node_compose_key() - Compose full key string of the XBC node
@@ -291,12 +303,7 @@ int __init xbc_init(const char *buf, size_t size, const char **emsg, int *epos);
int __init xbc_get_info(int *node_size, size_t *data_size);
/* XBC cleanup data structures */
-void __init _xbc_exit(bool early);
-
-static __always_inline void xbc_exit(void)
-{
- _xbc_exit(false);
-}
+void __init xbc_exit(void);
/* XBC embedded bootconfig data in kernel */
#ifdef CONFIG_BOOT_CONFIG_EMBED
diff --git a/init/main.c b/init/main.c
index 16749bb7a219..861e07f6c05c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -278,7 +278,7 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
int i;
if (!initrd_end || initrd_end < initrd_start ||
- initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8)
+ initrd_end - initrd_start < BOOTCONFIG_FOOTER_SIZE)
return NULL;
data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
@@ -336,9 +336,64 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
#ifdef CONFIG_BOOT_CONFIG
+/* Check if a parameter name matches an obs_kernel_param entry */
+static bool __init match_obs_param(const char *param, const char *pattern)
+{
+ size_t n = strlen(pattern);
+
+ if (n > 0 && pattern[n - 1] == '=')
+ return parameqn(param, pattern, n - 1) && param[n - 1] == '\0';
+
+ return parameq(param, pattern);
+}
+
+/* Return true if the given param is only defined by early_param(). */
+static bool __init is_early_only_param(const char *param)
+{
+ const struct obs_kernel_param *p;
+ const struct kernel_param *kp;
+ bool has_early = false;
+
+ /* If handled by a regular module_param, it is not early-only */
+ for (kp = __start___param; kp < __stop___param; kp++) {
+ if (parameq(param, kp->name))
+ return false;
+ }
+
+ /* Check __setup / early_param table */
+ for (p = __setup_start; p < __setup_end; p++) {
+ if (match_obs_param(param, p->str)) {
+ if (!p->early)
+ return false;
+ has_early = true;
+ }
+ }
+ return has_early;
+}
+
+struct xbc_filter_data {
+ bool warn;
+};
+
+static bool __init xbc_kernel_param_filter(struct xbc_node *node,
+ const char *key, void *data)
+{
+ struct xbc_filter_data *fdata = data;
+
+ if (is_early_only_param(key)) {
+ if (fdata && fdata->warn)
+ pr_warn("bootconfig: early_param 'kernel.%s' cannot be applied from bootconfig, skipping\n",
+ key);
+ return false;
+ }
+ return true;
+}
+
/* Make an extra command line under given key word */
-static char * __init xbc_make_cmdline(const char *key)
+static char * __init xbc_make_cmdline(const char *key, bool is_kernel)
{
+ struct xbc_filter_data fdata = { .warn = true };
+ xbc_cmdline_filter_fn filter = is_kernel ? xbc_kernel_param_filter : NULL;
struct xbc_node *root;
char *new_cmdline;
int ret, len = 0;
@@ -347,8 +402,12 @@ static char * __init xbc_make_cmdline(const char *key)
if (!root)
return NULL;
- /* Count required buffer size */
- len = xbc_snprint_cmdline(NULL, 0, root);
+ /*
+ * Pass 1: Count required buffer size. Emit warnings for skipped early
+ * params in this pass so they are logged even if all parameters under
+ * @key are skipped and len becomes 0.
+ */
+ len = xbc_snprint_cmdline_filter(NULL, 0, root, filter, &fdata);
if (len <= 0)
return NULL;
@@ -358,7 +417,9 @@ static char * __init xbc_make_cmdline(const char *key)
return NULL;
}
- ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
+ /* Pass 2: Render into buffer with warnings suppressed */
+ fdata.warn = false;
+ ret = xbc_snprint_cmdline_filter(new_cmdline, len + 1, root, filter, &fdata);
if (ret < 0 || ret > len) {
pr_err("Failed to print extra kernel cmdline.\n");
memblock_free(new_cmdline, len + 1);
@@ -432,9 +493,9 @@ static void __init setup_boot_config(void)
* before this series.
*/
if (!from_embedded || !xbc_embedded_cmdline_applied())
- extra_command_line = xbc_make_cmdline("kernel");
+ extra_command_line = xbc_make_cmdline("kernel", true);
/* Also, "init." keys are init arguments */
- extra_init_args = xbc_make_cmdline("init");
+ extra_init_args = xbc_make_cmdline("init", false);
}
return;
}
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index 89c88e359179..819685d6c68d 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -187,12 +187,9 @@ static inline void * __init xbc_alloc_mem(size_t size)
return memblock_alloc(size, SMP_CACHE_BYTES);
}
-static inline void __init xbc_free_mem(void *addr, size_t size, bool early)
+static inline void __init xbc_free_mem(void *addr, size_t size)
{
- if (early)
- memblock_free(addr, size);
- else if (addr)
- memblock_free(addr, size);
+ memblock_free(addr, size);
}
#else /* !__KERNEL__ */
@@ -202,7 +199,7 @@ static inline void *xbc_alloc_mem(size_t size)
return calloc(1, size);
}
-static inline void xbc_free_mem(void *addr, size_t size, bool early)
+static inline void xbc_free_mem(void *addr, size_t size)
{
free(addr);
}
@@ -539,18 +536,21 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
/**
- * xbc_snprint_cmdline() - Render bootconfig keys under @root as a cmdline string
+ * xbc_snprint_cmdline_filter() - Render bootconfig keys as cmdline string
* @buf: Destination buffer (may be NULL when @size is 0 to query the length)
* @size: Size of @buf in bytes
* @root: Subtree root whose key=value pairs should be rendered
+ * @filter: Filter callback (returns true to include, false to skip; may be NULL)
+ * @data: Private context passed to @filter
*
* Walk all key/value pairs under @root and emit them as a space-separated
* cmdline string into @buf. Values containing whitespace are quoted with
- * double quotes. Returns the number of bytes that would be written if @buf
- * were large enough (matching snprintf semantics), or a negative errno on
- * failure.
+ * double quotes. Keys for which @filter returns false are omitted.
+ * Returns the number of bytes that would be written if @buf were large enough
+ * (matching snprintf semantics), or a negative errno on failure.
*/
-int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
+int __init xbc_snprint_cmdline_filter(char *buf, size_t size, struct xbc_node *root,
+ xbc_cmdline_filter_fn filter, void *data)
{
struct xbc_node *knode, *vnode;
const char *val, *q;
@@ -582,6 +582,9 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
if (ret < 0)
return ret;
+ if (filter && !filter(knode, xbc_namebuf, data))
+ continue;
+
vnode = xbc_node_get_child(knode);
if (!vnode) {
ret = snprintf(buf ? buf + len : NULL, rest(len, size),
@@ -836,7 +839,6 @@ static int __init xbc_parse_array(char **__v)
return -ENOMEM;
*__v = next;
} while (c == ',');
- node->child = 0;
return c;
}
@@ -1003,9 +1005,30 @@ static int __init xbc_close_brace(char **k, char *n)
return __xbc_close_brace(n - 1);
}
+#ifndef __KERNEL__
+/* Sanity check for regression: node indices must be within bounds */
+static int __init xbc_sanity_check_tree(void)
+{
+ int i;
+
+ for (i = 0; i < xbc_node_num; i++) {
+ if (xbc_nodes[i].next >= xbc_node_num) {
+ return xbc_parse_error("No closing brace",
+ xbc_node_get_data(xbc_nodes + i));
+ }
+ if (xbc_nodes[i].child >= xbc_node_num) {
+ return xbc_parse_error("Broken child node",
+ xbc_node_get_data(xbc_nodes + i));
+ }
+ }
+
+ return 0;
+}
+#endif
+
static int __init xbc_verify_tree(void)
{
- int i, depth;
+ int depth;
size_t len, wlen;
struct xbc_node *n, *m;
@@ -1022,17 +1045,6 @@ static int __init xbc_verify_tree(void)
return -ENOENT;
}
- for (i = 0; i < xbc_node_num; i++) {
- if (xbc_nodes[i].next >= xbc_node_num) {
- return xbc_parse_error("No closing brace",
- xbc_node_get_data(xbc_nodes + i));
- }
- if (xbc_nodes[i].child >= xbc_node_num) {
- return xbc_parse_error("Broken child node",
- xbc_node_get_data(xbc_nodes + i));
- }
- }
-
/* Key tree limitation check */
n = &xbc_nodes[0];
depth = 1;
@@ -1119,24 +1131,30 @@ static int __init xbc_parse_tree(void)
}
} while (!ret);
+ if (!ret) {
+ while (p < xbc_data + xbc_data_size - 1 && *p == '\0')
+ p++;
+ if (p < xbc_data + xbc_data_size - 1)
+ ret = xbc_parse_error("Unexpected data after null character", p);
+ }
+
return ret;
}
/**
- * _xbc_exit() - Clean up all parsed bootconfig
- * @early: Set true if this is called before budy system is initialized.
+ * xbc_exit() - Clean up all parsed bootconfig
*
* This clears all data structures of parsed bootconfig on memory.
* If you need to reuse xbc_init() with new boot config, you can
* use this.
*/
-void __init _xbc_exit(bool early)
+void __init xbc_exit(void)
{
- xbc_free_mem(xbc_data, xbc_data_size, early);
+ xbc_free_mem(xbc_data, xbc_data_size);
xbc_data = NULL;
xbc_data_size = 0;
xbc_node_num = 0;
- xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX, early);
+ xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX);
xbc_nodes = NULL;
brace_index = 0;
}
@@ -1189,20 +1207,24 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos)
if (!xbc_nodes) {
if (emsg)
*emsg = "Failed to allocate bootconfig nodes";
- _xbc_exit(true);
+ xbc_exit();
return -ENOMEM;
}
ret = xbc_parse_tree();
if (!ret)
ret = xbc_verify_tree();
+#ifndef __KERNEL__
+ if (!ret)
+ ret = xbc_sanity_check_tree();
+#endif
if (ret < 0) {
if (epos)
*epos = xbc_err_pos;
if (emsg)
*emsg = xbc_err_msg;
- _xbc_exit(true);
+ xbc_exit();
} else {
ret = xbc_node_num;
}
diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c
index 17d971d47f87..56d76bdeaa09 100644
--- a/tools/bootconfig/main.c
+++ b/tools/bootconfig/main.c
@@ -17,9 +17,38 @@
#define pr_err(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
-/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */
-#define BOOTCONFIG_FOOTER_SIZE \
- (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN)
+static void show_xbc_error(const char *data, const char *msg, int pos)
+{
+ int lin = 1, col, i;
+
+ if (pos < 0) {
+ pr_err("Error: %s.\n", msg);
+ return;
+ }
+
+ /* Note that pos starts from 0 but lin and col should start from 1. */
+ col = pos + 1;
+ for (i = 0; i < pos; i++) {
+ if (data[i] == '\n') {
+ lin++;
+ col = pos - i;
+ }
+ }
+ pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
+
+}
+
+static int init_xbc_with_error(char *buf, int len)
+{
+ const char *msg;
+ int ret, pos;
+
+ ret = xbc_init(buf, len, &msg, &pos);
+ if (ret < 0)
+ show_xbc_error(buf, msg, pos);
+
+ return ret;
+}
static int xbc_show_value(struct xbc_node *node, bool semicolon)
{
@@ -134,8 +163,6 @@ static void xbc_show_list(void)
}
}
-#define PAGE_SIZE 4096
-
static int load_xbc_fd(int fd, char **buf, int size)
{
int ret;
@@ -197,7 +224,6 @@ static int load_xbc_from_initrd(int fd, char **buf)
int ret;
uint32_t size = 0, csum = 0, rcsum;
char magic[BOOTCONFIG_MAGIC_LEN];
- const char *msg;
ret = fstat(fd, &stat);
if (ret < 0)
@@ -249,52 +275,9 @@ static int load_xbc_from_initrd(int fd, char **buf)
return -EINVAL;
}
- ret = xbc_init(*buf, size, &msg, NULL);
- /* Wrong data */
- if (ret < 0) {
- pr_err("parse error: %s.\n", msg);
- return ret;
- }
-
- return size;
-}
-
-static void show_xbc_error(const char *data, const char *msg, int pos)
-{
- int lin = 1, col, i;
-
- if (pos < 0) {
- pr_err("Error: %s.\n", msg);
- return;
- }
-
- /* Note that pos starts from 0 but lin and col should start from 1. */
- col = pos + 1;
- for (i = 0; i < pos; i++) {
- if (data[i] == '\n') {
- lin++;
- col = pos - i;
- }
- }
- pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
+ ret = init_xbc_with_error(*buf, size);
-}
-
-static int init_xbc_with_error(char *buf, int len)
-{
- char *copy = strdup(buf);
- const char *msg;
- int ret, pos;
-
- if (!copy)
- return -ENOMEM;
-
- ret = xbc_init(buf, len, &msg, &pos);
- if (ret < 0)
- show_xbc_error(copy, msg, pos);
- free(copy);
-
- return ret;
+ return ret < 0 ? ret : size;
}
static int show_xbc_kernel_cmdline(void)
@@ -423,9 +406,8 @@ static int apply_xbc(const char *path, const char *xbc_path)
char *buf, *data;
size_t total_size;
struct stat stat;
- const char *msg;
uint32_t size, csum;
- int pos, pad;
+ int pad;
int ret, fd;
ret = load_xbc_file(xbc_path, &buf);
@@ -433,9 +415,18 @@ static int apply_xbc(const char *path, const char *xbc_path)
pr_err("Failed to load %s : %d\n", xbc_path, ret);
return ret;
}
- size = strlen(buf) + 1;
+ size = ret;
+ if (size == 0 || buf[size - 1] != '\0')
+ size++;
csum = xbc_calc_checksum(buf, size);
+ /* Verify the data format */
+ ret = init_xbc_with_error(buf, size);
+ if (ret < 0) {
+ free(buf);
+ return ret;
+ }
+
/* Backup the bootconfig data */
data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1);
if (!data) {
@@ -444,15 +435,6 @@ static int apply_xbc(const char *path, const char *xbc_path)
}
memcpy(data, buf, size);
- /* Check the data format */
- ret = xbc_init(buf, size, &msg, &pos);
- if (ret < 0) {
- show_xbc_error(data, msg, pos);
- free(data);
- free(buf);
-
- return ret;
- }
printf("Apply %s to %s\n", xbc_path, path);
xbc_get_info(&ret, NULL);
printf("\tNumber of nodes: %d\n", ret);
diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh
index fc69f815ce4a..530ce7e28d63 100755
--- a/tools/bootconfig/test-bootconfig.sh
+++ b/tools/bootconfig/test-bootconfig.sh
@@ -180,6 +180,18 @@ EOF
$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE
xpass grep -q "1:1" $OUTFILE
+echo "Intermediate null character test"
+printf "key = value\n\0extra = data\n" > $TEMPCONF
+xfail $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE
+xpass grep -q "Unexpected" $OUTFILE
+
+echo "Trailing null character test"
+printf "key = value\n\0" > $TEMPCONF
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xpass grep -q "value" $OUTFILE
+
echo "=== expected failure cases ==="
for i in samples/bad-* ; do
xfail $BOOTCONF -a $i $INITRD
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: Bootconfig updates for v7.4
2026-10-22 0:14 Bootconfig updates for v7.4 Masami Hiramatsu
@ 2026-10-22 0:43 ` Masami Hiramatsu
0 siblings, 0 replies; 2+ messages in thread
From: Masami Hiramatsu @ 2026-10-22 0:43 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Linus Torvalds, Sang-Heon Jeon, Steven Rostedt, linux-kernel
Sorry, please ignore this. I missed [GIT PULL] tag. So I resent with it.
On Thu, 22 Oct 2026 09:14:10 +0900
Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
> Hi Linus,
>
> Bootconfig updates for v7.4:
>
> - bootconfig: Parser robustness and validation improvements
> . Skip printing early params to cmdline from bootconfig: Suppress
> early_param keys from /proc/cmdline and warn the user, since bootconfig
> does not invoke early_param handlers and silently ignoring them is
> misleading.
> . Reject unexpected data after null character: Detect and reject non-null
> data following an intermediate null character in the bootconfig buffer,
> preventing silently ignored configuration after an early termination.
>
> - bootconfig: Code cleanups
> . Merge _xbc_exit() into xbc_exit(): Since memblock_free() now handles
> late freeing and NULL addresses, the separate _xbc_exit() helper and
> its early argument are unnecessary. Inline it into xbc_exit().
> . Remove redundant assignment in xbc_parse_array(): The node->child = 0
> assignment after the loop duplicates what xbc_init_node() already did.
> . Skip internal tree sanity checks in kernel: Move the node index bounds
> loop from xbc_verify_tree() into a userspace-only xbc_sanity_check_tree()
> to reduce boot-time overhead, since out-of-bounds indices cannot be
> produced by malformed input.
> . Move BOOTCONFIG_FOOTER_SIZE to include/linux/bootconfig.h: Share the
> footer size constant between kernel and user-space tools, replacing the
> hardcoded (BOOTCONFIG_MAGIC_LEN + 8) expression in init/main.c.
>
> - tools/bootconfig: Tooling improvements
> . Remove unused PAGE_SIZE macro from the bootconfig tool.
> . Consolidate xbc_init() to error message wrapper: Use
> init_xbc_with_error() for all bootconfig initialization paths in the
> tool for simpler and more consistent error handling.
>
>
> Please pull the latest bootconfig-v7.4 tree, which can be found at:
>
>
> git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
> bootconfig-v7.4
>
> Tag SHA1: 8c84ad1d280719b36079cdd280da8214c3a8013d
> Head SHA1: 677f83795fdfc25ddc51b665a9111f5ff199f7ca
>
>
> Masami Hiramatsu (Google) (5):
> bootconfig: Skip printing early params to cmdline from bootconfig
> bootconfig: Reject unexpected data after null character
> tools/bootconfig: Consolidate xbc_init() to error message wrapper
> bootconfig: Skip internal tree sanity checks in kernel
> bootconfig: Move BOOTCONFIG_FOOTER_SIZE to include/linux/bootconfig.h
>
> Sang-Heon Jeon (3):
> bootconfig: merge _xbc_exit() into xbc_exit()
> bootconfig: remove redundant assignment in xbc_parse_array()
> tools/bootconfig: remove unused PAGE_SIZE macro
>
> ----
> include/linux/bootconfig.h | 21 ++++---
> init/main.c | 75 ++++++++++++++++++++++---
> lib/bootconfig.c | 84 +++++++++++++++++-----------
> tools/bootconfig/main.c | 108 +++++++++++++++---------------------
> tools/bootconfig/test-bootconfig.sh | 12 ++++
> 5 files changed, 192 insertions(+), 108 deletions(-)
> ---------------------------
> diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h
> index deda507500da..260a6f46042e 100644
> --- a/include/linux/bootconfig.h
> +++ b/include/linux/bootconfig.h
> @@ -27,6 +27,10 @@ bool __init cmdline_has_extra_options(void);
> #define BOOTCONFIG_ALIGN (1 << BOOTCONFIG_ALIGN_SHIFT)
> #define BOOTCONFIG_ALIGN_MASK (BOOTCONFIG_ALIGN - 1)
>
> +/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */
> +#define BOOTCONFIG_FOOTER_SIZE \
> + (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN)
> +
> /**
> * xbc_calc_checksum() - Calculate checksum of bootconfig
> * @data: Bootconfig data.
> @@ -266,7 +270,15 @@ int __init xbc_node_compose_key_after(struct xbc_node *root,
> struct xbc_node *node, char *buf, size_t size);
>
> /* Render key/value pairs under @root as a flat cmdline string */
> -int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root);
> +typedef bool (*xbc_cmdline_filter_fn)(struct xbc_node *node, const char *key, void *data);
> +
> +int __init xbc_snprint_cmdline_filter(char *buf, size_t size, struct xbc_node *root,
> + xbc_cmdline_filter_fn filter, void *data);
> +
> +static inline int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
> +{
> + return xbc_snprint_cmdline_filter(buf, size, root, NULL, NULL);
> +}
>
> /**
> * xbc_node_compose_key() - Compose full key string of the XBC node
> @@ -291,12 +303,7 @@ int __init xbc_init(const char *buf, size_t size, const char **emsg, int *epos);
> int __init xbc_get_info(int *node_size, size_t *data_size);
>
> /* XBC cleanup data structures */
> -void __init _xbc_exit(bool early);
> -
> -static __always_inline void xbc_exit(void)
> -{
> - _xbc_exit(false);
> -}
> +void __init xbc_exit(void);
>
> /* XBC embedded bootconfig data in kernel */
> #ifdef CONFIG_BOOT_CONFIG_EMBED
> diff --git a/init/main.c b/init/main.c
> index 16749bb7a219..861e07f6c05c 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -278,7 +278,7 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
> int i;
>
> if (!initrd_end || initrd_end < initrd_start ||
> - initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8)
> + initrd_end - initrd_start < BOOTCONFIG_FOOTER_SIZE)
> return NULL;
>
> data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
> @@ -336,9 +336,64 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
>
> #ifdef CONFIG_BOOT_CONFIG
>
> +/* Check if a parameter name matches an obs_kernel_param entry */
> +static bool __init match_obs_param(const char *param, const char *pattern)
> +{
> + size_t n = strlen(pattern);
> +
> + if (n > 0 && pattern[n - 1] == '=')
> + return parameqn(param, pattern, n - 1) && param[n - 1] == '\0';
> +
> + return parameq(param, pattern);
> +}
> +
> +/* Return true if the given param is only defined by early_param(). */
> +static bool __init is_early_only_param(const char *param)
> +{
> + const struct obs_kernel_param *p;
> + const struct kernel_param *kp;
> + bool has_early = false;
> +
> + /* If handled by a regular module_param, it is not early-only */
> + for (kp = __start___param; kp < __stop___param; kp++) {
> + if (parameq(param, kp->name))
> + return false;
> + }
> +
> + /* Check __setup / early_param table */
> + for (p = __setup_start; p < __setup_end; p++) {
> + if (match_obs_param(param, p->str)) {
> + if (!p->early)
> + return false;
> + has_early = true;
> + }
> + }
> + return has_early;
> +}
> +
> +struct xbc_filter_data {
> + bool warn;
> +};
> +
> +static bool __init xbc_kernel_param_filter(struct xbc_node *node,
> + const char *key, void *data)
> +{
> + struct xbc_filter_data *fdata = data;
> +
> + if (is_early_only_param(key)) {
> + if (fdata && fdata->warn)
> + pr_warn("bootconfig: early_param 'kernel.%s' cannot be applied from bootconfig, skipping\n",
> + key);
> + return false;
> + }
> + return true;
> +}
> +
> /* Make an extra command line under given key word */
> -static char * __init xbc_make_cmdline(const char *key)
> +static char * __init xbc_make_cmdline(const char *key, bool is_kernel)
> {
> + struct xbc_filter_data fdata = { .warn = true };
> + xbc_cmdline_filter_fn filter = is_kernel ? xbc_kernel_param_filter : NULL;
> struct xbc_node *root;
> char *new_cmdline;
> int ret, len = 0;
> @@ -347,8 +402,12 @@ static char * __init xbc_make_cmdline(const char *key)
> if (!root)
> return NULL;
>
> - /* Count required buffer size */
> - len = xbc_snprint_cmdline(NULL, 0, root);
> + /*
> + * Pass 1: Count required buffer size. Emit warnings for skipped early
> + * params in this pass so they are logged even if all parameters under
> + * @key are skipped and len becomes 0.
> + */
> + len = xbc_snprint_cmdline_filter(NULL, 0, root, filter, &fdata);
> if (len <= 0)
> return NULL;
>
> @@ -358,7 +417,9 @@ static char * __init xbc_make_cmdline(const char *key)
> return NULL;
> }
>
> - ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
> + /* Pass 2: Render into buffer with warnings suppressed */
> + fdata.warn = false;
> + ret = xbc_snprint_cmdline_filter(new_cmdline, len + 1, root, filter, &fdata);
> if (ret < 0 || ret > len) {
> pr_err("Failed to print extra kernel cmdline.\n");
> memblock_free(new_cmdline, len + 1);
> @@ -432,9 +493,9 @@ static void __init setup_boot_config(void)
> * before this series.
> */
> if (!from_embedded || !xbc_embedded_cmdline_applied())
> - extra_command_line = xbc_make_cmdline("kernel");
> + extra_command_line = xbc_make_cmdline("kernel", true);
> /* Also, "init." keys are init arguments */
> - extra_init_args = xbc_make_cmdline("init");
> + extra_init_args = xbc_make_cmdline("init", false);
> }
> return;
> }
> diff --git a/lib/bootconfig.c b/lib/bootconfig.c
> index 89c88e359179..819685d6c68d 100644
> --- a/lib/bootconfig.c
> +++ b/lib/bootconfig.c
> @@ -187,12 +187,9 @@ static inline void * __init xbc_alloc_mem(size_t size)
> return memblock_alloc(size, SMP_CACHE_BYTES);
> }
>
> -static inline void __init xbc_free_mem(void *addr, size_t size, bool early)
> +static inline void __init xbc_free_mem(void *addr, size_t size)
> {
> - if (early)
> - memblock_free(addr, size);
> - else if (addr)
> - memblock_free(addr, size);
> + memblock_free(addr, size);
> }
>
> #else /* !__KERNEL__ */
> @@ -202,7 +199,7 @@ static inline void *xbc_alloc_mem(size_t size)
> return calloc(1, size);
> }
>
> -static inline void xbc_free_mem(void *addr, size_t size, bool early)
> +static inline void xbc_free_mem(void *addr, size_t size)
> {
> free(addr);
> }
> @@ -539,18 +536,21 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
> #define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
>
> /**
> - * xbc_snprint_cmdline() - Render bootconfig keys under @root as a cmdline string
> + * xbc_snprint_cmdline_filter() - Render bootconfig keys as cmdline string
> * @buf: Destination buffer (may be NULL when @size is 0 to query the length)
> * @size: Size of @buf in bytes
> * @root: Subtree root whose key=value pairs should be rendered
> + * @filter: Filter callback (returns true to include, false to skip; may be NULL)
> + * @data: Private context passed to @filter
> *
> * Walk all key/value pairs under @root and emit them as a space-separated
> * cmdline string into @buf. Values containing whitespace are quoted with
> - * double quotes. Returns the number of bytes that would be written if @buf
> - * were large enough (matching snprintf semantics), or a negative errno on
> - * failure.
> + * double quotes. Keys for which @filter returns false are omitted.
> + * Returns the number of bytes that would be written if @buf were large enough
> + * (matching snprintf semantics), or a negative errno on failure.
> */
> -int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
> +int __init xbc_snprint_cmdline_filter(char *buf, size_t size, struct xbc_node *root,
> + xbc_cmdline_filter_fn filter, void *data)
> {
> struct xbc_node *knode, *vnode;
> const char *val, *q;
> @@ -582,6 +582,9 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
> if (ret < 0)
> return ret;
>
> + if (filter && !filter(knode, xbc_namebuf, data))
> + continue;
> +
> vnode = xbc_node_get_child(knode);
> if (!vnode) {
> ret = snprintf(buf ? buf + len : NULL, rest(len, size),
> @@ -836,7 +839,6 @@ static int __init xbc_parse_array(char **__v)
> return -ENOMEM;
> *__v = next;
> } while (c == ',');
> - node->child = 0;
>
> return c;
> }
> @@ -1003,9 +1005,30 @@ static int __init xbc_close_brace(char **k, char *n)
> return __xbc_close_brace(n - 1);
> }
>
> +#ifndef __KERNEL__
> +/* Sanity check for regression: node indices must be within bounds */
> +static int __init xbc_sanity_check_tree(void)
> +{
> + int i;
> +
> + for (i = 0; i < xbc_node_num; i++) {
> + if (xbc_nodes[i].next >= xbc_node_num) {
> + return xbc_parse_error("No closing brace",
> + xbc_node_get_data(xbc_nodes + i));
> + }
> + if (xbc_nodes[i].child >= xbc_node_num) {
> + return xbc_parse_error("Broken child node",
> + xbc_node_get_data(xbc_nodes + i));
> + }
> + }
> +
> + return 0;
> +}
> +#endif
> +
> static int __init xbc_verify_tree(void)
> {
> - int i, depth;
> + int depth;
> size_t len, wlen;
> struct xbc_node *n, *m;
>
> @@ -1022,17 +1045,6 @@ static int __init xbc_verify_tree(void)
> return -ENOENT;
> }
>
> - for (i = 0; i < xbc_node_num; i++) {
> - if (xbc_nodes[i].next >= xbc_node_num) {
> - return xbc_parse_error("No closing brace",
> - xbc_node_get_data(xbc_nodes + i));
> - }
> - if (xbc_nodes[i].child >= xbc_node_num) {
> - return xbc_parse_error("Broken child node",
> - xbc_node_get_data(xbc_nodes + i));
> - }
> - }
> -
> /* Key tree limitation check */
> n = &xbc_nodes[0];
> depth = 1;
> @@ -1119,24 +1131,30 @@ static int __init xbc_parse_tree(void)
> }
> } while (!ret);
>
> + if (!ret) {
> + while (p < xbc_data + xbc_data_size - 1 && *p == '\0')
> + p++;
> + if (p < xbc_data + xbc_data_size - 1)
> + ret = xbc_parse_error("Unexpected data after null character", p);
> + }
> +
> return ret;
> }
>
> /**
> - * _xbc_exit() - Clean up all parsed bootconfig
> - * @early: Set true if this is called before budy system is initialized.
> + * xbc_exit() - Clean up all parsed bootconfig
> *
> * This clears all data structures of parsed bootconfig on memory.
> * If you need to reuse xbc_init() with new boot config, you can
> * use this.
> */
> -void __init _xbc_exit(bool early)
> +void __init xbc_exit(void)
> {
> - xbc_free_mem(xbc_data, xbc_data_size, early);
> + xbc_free_mem(xbc_data, xbc_data_size);
> xbc_data = NULL;
> xbc_data_size = 0;
> xbc_node_num = 0;
> - xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX, early);
> + xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX);
> xbc_nodes = NULL;
> brace_index = 0;
> }
> @@ -1189,20 +1207,24 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos)
> if (!xbc_nodes) {
> if (emsg)
> *emsg = "Failed to allocate bootconfig nodes";
> - _xbc_exit(true);
> + xbc_exit();
> return -ENOMEM;
> }
>
> ret = xbc_parse_tree();
> if (!ret)
> ret = xbc_verify_tree();
> +#ifndef __KERNEL__
> + if (!ret)
> + ret = xbc_sanity_check_tree();
> +#endif
>
> if (ret < 0) {
> if (epos)
> *epos = xbc_err_pos;
> if (emsg)
> *emsg = xbc_err_msg;
> - _xbc_exit(true);
> + xbc_exit();
> } else {
> ret = xbc_node_num;
> }
> diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c
> index 17d971d47f87..56d76bdeaa09 100644
> --- a/tools/bootconfig/main.c
> +++ b/tools/bootconfig/main.c
> @@ -17,9 +17,38 @@
>
> #define pr_err(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
>
> -/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */
> -#define BOOTCONFIG_FOOTER_SIZE \
> - (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN)
> +static void show_xbc_error(const char *data, const char *msg, int pos)
> +{
> + int lin = 1, col, i;
> +
> + if (pos < 0) {
> + pr_err("Error: %s.\n", msg);
> + return;
> + }
> +
> + /* Note that pos starts from 0 but lin and col should start from 1. */
> + col = pos + 1;
> + for (i = 0; i < pos; i++) {
> + if (data[i] == '\n') {
> + lin++;
> + col = pos - i;
> + }
> + }
> + pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
> +
> +}
> +
> +static int init_xbc_with_error(char *buf, int len)
> +{
> + const char *msg;
> + int ret, pos;
> +
> + ret = xbc_init(buf, len, &msg, &pos);
> + if (ret < 0)
> + show_xbc_error(buf, msg, pos);
> +
> + return ret;
> +}
>
> static int xbc_show_value(struct xbc_node *node, bool semicolon)
> {
> @@ -134,8 +163,6 @@ static void xbc_show_list(void)
> }
> }
>
> -#define PAGE_SIZE 4096
> -
> static int load_xbc_fd(int fd, char **buf, int size)
> {
> int ret;
> @@ -197,7 +224,6 @@ static int load_xbc_from_initrd(int fd, char **buf)
> int ret;
> uint32_t size = 0, csum = 0, rcsum;
> char magic[BOOTCONFIG_MAGIC_LEN];
> - const char *msg;
>
> ret = fstat(fd, &stat);
> if (ret < 0)
> @@ -249,52 +275,9 @@ static int load_xbc_from_initrd(int fd, char **buf)
> return -EINVAL;
> }
>
> - ret = xbc_init(*buf, size, &msg, NULL);
> - /* Wrong data */
> - if (ret < 0) {
> - pr_err("parse error: %s.\n", msg);
> - return ret;
> - }
> -
> - return size;
> -}
> -
> -static void show_xbc_error(const char *data, const char *msg, int pos)
> -{
> - int lin = 1, col, i;
> -
> - if (pos < 0) {
> - pr_err("Error: %s.\n", msg);
> - return;
> - }
> -
> - /* Note that pos starts from 0 but lin and col should start from 1. */
> - col = pos + 1;
> - for (i = 0; i < pos; i++) {
> - if (data[i] == '\n') {
> - lin++;
> - col = pos - i;
> - }
> - }
> - pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
> + ret = init_xbc_with_error(*buf, size);
>
> -}
> -
> -static int init_xbc_with_error(char *buf, int len)
> -{
> - char *copy = strdup(buf);
> - const char *msg;
> - int ret, pos;
> -
> - if (!copy)
> - return -ENOMEM;
> -
> - ret = xbc_init(buf, len, &msg, &pos);
> - if (ret < 0)
> - show_xbc_error(copy, msg, pos);
> - free(copy);
> -
> - return ret;
> + return ret < 0 ? ret : size;
> }
>
> static int show_xbc_kernel_cmdline(void)
> @@ -423,9 +406,8 @@ static int apply_xbc(const char *path, const char *xbc_path)
> char *buf, *data;
> size_t total_size;
> struct stat stat;
> - const char *msg;
> uint32_t size, csum;
> - int pos, pad;
> + int pad;
> int ret, fd;
>
> ret = load_xbc_file(xbc_path, &buf);
> @@ -433,9 +415,18 @@ static int apply_xbc(const char *path, const char *xbc_path)
> pr_err("Failed to load %s : %d\n", xbc_path, ret);
> return ret;
> }
> - size = strlen(buf) + 1;
> + size = ret;
> + if (size == 0 || buf[size - 1] != '\0')
> + size++;
> csum = xbc_calc_checksum(buf, size);
>
> + /* Verify the data format */
> + ret = init_xbc_with_error(buf, size);
> + if (ret < 0) {
> + free(buf);
> + return ret;
> + }
> +
> /* Backup the bootconfig data */
> data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1);
> if (!data) {
> @@ -444,15 +435,6 @@ static int apply_xbc(const char *path, const char *xbc_path)
> }
> memcpy(data, buf, size);
>
> - /* Check the data format */
> - ret = xbc_init(buf, size, &msg, &pos);
> - if (ret < 0) {
> - show_xbc_error(data, msg, pos);
> - free(data);
> - free(buf);
> -
> - return ret;
> - }
> printf("Apply %s to %s\n", xbc_path, path);
> xbc_get_info(&ret, NULL);
> printf("\tNumber of nodes: %d\n", ret);
> diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh
> index fc69f815ce4a..530ce7e28d63 100755
> --- a/tools/bootconfig/test-bootconfig.sh
> +++ b/tools/bootconfig/test-bootconfig.sh
> @@ -180,6 +180,18 @@ EOF
> $BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE
> xpass grep -q "1:1" $OUTFILE
>
> +echo "Intermediate null character test"
> +printf "key = value\n\0extra = data\n" > $TEMPCONF
> +xfail $BOOTCONF -a $TEMPCONF $INITRD
> +$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE
> +xpass grep -q "Unexpected" $OUTFILE
> +
> +echo "Trailing null character test"
> +printf "key = value\n\0" > $TEMPCONF
> +xpass $BOOTCONF -a $TEMPCONF $INITRD
> +$BOOTCONF $INITRD > $OUTFILE
> +xpass grep -q "value" $OUTFILE
> +
> echo "=== expected failure cases ==="
> for i in samples/bad-* ; do
> xfail $BOOTCONF -a $i $INITRD
> --
> Masami Hiramatsu (Google) <mhiramat@kernel.org>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-22 0:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 0:14 Bootconfig updates for v7.4 Masami Hiramatsu
2026-10-22 0:43 ` Masami Hiramatsu
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®