Memory safety / Undefined behavior (NULL-pointer arithmetic)
Description
The commit fixes undefined pointer arithmetic in lib/bootconfig.c: xbc_snprint_cmdline() when the function is called with a NULL buffer and size 0. The original code computed end = buf + size and used buf in pointer arithmetic, which is undefined when buf is NULL. The patch introduces a local length accumulator (size_t len) and avoids performing pointer arithmetic on buf. It uses len to track the written length and updates snprintf calls with a conditional buf ? buf + len : NULL and rest(len, size), ultimately returning len. This prevents build-time UBSan/FORTIFY_SOURCE failures and reduces risk of memory-safety issues in edge cases where a caller queries the required length (buf=NULL, size=0). While primarily a correctness/memory-safety fix, it addresses a class of undefined behavior that could otherwise crash or destabilize builds or runs under instrumentation.
Proof of Concept
// Proof-of-concept demonstrating the problematic pattern (broken version) and why the fix is needed
// This reproduces a simplified scenario of pointer arithmetic on a potentially NULL buffer.
// Compile with -fsanitize=undefined to observe UB when buf is NULL and size is 0.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t broken_snprint(char *buf, size_t size) {
// This simulates the problematic code path: end = buf + size where buf may be NULL
char *end = buf + size; // undefined behavior if buf is NULL
size_t len = 0;
// pretend to write something, advancing len
if (size) {
len += 1; // pretend one byte written
}
// return would-be length, using the invalid end
return end - buf; // UB when buf is NULL
}
int main(void) {
// Trigger the problematic call pattern: NULL buffer, 0 size
size_t r = broken_snprint(NULL, 0);
printf("result=%zu\n", r);
return 0;
}
// Expected (post-fix) behavior: calling with NULL buf and 0 size should return 0 without performing
// any arithmetic on a NULL pointer. In practice, compile with UBSan to observe that the broken version
// exhibits undefined behavior whereas the fixed version would avoid dereferencing or arithmetic on NULL.
Commit Details
Author: Linus Torvalds
Date: 2026-07-02 00:21 UTC
Message:
Merge tag 'bootconfig-fixes-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull bootconfig fix from Masami Hiramatsu:
- bootconfig: Fix NULL-pointer arithmetic
Fix undefined pointer arithmetic in xbc_snprint_cmdline() when
probing the buffer length with NULL and size 0. Track the written
length as a size_t instead to prevent build-time UBSan/FORTIFY_SOURCE
failures.
* tag 'bootconfig-fixes-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()
Triage Assessment
Vulnerability Type: Memory Safety / Undefined Behavior
Confidence: HIGH
Reasoning:
The patch fixes undefined pointer arithmetic when handling a NULL buffer and size 0, switching to tracking written length via size_t to avoid arithmetic on NULL pointers. This prevents potential memory safety vulnerabilities (UB/UBSanFORTIFY triggers) that could lead to crashes or exploitation in edge cases.
Verification Assessment
Vulnerability Type: Memory safety / Undefined behavior (NULL-pointer arithmetic)
Confidence: HIGH
Affected Versions: <= v7.0-rc6 (pre-fix); fixed in bootconfig patch merged for 7.2-rc1
Code Diff
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index f445b7703fdd96..2ed9ee3dc81c72 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -427,10 +427,18 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
{
struct xbc_node *knode, *vnode;
- char *end = buf + size;
const char *val, *q;
+ size_t len = 0;
int ret;
+ /*
+ * Track the running written length rather than advancing @buf, so we
+ * never form "buf + size" or "buf += ret" while @buf is NULL (the
+ * size-probe call passes buf=NULL, size=0). NULL pointer arithmetic
+ * is undefined behavior and trips host UBSan / FORTIFY_SOURCE when
+ * this renderer runs at kernel build time. snprintf(NULL, 0, ...)
+ * itself is well defined and returns the would-be length.
+ */
xbc_node_for_each_key_value(root, knode, val) {
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
@@ -439,10 +447,11 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
vnode = xbc_node_get_child(knode);
if (!vnode) {
- ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s ", xbc_namebuf);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
continue;
}
xbc_array_for_each_value(vnode, val) {
@@ -452,15 +461,15 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
* whitespace.
*/
q = strpbrk(val, " \t\r\n") ? "\"" : "";
- ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ",
- xbc_namebuf, q, val, q);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s=%s%s%s ", xbc_namebuf, q, val, q);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
}
}
- return buf - (end - size);
+ return len;
}
#undef rest