All of lore.kernel.org
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] bootconfig: Fix integer overflow in initrd size check" failed to apply to 5.10-stable tree
@ 2026-09-16 15:15 gregkh
  2026-09-17  2:18 ` [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h Sasha Levin
  0 siblings, 1 reply; 5+ messages in thread
From: gregkh @ 2026-09-16 15:15 UTC (permalink / raw)
  To: mhiramat, ekffu200098, sashiko-bot; +Cc: stable


The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 7812d6dab0698001e50e8c2f901e17da3eb6f429
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026091618-used-flashbulb-70ef@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'

Possible dependencies:



thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 7812d6dab0698001e50e8c2f901e17da3eb6f429 Mon Sep 17 00:00:00 2001
From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
Date: Fri, 11 Sep 2026 00:15:34 +0900
Subject: [PATCH] bootconfig: Fix integer overflow in initrd size check

Sashiko reported that in get_boot_config_from_initrd(), a crafted initrd
with a huge bootconfig size (such as 0xFFFFFFFF) can cause the pointer
arithmetic:

    data = ((void *)hdr) - size;

to wrap around on 32-bit systems (or when pointer subtraction overflows).
Because data wraps around, the subsequent bounds check:

    if ((unsigned long)data < initrd_start)

evaluates to false, bypassing the check. The kernel then calls
xbc_calc_checksum(data, size), which attempts to read 4GB of memory,
hitting unmapped pages and triggering a fatal kernel page fault during
early boot. Furthermore, on 64-bit systems with an initrd > 4.29 GB, an
unbounded 32-bit size can similarly bypass the initrd_start check.

Fix this by:
1. Ensuring the initrd is at least large enough to contain the bootconfig
   footer and verifying hdr is within the initrd bounds.
2. Checking that size does not exceed XBC_DATA_MAX and does not exceed
   the available space between initrd_start and hdr before performing
   pointer subtraction.

Link: https://lore.kernel.org/all/178905333479.213925.1358412668943562406.stgit@devnote2/

Fixes: de462e5f1071 ("bootconfig: Fix to remove bootconfig data from initrd while boot")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260910010137.EE0431F000FF@smtp.kernel.org/
Assisted-by: Antigravity:gemini-3.8-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reviewed-by: Sang-Heon Jeon <ekffu200098@gmail.com>

diff --git a/init/main.c b/init/main.c
index 2613d3f9b3ce..16749bb7a219 100644
--- a/init/main.c
+++ b/init/main.c
@@ -277,7 +277,8 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
 	u8 *hdr;
 	int i;
 
-	if (!initrd_end)
+	if (!initrd_end || initrd_end < initrd_start ||
+	    initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8)
 		return NULL;
 
 	data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
@@ -294,16 +295,26 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
 
 found:
 	hdr = (u8 *)(data - 8);
+	if ((unsigned long)hdr < initrd_start)
+		return NULL;
+
 	size = get_unaligned_le32(hdr);
 	csum = get_unaligned_le32(hdr + 4);
 
-	data = ((void *)hdr) - size;
-	if ((unsigned long)data < initrd_start) {
-		pr_err("bootconfig size %d is greater than initrd size %ld\n",
+	if (size > XBC_DATA_MAX) {
+		pr_err("bootconfig size %u is greater than max size %d\n",
+			size, XBC_DATA_MAX);
+		return NULL;
+	}
+
+	if (size > ((unsigned long)hdr - initrd_start)) {
+		pr_err("bootconfig size %u is greater than initrd size %lu\n",
 			size, initrd_end - initrd_start);
 		return NULL;
 	}
 
+	data = ((void *)hdr) - size;
+
 	if (xbc_calc_checksum(data, size) != csum) {
 		pr_err("bootconfig checksum failed\n");
 		return NULL;
@@ -394,12 +405,6 @@ static void __init setup_boot_config(void)
 		return;
 	}
 
-	if (size >= XBC_DATA_MAX) {
-		pr_err("bootconfig size %ld greater than max size %d\n",
-			(long)size, XBC_DATA_MAX);
-		return;
-	}
-
 	ret = xbc_init(data, size, &msg, &pos);
 	if (ret < 0) {
 		if (pos < 0)


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h
  2026-09-16 15:15 FAILED: patch "[PATCH] bootconfig: Fix integer overflow in initrd size check" failed to apply to 5.10-stable tree gregkh
@ 2026-09-17  2:18 ` Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 2/4] ns: uniformly initialize ns_common Sasha Levin
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-17  2:18 UTC (permalink / raw)
  To: stable; +Cc: Christian Brauner, Jan Kara, Sasha Levin

From: Christian Brauner <brauner@kernel.org>

[ Upstream commit e3e1812f8e25ac277f5cc9249802365300c582e3 ]

Move the helper to ns_common.h where it belongs.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: 7812d6dab069 ("bootconfig: Fix integer overflow in initrd size check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/ns_common.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h
index 5fbc4000358f1..d2b9e0b4a928f 100644
--- a/include/linux/ns_common.h
+++ b/include/linux/ns_common.h
@@ -4,10 +4,30 @@
 
 struct proc_ns_operations;
 
+struct cgroup_namespace;
+struct ipc_namespace;
+struct mnt_namespace;
+struct net;
+struct pid_namespace;
+struct time_namespace;
+struct user_namespace;
+struct uts_namespace;
+
 struct ns_common {
 	atomic_long_t stashed;
 	const struct proc_ns_operations *ops;
 	unsigned int inum;
 };
 
+#define to_ns_common(__ns)                              \
+	_Generic((__ns),                                \
+		struct cgroup_namespace *: &(__ns)->ns, \
+		struct ipc_namespace *:    &(__ns)->ns, \
+		struct mnt_namespace *:    &(__ns)->ns, \
+		struct net *:              &(__ns)->ns, \
+		struct pid_namespace *:    &(__ns)->ns, \
+		struct time_namespace *:   &(__ns)->ns, \
+		struct user_namespace *:   &(__ns)->ns, \
+		struct uts_namespace *:    &(__ns)->ns)
+
 #endif
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5.10.y 2/4] ns: uniformly initialize ns_common
  2026-09-17  2:18 ` [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h Sasha Levin
@ 2026-09-17  2:19   ` Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 3/4] init/main: read bootconfig header with get_unaligned_le32() Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 4/4] bootconfig: Fix integer overflow in initrd size check Sasha Levin
  2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-17  2:19 UTC (permalink / raw)
  To: stable; +Cc: Christian Brauner, Jan Kara, Sasha Levin

From: Christian Brauner <brauner@kernel.org>

[ Upstream commit 660def10b01b248fd97255afacb7b0e305ac833a ]

No point in cargo-culting the same code across all the different types.
Use one common initializer.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: 7812d6dab069 ("bootconfig: Fix integer overflow in initrd size check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/proc_ns.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index 75807ecef880f..5ea4835550823 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -70,6 +70,22 @@ static inline int ns_alloc_inum(struct ns_common *ns)
 	return proc_alloc_inum(&ns->inum);
 }
 
+static inline int ns_common_init(struct ns_common *ns,
+				 const struct proc_ns_operations *ops,
+				 bool alloc_inum)
+{
+	if (alloc_inum) {
+		int ret;
+		ret = proc_alloc_inum(&ns->inum);
+		if (ret)
+			return ret;
+	}
+	refcount_set(&ns->count, 1);
+	ns->stashed = NULL;
+	ns->ops = ops;
+	return 0;
+}
+
 #define ns_free_inum(ns) proc_free_inum((ns)->inum)
 
 extern struct file *proc_ns_fget(int fd);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5.10.y 3/4] init/main: read bootconfig header with get_unaligned_le32()
  2026-09-17  2:18 ` [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 2/4] ns: uniformly initialize ns_common Sasha Levin
@ 2026-09-17  2:19   ` Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 4/4] bootconfig: Fix integer overflow in initrd size check Sasha Levin
  2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-17  2:19 UTC (permalink / raw)
  To: stable; +Cc: Sun Jian, Ingo Molnar, Thomas Gleixner, Andrew Morton,
	Sasha Levin

From: Sun Jian <sun.jian.kdev@gmail.com>

[ Upstream commit 499f86de4f8c34e19a57daf2b6f0cba848e91994 ]

get_boot_config_from_initrd() scans up to 3 bytes before initrd_end to
handle GRUB 4-byte alignment.  As a result, the bootconfig header
immediately preceding the magic may be unaligned.

Read the size and checksum fields with get_unaligned_le32() instead of
casting to u32 * and using le32_to_cpu(), avoiding potential unaligned
access and silencing sparse "cast to restricted __le32" warnings.

Sparse warnings (gcc + C=1):
  init/main.c:292:16: warning: cast to restricted __le32
  init/main.c:293:16: warning: cast to restricted __le32

No functional change intended.

Link: https://lkml.kernel.org/r/20260113101532.1630770-1-sun.jian.kdev@gmail.com
Signed-off-by: Sun Jian <sun.jian.kdev@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

Stable backport notes:
- Use <asm/unaligned.h>, the unaligned-access header provided by 5.10.
- Reuse and relocate the existing boot_config_checksum() implementation as
  xbc_calc_checksum(), and validate the checksum before trimming the initrd,
  as in 765b8552a200. No additional function is introduced.
- Adapt the existing xbc_init() and its callers to the explicit-size,
  internally owned buffer interface from bdac5c2b243f. Use the 5.10
  memblock_free(__pa(...), ...) API, handle partial allocation cleanup, and
  initialize the parser result after removing the strlen() assignment.
- Repair the inherited ns_common_init() from b033981390f7: 5.10 has no
  common count field and stashed is atomic_long_t, so initialize it with
  atomic_long_set() and leave per-namespace reference counts alone.
- Match the size-check diagnostic context so target 7812d6dab069 applies
  unchanged. Its overflow and footer-bounds checks remain in the target.

These adaptations bridge the older bootconfig implementation without
pulling in unrelated modern init headers or adding functions.

Stable-dep-of: 7812d6dab069 ("bootconfig: Fix integer overflow in initrd size check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/bootconfig.h |  2 +-
 include/linux/proc_ns.h    |  3 +-
 init/main.c                | 69 +++++++++++++++++---------------------
 lib/bootconfig.c           | 41 ++++++++++++++--------
 tools/bootconfig/main.c    |  6 ++--
 5 files changed, 62 insertions(+), 59 deletions(-)

diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h
index 39d2e2468c237..15c3328ad60cc 100644
--- a/include/linux/bootconfig.h
+++ b/include/linux/bootconfig.h
@@ -222,7 +222,7 @@ static inline int __init xbc_node_compose_key(struct xbc_node *node,
 }
 
 /* XBC node initializer */
-int __init xbc_init(char *buf, const char **emsg, int *epos);
+int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos);
 
 
 /* XBC cleanup data structures */
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index 5ea4835550823..b726eafbd2584 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -80,8 +80,7 @@ static inline int ns_common_init(struct ns_common *ns,
 		if (ret)
 			return ret;
 	}
-	refcount_set(&ns->count, 1);
-	ns->stashed = NULL;
+	atomic_long_set(&ns->stashed, 0);
 	ns->ops = ops;
 	return 0;
 }
diff --git a/init/main.c b/init/main.c
index d23d1a8d5393f..4da396cc3af71 100644
--- a/init/main.c
+++ b/init/main.c
@@ -102,6 +102,7 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
+#include <asm/unaligned.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/initcall.h>
@@ -262,11 +263,22 @@ static int __init loglevel(char *str)
 early_param("loglevel", loglevel);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum)
+static u32 __init xbc_calc_checksum(const void *data, u32 size)
+{
+	const unsigned char *p = data;
+	u32 ret = 0;
+
+	while (size--)
+		ret += *p++;
+
+	return ret;
+}
+
+static void * __init get_boot_config_from_initrd(u32 *_size)
 {
 	u32 size, csum;
 	char *data;
-	u32 *hdr;
+	u8 *hdr;
 	int i;
 
 	if (!initrd_end)
@@ -285,9 +297,9 @@ static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum)
 	return NULL;
 
 found:
-	hdr = (u32 *)(data - 8);
-	size = le32_to_cpu(hdr[0]);
-	csum = le32_to_cpu(hdr[1]);
+	hdr = (u8 *)(data - 8);
+	size = get_unaligned_le32(hdr);
+	csum = get_unaligned_le32(hdr + 4);
 
 	data = ((void *)hdr) - size;
 	if ((unsigned long)data < initrd_start) {
@@ -296,17 +308,20 @@ static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum)
 		return NULL;
 	}
 
+	if (xbc_calc_checksum(data, size) != csum) {
+		pr_err("bootconfig checksum failed\n");
+		return NULL;
+	}
+
 	/* Remove bootconfig from initramfs/initrd */
 	initrd_end = (unsigned long)data;
 	if (_size)
 		*_size = size;
-	if (_csum)
-		*_csum = csum;
 
 	return data;
 }
 #else
-static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum)
+static void * __init get_boot_config_from_initrd(u32 *_size)
 {
 	return NULL;
 }
@@ -346,16 +361,6 @@ static char * __init xbc_make_cmdline(const char *key)
 	return new_cmdline;
 }
 
-static u32 boot_config_checksum(unsigned char *p, u32 size)
-{
-	u32 ret = 0;
-
-	while (size--)
-		ret += *p++;
-
-	return ret;
-}
-
 static int __init bootconfig_params(char *param, char *val,
 				    const char *unused, void *arg)
 {
@@ -370,12 +375,12 @@ static void __init setup_boot_config(const char *cmdline)
 	static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
 	const char *msg;
 	int pos;
-	u32 size, csum;
-	char *data, *copy, *err;
+	u32 size;
+	char *data, *err;
 	int ret;
 
 	/* Cut out the bootconfig data even if we have no bootconfig option */
-	data = get_boot_config_from_initrd(&size, &csum);
+	data = get_boot_config_from_initrd(&size);
 
 	strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
 	err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL,
@@ -394,26 +399,12 @@ static void __init setup_boot_config(const char *cmdline)
 	}
 
 	if (size >= XBC_DATA_MAX) {
-		pr_err("bootconfig size %d greater than max size %d\n",
-			size, XBC_DATA_MAX);
+		pr_err("bootconfig size %ld greater than max size %d\n",
+			(long)size, XBC_DATA_MAX);
 		return;
 	}
 
-	if (boot_config_checksum((unsigned char *)data, size) != csum) {
-		pr_err("bootconfig checksum failed\n");
-		return;
-	}
-
-	copy = memblock_alloc(size + 1, SMP_CACHE_BYTES);
-	if (!copy) {
-		pr_err("Failed to allocate memory for bootconfig\n");
-		return;
-	}
-
-	memcpy(copy, data, size);
-	copy[size] = '\0';
-
-	ret = xbc_init(copy, &msg, &pos);
+	ret = xbc_init(data, size, &msg, &pos);
 	if (ret < 0) {
 		if (pos < 0)
 			pr_err("Failed to init bootconfig: %s.\n", msg);
@@ -435,7 +426,7 @@ static void __init setup_boot_config(const char *cmdline)
 static void __init setup_boot_config(const char *cmdline)
 {
 	/* Remove bootconfig data from initrd */
-	get_boot_config_from_initrd(NULL, NULL);
+	get_boot_config_from_initrd(NULL);
 }
 
 static int __init warn_bootconfig(char *str)
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index f6bede03c6926..5d2fa27de8ce6 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -814,32 +814,37 @@ static int __init xbc_verify_tree(void)
  */
 void __init xbc_destroy_all(void)
 {
+	if (xbc_data)
+		memblock_free(__pa(xbc_data), xbc_data_size);
 	xbc_data = NULL;
 	xbc_data_size = 0;
 	xbc_node_num = 0;
-	memblock_free(__pa(xbc_nodes), sizeof(struct xbc_node) * XBC_NODE_MAX);
+	if (xbc_nodes)
+		memblock_free(__pa(xbc_nodes),
+			      sizeof(struct xbc_node) * XBC_NODE_MAX);
 	xbc_nodes = NULL;
 	brace_index = 0;
 }
 
 /**
  * xbc_init() - Parse given XBC file and build XBC internal tree
- * @buf: boot config text
+ * @data: The boot config text original data
+ * @size: The size of @data
  * @emsg: A pointer of const char * to store the error message
  * @epos: A pointer of int to store the error position
  *
- * This parses the boot config text in @buf. @buf must be a
- * null terminated string and smaller than XBC_DATA_MAX.
+ * This parses the boot config text in @data. @size must not exceed
+ * XBC_DATA_MAX.
  * Return the number of stored nodes (>0) if succeeded, or -errno
  * if there is any error.
  * In error cases, @emsg will be updated with an error message and
  * @epos will be updated with the error position which is the byte offset
- * of @buf. If the error is not a parser error, @epos will be -1.
+ * of @data. If the error is not a parser error, @epos will be -1.
  */
-int __init xbc_init(char *buf, const char **emsg, int *epos)
+int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos)
 {
 	char *p, *q;
-	int ret, c;
+	int ret = 0, c;
 
 	if (epos)
 		*epos = -1;
@@ -850,27 +855,35 @@ int __init xbc_init(char *buf, const char **emsg, int *epos)
 		return -EBUSY;
 	}
 
-	ret = strlen(buf);
-	if (ret > XBC_DATA_MAX - 1 || ret == 0) {
+	if (size > XBC_DATA_MAX || size == 0) {
 		if (emsg)
-			*emsg = ret ? "Config data is too big" :
+			*emsg = size ? "Config data is too big" :
 				"Config data is empty";
 		return -ERANGE;
 	}
 
+	xbc_data = memblock_alloc(size + 1, SMP_CACHE_BYTES);
+	if (!xbc_data) {
+		if (emsg)
+			*emsg = "Failed to allocate bootconfig data";
+		return -ENOMEM;
+	}
+	memcpy(xbc_data, data, size);
+	xbc_data[size] = '\0';
+	xbc_data_size = size + 1;
+
 	xbc_nodes = memblock_alloc(sizeof(struct xbc_node) * XBC_NODE_MAX,
 				   SMP_CACHE_BYTES);
 	if (!xbc_nodes) {
 		if (emsg)
 			*emsg = "Failed to allocate bootconfig nodes";
+		xbc_destroy_all();
 		return -ENOMEM;
 	}
 	memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX);
-	xbc_data = buf;
-	xbc_data_size = ret + 1;
-	last_parent = NULL;
 
-	p = buf;
+	last_parent = NULL;
+	p = xbc_data;
 	do {
 		q = strpbrk(p, "{}=+;:\n#");
 		if (!q) {
diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c
index 387cb91862dfc..39081b2d768f1 100644
--- a/tools/bootconfig/main.c
+++ b/tools/bootconfig/main.c
@@ -214,7 +214,7 @@ static int load_xbc_from_initrd(int fd, char **buf)
 		return -EINVAL;
 	}
 
-	ret = xbc_init(*buf, &msg, NULL);
+	ret = xbc_init(*buf, size, &msg, NULL);
 	/* Wrong data */
 	if (ret < 0) {
 		pr_err("parse error: %s.\n", msg);
@@ -254,7 +254,7 @@ static int init_xbc_with_error(char *buf, int len)
 	if (!copy)
 		return -ENOMEM;
 
-	ret = xbc_init(buf, &msg, &pos);
+	ret = xbc_init(buf, len, &msg, &pos);
 	if (ret < 0)
 		show_xbc_error(copy, msg, pos);
 	free(copy);
@@ -367,7 +367,7 @@ static int apply_xbc(const char *path, const char *xbc_path)
 	memcpy(data, buf, size);
 
 	/* Check the data format */
-	ret = xbc_init(buf, &msg, &pos);
+	ret = xbc_init(buf, size, &msg, &pos);
 	if (ret < 0) {
 		show_xbc_error(data, msg, pos);
 		free(data);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5.10.y 4/4] bootconfig: Fix integer overflow in initrd size check
  2026-09-17  2:18 ` [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 2/4] ns: uniformly initialize ns_common Sasha Levin
  2026-09-17  2:19   ` [PATCH 5.10.y 3/4] init/main: read bootconfig header with get_unaligned_le32() Sasha Levin
@ 2026-09-17  2:19   ` Sasha Levin
  2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-17  2:19 UTC (permalink / raw)
  To: stable; +Cc: Masami Hiramatsu (Google), Sashiko, Sang-Heon Jeon, Sasha Levin

From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>

[ Upstream commit 7812d6dab0698001e50e8c2f901e17da3eb6f429 ]

Sashiko reported that in get_boot_config_from_initrd(), a crafted initrd
with a huge bootconfig size (such as 0xFFFFFFFF) can cause the pointer
arithmetic:

    data = ((void *)hdr) - size;

to wrap around on 32-bit systems (or when pointer subtraction overflows).
Because data wraps around, the subsequent bounds check:

    if ((unsigned long)data < initrd_start)

evaluates to false, bypassing the check. The kernel then calls
xbc_calc_checksum(data, size), which attempts to read 4GB of memory,
hitting unmapped pages and triggering a fatal kernel page fault during
early boot. Furthermore, on 64-bit systems with an initrd > 4.29 GB, an
unbounded 32-bit size can similarly bypass the initrd_start check.

Fix this by:
1. Ensuring the initrd is at least large enough to contain the bootconfig
   footer and verifying hdr is within the initrd bounds.
2. Checking that size does not exceed XBC_DATA_MAX and does not exceed
   the available space between initrd_start and hdr before performing
   pointer subtraction.

Link: https://lore.kernel.org/all/178905333479.213925.1358412668943562406.stgit@devnote2/

Fixes: de462e5f1071 ("bootconfig: Fix to remove bootconfig data from initrd while boot")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260910010137.EE0431F000FF@smtp.kernel.org/
Assisted-by: Antigravity:gemini-3.8-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reviewed-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 init/main.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/init/main.c b/init/main.c
index 4da396cc3af71..faf4eecda23e6 100644
--- a/init/main.c
+++ b/init/main.c
@@ -281,7 +281,8 @@ static void * __init get_boot_config_from_initrd(u32 *_size)
 	u8 *hdr;
 	int i;
 
-	if (!initrd_end)
+	if (!initrd_end || initrd_end < initrd_start ||
+	    initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8)
 		return NULL;
 
 	data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
@@ -298,16 +299,26 @@ static void * __init get_boot_config_from_initrd(u32 *_size)
 
 found:
 	hdr = (u8 *)(data - 8);
+	if ((unsigned long)hdr < initrd_start)
+		return NULL;
+
 	size = get_unaligned_le32(hdr);
 	csum = get_unaligned_le32(hdr + 4);
 
-	data = ((void *)hdr) - size;
-	if ((unsigned long)data < initrd_start) {
-		pr_err("bootconfig size %d is greater than initrd size %ld\n",
+	if (size > XBC_DATA_MAX) {
+		pr_err("bootconfig size %u is greater than max size %d\n",
+			size, XBC_DATA_MAX);
+		return NULL;
+	}
+
+	if (size > ((unsigned long)hdr - initrd_start)) {
+		pr_err("bootconfig size %u is greater than initrd size %lu\n",
 			size, initrd_end - initrd_start);
 		return NULL;
 	}
 
+	data = ((void *)hdr) - size;
+
 	if (xbc_calc_checksum(data, size) != csum) {
 		pr_err("bootconfig checksum failed\n");
 		return NULL;
@@ -398,12 +409,6 @@ static void __init setup_boot_config(const char *cmdline)
 		return;
 	}
 
-	if (size >= XBC_DATA_MAX) {
-		pr_err("bootconfig size %ld greater than max size %d\n",
-			(long)size, XBC_DATA_MAX);
-		return;
-	}
-
 	ret = xbc_init(data, size, &msg, &pos);
 	if (ret < 0) {
 		if (pos < 0)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-17  2:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 15:15 FAILED: patch "[PATCH] bootconfig: Fix integer overflow in initrd size check" failed to apply to 5.10-stable tree gregkh
2026-09-17  2:18 ` [PATCH 5.10.y 1/4] ns: move to_ns_common() to ns_common.h Sasha Levin
2026-09-17  2:19   ` [PATCH 5.10.y 2/4] ns: uniformly initialize ns_common Sasha Levin
2026-09-17  2:19   ` [PATCH 5.10.y 3/4] init/main: read bootconfig header with get_unaligned_le32() Sasha Levin
2026-09-17  2:19   ` [PATCH 5.10.y 4/4] bootconfig: Fix integer overflow in initrd size check Sasha Levin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.