From 7eaf074e9109860bfc2f7b01958059e9f2d4a76e Mon Sep 17 00:00:00 2001 From: Josh Law Date: Thu, 19 Mar 2026 08:43:23 +0900 Subject: [PATCH 01/13] lib/bootconfig: clean up comment typos and bracing Fixes kerneldoc typos ("initiized" and "uder") and adds a missing blank line. Also fixes inconsistent if/else bracing in __xbc_add_key() and elsewhere. Link: https://lore.kernel.org/all/20260318155919.78168-2-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index e88d0221a826..874e04f9a0bd 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -79,6 +79,7 @@ static inline void xbc_free_mem(void *addr, size_t size, bool early) free(addr); } #endif + /** * xbc_get_info() - Get the information of loaded boot config * @node_size: A pointer to store the number of nodes. @@ -112,7 +113,7 @@ static int __init xbc_parse_error(const char *msg, const char *p) * xbc_root_node() - Get the root node of extended boot config * * Return the address of root node of extended boot config. If the - * extended boot config is not initiized, return NULL. + * extended boot config is not initialized, return NULL. */ struct xbc_node * __init xbc_root_node(void) { @@ -364,7 +365,7 @@ struct xbc_node * __init xbc_node_find_next_leaf(struct xbc_node *root, node = xbc_node_get_parent(node); if (node == root) return NULL; - /* User passed a node which is not uder parent */ + /* User passed a node which is not under parent */ if (WARN_ON(!node)) return NULL; } @@ -472,8 +473,9 @@ static struct xbc_node * __init __xbc_add_sibling(char *data, uint32_t flag, boo sib->next = xbc_node_index(node); } } - } else + } else { xbc_parse_error("Too many nodes", data); + } return node; } @@ -655,9 +657,9 @@ static int __init __xbc_add_key(char *k) if (unlikely(xbc_node_num == 0)) goto add_node; - if (!last_parent) /* the first level */ + if (!last_parent) { /* the first level */ node = find_match_node(xbc_nodes, k); - else { + } else { child = xbc_node_get_child(last_parent); /* Since the value node is the first child, skip it. */ if (child && xbc_node_is_value(child)) @@ -665,9 +667,9 @@ static int __init __xbc_add_key(char *k) node = find_match_node(child, k); } - if (node) + if (node) { last_parent = node; - else { + } else { add_node: node = xbc_add_child(k, XBC_KEY); if (!node) @@ -992,8 +994,9 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos) if (emsg) *emsg = xbc_err_msg; _xbc_exit(true); - } else + } else { ret = xbc_node_num; + } return ret; } From bf45f7c591939196d043e30bc5961ef30fcff52d Mon Sep 17 00:00:00 2001 From: Josh Law Date: Thu, 19 Mar 2026 08:43:23 +0900 Subject: [PATCH 02/13] lib/bootconfig: narrow flag parameter type from uint32_t to uint16_t The flag parameter in the node creation helpers only ever carries XBC_KEY (0) or XBC_VALUE (0x8000), both of which fit in uint16_t. Using uint16_t matches the width of xbc_node.data where the flag is ultimately stored. Link: https://lore.kernel.org/all/20260318155919.78168-3-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 874e04f9a0bd..ee2f072831aa 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -408,7 +408,7 @@ const char * __init xbc_node_find_next_key_value(struct xbc_node *root, /* XBC parse and tree build */ -static int __init xbc_init_node(struct xbc_node *node, char *data, uint32_t flag) +static int __init xbc_init_node(struct xbc_node *node, char *data, uint16_t flag) { unsigned long offset = data - xbc_data; @@ -422,7 +422,7 @@ static int __init xbc_init_node(struct xbc_node *node, char *data, uint32_t flag return 0; } -static struct xbc_node * __init xbc_add_node(char *data, uint32_t flag) +static struct xbc_node * __init xbc_add_node(char *data, uint16_t flag) { struct xbc_node *node; @@ -452,7 +452,7 @@ static inline __init struct xbc_node *xbc_last_child(struct xbc_node *node) return node; } -static struct xbc_node * __init __xbc_add_sibling(char *data, uint32_t flag, bool head) +static struct xbc_node * __init __xbc_add_sibling(char *data, uint16_t flag, bool head) { struct xbc_node *sib, *node = xbc_add_node(data, flag); @@ -480,17 +480,17 @@ static struct xbc_node * __init __xbc_add_sibling(char *data, uint32_t flag, boo return node; } -static inline struct xbc_node * __init xbc_add_sibling(char *data, uint32_t flag) +static inline struct xbc_node * __init xbc_add_sibling(char *data, uint16_t flag) { return __xbc_add_sibling(data, flag, false); } -static inline struct xbc_node * __init xbc_add_head_sibling(char *data, uint32_t flag) +static inline struct xbc_node * __init xbc_add_head_sibling(char *data, uint16_t flag) { return __xbc_add_sibling(data, flag, true); } -static inline __init struct xbc_node *xbc_add_child(char *data, uint32_t flag) +static inline __init struct xbc_node *xbc_add_child(char *data, uint16_t flag) { struct xbc_node *node = xbc_add_sibling(data, flag); From 1c04fa80118cc20a943b9ec5b861a824fa90db1c Mon Sep 17 00:00:00 2001 From: Josh Law Date: Thu, 19 Mar 2026 08:43:24 +0900 Subject: [PATCH 03/13] lib/bootconfig: fix off-by-one in xbc_verify_tree() next node check Valid node indices are 0 to xbc_node_num-1, so a next value equal to xbc_node_num is out of bounds. Use >= instead of > to catch this. A malformed or corrupt bootconfig could pass tree verification with an out-of-bounds next index. On subsequent tree traversal at boot time, xbc_node_get_next() would return a pointer past the allocated xbc_nodes array, causing an out-of-bounds read of kernel memory. Link: https://lore.kernel.org/all/20260318155919.78168-4-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index ee2f072831aa..885886212248 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -817,7 +817,7 @@ static int __init xbc_verify_tree(void) } for (i = 0; i < xbc_node_num; i++) { - if (xbc_nodes[i].next > xbc_node_num) { + if (xbc_nodes[i].next >= xbc_node_num) { return xbc_parse_error("No closing brace", xbc_node_get_data(xbc_nodes + i)); } From ae9bf4d3835fb1cd3f79ea74e96e6ab6cfe8f415 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Thu, 19 Mar 2026 08:43:24 +0900 Subject: [PATCH 04/13] lib/bootconfig: increment xbc_node_num after node init succeeds Move the xbc_node_num increment to after xbc_init_node() so a failed init does not leave a partially initialized node counted in the array. If xbc_init_node() fails on a data offset at the boundary of a maximum-size bootconfig, the pre-incremented count causes subsequent tree verification and traversal to consider the uninitialized node as valid, potentially leading to an out-of-bounds read or unpredictable boot behavior. Link: https://lore.kernel.org/all/20260318155919.78168-5-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 885886212248..c02b11a1b501 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -429,9 +429,10 @@ static struct xbc_node * __init xbc_add_node(char *data, uint16_t flag) if (xbc_node_num == XBC_NODE_MAX) return NULL; - node = &xbc_nodes[xbc_node_num++]; + node = &xbc_nodes[xbc_node_num]; if (xbc_init_node(node, data, flag) < 0) return NULL; + xbc_node_num++; return node; } From 73a9f74b86c6b88d1b6aec82adea56074ef2a9b9 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:11 +0000 Subject: [PATCH 05/13] lib/bootconfig: drop redundant memset of xbc_nodes memblock_alloc() already returns zeroed memory, so the explicit memset in xbc_init() is redundant. Switch the userspace xbc_alloc_mem() from malloc() to calloc() so both paths return zeroed memory, and remove the separate memset call. Link: https://lore.kernel.org/all/20260318155919.78168-6-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index c02b11a1b501..1b4900053abe 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -71,7 +71,7 @@ static inline void __init xbc_free_mem(void *addr, size_t size, bool early) static inline void *xbc_alloc_mem(size_t size) { - return malloc(size); + return calloc(1, size); } static inline void xbc_free_mem(void *addr, size_t size, bool early) @@ -983,7 +983,6 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos) _xbc_exit(true); return -ENOMEM; } - memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX); ret = xbc_parse_tree(); if (!ret) From 306c36a76da2d6d2b5e91db925d41a9a8d77dbfd Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:12 +0000 Subject: [PATCH 06/13] bootconfig: constify xbc_calc_checksum() data parameter xbc_calc_checksum() only reads the data buffer, so mark the parameter as const void * and the internal pointer as const unsigned char *. Link: https://lore.kernel.org/all/20260318155919.78168-7-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- include/linux/bootconfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index 25df9260d206..23a96c5edcf3 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -36,9 +36,9 @@ bool __init cmdline_has_extra_options(void); * The checksum will be used with the BOOTCONFIG_MAGIC and the size for * embedding the bootconfig in the initrd image. */ -static inline __init uint32_t xbc_calc_checksum(void *data, uint32_t size) +static inline __init uint32_t xbc_calc_checksum(const void *data, uint32_t size) { - unsigned char *p = data; + const unsigned char *p = data; uint32_t ret = 0; while (size--) From 2564fa0bb2dbee126cac03c9d916e6c6a7910f31 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:13 +0000 Subject: [PATCH 07/13] lib/bootconfig: replace linux/kernel.h with specific includes linux/kernel.h is a legacy catch-all header. Replace it with the specific headers actually needed: linux/cache.h for SMP_CACHE_BYTES, linux/compiler.h for unlikely(), and linux/sprintf.h for snprintf(). Link: https://lore.kernel.org/all/20260318155919.78168-8-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 1b4900053abe..0663b74ad131 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -17,7 +17,9 @@ #include #include #include -#include +#include +#include +#include #include #include From 909bb3a6c53faf86e96694ed09e7f32cad11ba2e Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:14 +0000 Subject: [PATCH 08/13] lib/bootconfig: validate child node index in xbc_verify_tree() xbc_verify_tree() validates that each node's next index is within bounds, but does not check the child index. Add the same bounds check for the child field. Without this check, a corrupt bootconfig that passes next-index validation could still trigger an out-of-bounds memory access via an invalid child index when xbc_node_get_child() is called during tree traversal at boot time. Link: https://lore.kernel.org/all/20260318155919.78168-9-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 0663b74ad131..8c50e942d747 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -824,6 +824,10 @@ static int __init xbc_verify_tree(void) 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 */ From 8f3e79397a980512c2329b3445ebe7258e2d3f01 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:15 +0000 Subject: [PATCH 09/13] lib/bootconfig: fix signed comparison in xbc_node_get_data() lib/bootconfig.c:188:28: warning: comparison of integer expressions of different signedness: 'int' and 'size_t' [-Wsign-compare] The local variable 'offset' is declared as int, but xbc_data_size is size_t. Change the type to size_t to match and eliminate the warning. Link: https://lore.kernel.org/all/20260318155919.78168-10-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 8c50e942d747..94ae6662531d 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -183,7 +183,7 @@ struct xbc_node * __init xbc_node_get_next(struct xbc_node *node) */ const char * __init xbc_node_get_data(struct xbc_node *node) { - int offset = node->data & ~XBC_VALUE; + size_t offset = node->data & ~XBC_VALUE; if (WARN_ON(offset >= xbc_data_size)) return NULL; From 68f479de0e013d0c27432240f35bf2a3cc3260f6 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:16 +0000 Subject: [PATCH 10/13] lib/bootconfig: use size_t for strlen result in xbc_node_match_prefix() lib/bootconfig.c:198:19: warning: conversion from 'size_t' to 'int' may change value [-Wconversion] lib/bootconfig.c:200:33: warning: conversion to '__kernel_size_t' from 'int' may change the sign of the result [-Wsign-conversion] strlen() returns size_t but the result was stored in an int. The value is then passed back to strncmp() which expects size_t, causing a second sign-conversion warning on the round-trip. Use size_t throughout to match the API types. Link: https://lore.kernel.org/all/20260318155919.78168-11-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 94ae6662531d..9f059bb68e41 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -195,7 +195,7 @@ static bool __init xbc_node_match_prefix(struct xbc_node *node, const char **prefix) { const char *p = xbc_node_get_data(node); - int len = strlen(p); + size_t len = strlen(p); if (strncmp(*prefix, p, len)) return false; From 0f2199904188abd5477a6517a9ce525bdc2dc01d Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:17 +0000 Subject: [PATCH 11/13] lib/bootconfig: use signed type for offset in xbc_init_node() lib/bootconfig.c:415:32: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion] Pointer subtraction yields ptrdiff_t (signed), which was stored in unsigned long. The original unsigned type implicitly caught a negative offset (data < xbc_data) because the wrapped value would exceed XBC_DATA_MAX. Make this intent explicit by using a signed long and adding an offset < 0 check to the WARN_ON condition. Link: https://lore.kernel.org/all/20260318155919.78168-12-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 9f059bb68e41..1f84748607b4 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -412,9 +412,9 @@ const char * __init xbc_node_find_next_key_value(struct xbc_node *root, static int __init xbc_init_node(struct xbc_node *node, char *data, uint16_t flag) { - unsigned long offset = data - xbc_data; + long offset = data - xbc_data; - if (WARN_ON(offset >= XBC_DATA_MAX)) + if (WARN_ON(offset < 0 || offset >= XBC_DATA_MAX)) return -EINVAL; node->data = (uint16_t)offset | flag; From 05213e4b10b9bd2e121d3e73428404b4f920dd9a Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:18 +0000 Subject: [PATCH 12/13] lib/bootconfig: use size_t for key length tracking in xbc_verify_tree() lib/bootconfig.c:839:24: warning: conversion from 'size_t' to 'int' may change value [-Wconversion] lib/bootconfig.c:860:32: warning: conversion from 'size_t' to 'int' may change value [-Wconversion] lib/bootconfig.c:860:29: warning: conversion to 'size_t' from 'int' may change the sign of the result [-Wsign-conversion] The key length variables len and wlen accumulate strlen() results but were declared as int, causing truncation and sign-conversion warnings. Change both to size_t to match the strlen() return type and avoid mixed-sign arithmetic. Link: https://lore.kernel.org/all/20260318155919.78168-13-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- lib/bootconfig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 1f84748607b4..343aa9629464 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -803,7 +803,8 @@ static int __init xbc_close_brace(char **k, char *n) static int __init xbc_verify_tree(void) { - int i, depth, len, wlen; + int i, depth; + size_t len, wlen; struct xbc_node *n, *m; /* Brace closing */ From 6eb255d019b810614c5cbd99b9ef281b7b9361e3 Mon Sep 17 00:00:00 2001 From: Josh Law Date: Wed, 18 Mar 2026 15:59:19 +0000 Subject: [PATCH 13/13] lib/bootconfig: change xbc_node_index() return type to uint16_t lib/bootconfig.c:136:21: warning: conversion from 'long int' to 'int' may change value [-Wconversion] lib/bootconfig.c:308:33: warning: conversion from 'int' to 'uint16_t' may change value [-Wconversion] lib/bootconfig.c:467:37: warning: conversion from 'int' to 'uint16_t' may change value [-Wconversion] lib/bootconfig.c:469:40: warning: conversion from 'int' to 'uint16_t' may change value [-Wconversion] lib/bootconfig.c:472:54: warning: conversion from 'int' to 'uint16_t' may change value [-Wconversion] lib/bootconfig.c:476:45: warning: conversion from 'int' to 'uint16_t' may change value [-Wconversion] xbc_node_index() returns the position of a node in the xbc_nodes array, which has at most XBC_NODE_MAX (8192) entries, well within uint16_t range. Every caller stores the result in a uint16_t field (node->parent, node->child, node->next, or the keys[] array in compose_key_after), so the int return type causes narrowing warnings at all six call sites. Change the return type to uint16_t and add an explicit cast on the pointer subtraction to match the storage width and eliminate the warnings. Link: https://lore.kernel.org/all/20260318155919.78168-14-objecting@objecting.org/ Signed-off-by: Josh Law Signed-off-by: Masami Hiramatsu (Google) --- include/linux/bootconfig.h | 2 +- lib/bootconfig.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index 23a96c5edcf3..692a5acc2ffc 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -66,7 +66,7 @@ struct xbc_node { /* Node tree access raw APIs */ struct xbc_node * __init xbc_root_node(void); -int __init xbc_node_index(struct xbc_node *node); +uint16_t __init xbc_node_index(struct xbc_node *node); struct xbc_node * __init xbc_node_get_parent(struct xbc_node *node); struct xbc_node * __init xbc_node_get_child(struct xbc_node *node); struct xbc_node * __init xbc_node_get_next(struct xbc_node *node); diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 343aa9629464..01966ab9a8b5 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -131,9 +131,9 @@ struct xbc_node * __init xbc_root_node(void) * * Return the index number of @node in XBC node list. */ -int __init xbc_node_index(struct xbc_node *node) +uint16_t __init xbc_node_index(struct xbc_node *node) { - return node - &xbc_nodes[0]; + return (uint16_t)(node - &xbc_nodes[0]); } /**