summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-23 12:20:54 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-23 12:20:54 -1000
commit90b754d40117b2889bbe847ce7bb4dcf968e7cb8 (patch)
tree95c8c91b5a5b33cc7ed7837768fe54dbccd58339 /lib
parent3f942403bbad36a120432be69445154891b65398 (diff)
parent677f83795fdfc25ddc51b665a9111f5ff199f7ca (diff)
downloadlinux-90b754d40117b2889bbe847ce7bb4dcf968e7cb8.tar.gz
linux-90b754d40117b2889bbe847ce7bb4dcf968e7cb8.zip
Merge tag 'bootconfig-v7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull bootconfig updates from Masami Hiramatsu: "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 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 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" * tag 'bootconfig-v7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: bootconfig: Move BOOTCONFIG_FOOTER_SIZE to include/linux/bootconfig.h bootconfig: Skip internal tree sanity checks in kernel tools/bootconfig: Consolidate xbc_init() to error message wrapper bootconfig: Reject unexpected data after null character bootconfig: Skip printing early params to cmdline from bootconfig tools/bootconfig: remove unused PAGE_SIZE macro bootconfig: remove redundant assignment in xbc_parse_array() bootconfig: merge _xbc_exit() into xbc_exit()
Diffstat (limited to 'lib')
-rw-r--r--lib/bootconfig.c84
1 files changed, 53 insertions, 31 deletions
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;
}