u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4
@ 2026-09-09 19:20 Sriram Sriram
  2026-09-09 19:20 ` [PATCH 1/4] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Sriram Sriram @ 2026-09-09 19:20 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Simon Glass, Drew Kluemke,
	Daniel Munic, Sriram Sriram

This series collects four independent robustness fixes to network, boot
image and filesystem code that handle attacker-influenced or on-disk
input. Each was found by auditing length handling around memcpy(),
integer arithmetic on packet/image data, and loop-counter widths.

  1. net: nfs: the NFS client copies received UDP payloads into a
     stack-allocated struct rpc_t with memcpy() using the wire length
     without checking it against the destination size, allowing a
     malicious NFS server to overflow the stack buffer. Add a bounds
     check at each copy site.

  2. boot: image-fit: the decompression path computes the output buffer
     size as 'len * 20', which can wrap on 32/64-bit ulong for a large
     image and cause a heap buffer overflow. Reject sizes that would
     overflow before the multiplication.

  3. net: tftp: the OACK option parser uses strcasecmp() on packet data
     that may not be NUL-terminated within the received length, causing
     an out-of-bounds read. Use a bounded strncasecmp() plus an explicit
     terminator check.

  4. fs: ext4: ext4fs_update() walks all block groups with a signed
     16-bit loop counter while fs->no_blkgrp is a uint32_t. A filesystem
     with more than 32767 block groups overflows the counter (undefined
     behaviour) and the bitmap write-back loops fail to terminate
     correctly. Widen the counter to u32.

The fixes are independent and can be applied in any order. Built for
sandbox (net/tftp.o, boot/image-fit.o, fs/ext4/ext4_write.o, and
net/nfs-common.o with CONFIG_CMD_NFS=y) and checked with
scripts/checkpatch.pl.

Daniel Munic (1):
  fs: ext4: widen ext4fs_update() block-group loop counter

Drew Kluemke (3):
  net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt
  boot: image-fit: add overflow guard for FIT decompression buffer
  net: tftp: use bounded string compare for OACK option parsing

 boot/image-fit.c     | 10 +++++++++-
 fs/ext4/ext4_write.c |  2 +-
 net/nfs-common.c     | 10 ++++++++++
 net/tftp.c           | 13 +++++++++----
 4 files changed, 29 insertions(+), 6 deletions(-)

-- 
2.49.0


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

* [PATCH 1/4] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt
  2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
@ 2026-09-09 19:20 ` Sriram Sriram
  2026-09-09 19:20 ` [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer Sriram Sriram
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Sriram Sriram @ 2026-09-09 19:20 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Simon Glass, Drew Kluemke,
	Daniel Munic, Sriram Sriram

From: Drew Kluemke <ankluemk@microsoft.com>

Multiple NFS reply handlers (rpc_lookup_reply, nfs_mount_reply,
nfs_umountall_reply, nfs_lookup_reply, nfs_readlink_reply) copy network
data into a stack-allocated struct rpc_t without verifying that the UDP
payload length fits within the buffer. A malicious or malformed NFS
server response with len > sizeof(rpc_pkt) overwrites the stack frame.

Add a bounds check before each memcpy to drop oversized packets.

Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
 net/nfs-common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/net/nfs-common.c b/net/nfs-common.c
index 637fcfd9bb8..226e3fe5798 100644
--- a/net/nfs-common.c
+++ b/net/nfs-common.c
@@ -503,6 +503,8 @@ static int rpc_lookup_reply(int prog, uchar *pkt, unsigned int len)
 {
 	struct rpc_t rpc_pkt;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -532,6 +534,8 @@ static int nfs_mount_reply(uchar *pkt, unsigned int len)
 	struct rpc_t rpc_pkt;
 	int ret;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -561,6 +565,8 @@ static int nfs_umountall_reply(uchar *pkt, unsigned int len)
 {
 	struct rpc_t rpc_pkt;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -584,6 +590,8 @@ static int nfs_lookup_reply(uchar *pkt, unsigned int len)
 	struct rpc_t rpc_pkt;
 	int ret;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -645,6 +653,8 @@ static int nfs_readlink_reply(uchar *pkt, unsigned int len)
 	int rlen;
 	int nfsv3_data_offset = 0;
 
+	if (len > sizeof(rpc_pkt))
+		return -NFS_RPC_DROP;
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
-- 
2.49.0


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

* [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer
  2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
  2026-09-09 19:20 ` [PATCH 1/4] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
@ 2026-09-09 19:20 ` Sriram Sriram
  2026-09-10 19:09   ` Tom Rini
  2026-09-09 19:20 ` [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing Sriram Sriram
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Sriram Sriram @ 2026-09-09 19:20 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Simon Glass, Drew Kluemke,
	Daniel Munic, Sriram Sriram

From: Drew Kluemke <ankluemk@microsoft.com>

Add an overflow check before the 'len * 20' multiplication used to
compute the maximum decompression buffer size. On platforms where len
exceeds ULONG_MAX / 20 the multiplication wraps to a small value,
leading malloc to allocate a tiny buffer while decompression writes the
full stream -- a heap buffer overflow.

Guard against this by returning -ENOEXEC when len exceeds the safe
threshold.

Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
 boot/image-fit.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/boot/image-fit.c b/boot/image-fit.c
index 26e9323da06..9770435f939 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -2355,9 +2355,17 @@ int fit_image_load(struct bootm_headers *images, ulong addr,
 	    !(image_type == IH_TYPE_KERNEL ||
 	      image_type == IH_TYPE_KERNEL_NOLOAD ||
 	      image_type == IH_TYPE_RAMDISK)) {
-		ulong max_decomp_len = len * 20;
+		ulong max_decomp_len;
 
 		log_debug("decompressing image\n");
+
+		if (len > ULONG_MAX / 20) {
+			printf("Error: %s image too large for decompression (0x%lx)\n",
+			       prop_name, len);
+			return -ENOEXEC;
+		}
+		max_decomp_len = len * 20;
+
 		if (load == data) {
 			loadbuf = aligned_alloc(8, max_decomp_len);
 			load = map_to_sysmem(loadbuf);
-- 
2.49.0


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

* [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing
  2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
  2026-09-09 19:20 ` [PATCH 1/4] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
  2026-09-09 19:20 ` [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer Sriram Sriram
@ 2026-09-09 19:20 ` Sriram Sriram
  2026-09-10 19:25   ` Tom Rini
  2026-09-09 19:20 ` [PATCH 4/4] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
  2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
  4 siblings, 1 reply; 14+ messages in thread
From: Sriram Sriram @ 2026-09-09 19:20 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Simon Glass, Drew Kluemke,
	Daniel Munic, Sriram Sriram

From: Drew Kluemke <ankluemk@microsoft.com>

The TFTP OACK handler matches option names in the received packet with
strcasecmp(), which scans until a NUL byte. A malformed or truncated
OACK packet may not contain a NUL within the received length, causing
an out-of-bounds read past the packet buffer.

Replace each strcasecmp() with a strncasecmp() bounded to the option
name length plus an explicit check that the name is NUL-terminated at
the expected position. For the "windowsize" option, whose name and
value extend beyond the loop's "i + 8 < len" guard, add an explicit
"i + 11 < len" bound before the comparison.

Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
 net/tftp.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/tftp.c b/net/tftp.c
index beb9d08f5a2..35693e2a93e 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -544,7 +544,8 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		 * something like "len-8" may give a *huge* number
 		 */
 		for (i = 0; i+8 < len; i++) {
-			if (strcasecmp((char *)pkt + i, "blksize") == 0) {
+			if (!strncasecmp((char *)pkt + i, "blksize", 7) &&
+			    pkt[i + 7] == '\0') {
 				tftp_block_size = (unsigned short)
 					dectoul((char *)pkt + i + 8, NULL);
 				debug("Blocksize oack: %s, %d\n",
@@ -555,7 +556,8 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 					tftp_state = STATE_INVALID_OPTION;
 				}
 			}
-			if (strcasecmp((char *)pkt + i, "timeout") == 0) {
+			if (!strncasecmp((char *)pkt + i, "timeout", 7) &&
+			    pkt[i + 7] == '\0') {
 				timeout_val_rcvd = (unsigned short)
 					dectoul((char *)pkt + i + 8, NULL);
 				debug("Timeout oack: %s, %d\n",
@@ -567,14 +569,17 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 				}
 			}
 #ifdef CONFIG_TFTP_TSIZE
-			if (strcasecmp((char *)pkt + i, "tsize") == 0) {
+			if (!strncasecmp((char *)pkt + i, "tsize", 5) &&
+			    pkt[i + 5] == '\0') {
 				tftp_tsize = dectoul((char *)pkt + i + 6,
 						     NULL);
 				debug("size = %s, %u\n",
 				      (char *)pkt + i + 6, tftp_tsize);
 			}
 #endif
-			if (strcasecmp((char *)pkt + i,  "windowsize") == 0) {
+			if (i + 11 < len &&
+			    !strncasecmp((char *)pkt + i, "windowsize", 10) &&
+			    pkt[i + 10] == '\0') {
 				tftp_windowsize =
 					dectoul((char *)pkt + i + 11, NULL);
 				debug("windowsize = %s, %d\n",
-- 
2.49.0


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

* [PATCH 4/4] fs: ext4: widen ext4fs_update() block-group loop counter
  2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
                   ` (2 preceding siblings ...)
  2026-09-09 19:20 ` [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing Sriram Sriram
@ 2026-09-09 19:20 ` Sriram Sriram
  2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
  4 siblings, 0 replies; 14+ messages in thread
From: Sriram Sriram @ 2026-09-09 19:20 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Simon Glass, Drew Kluemke,
	Daniel Munic, Sriram Sriram

From: Daniel Munic <v-dmunic@microsoft.com>

ext4fs_update() iterates over all block groups with a signed 16-bit
loop counter:

	short i;
	...
	for (i = 0; i < fs->no_blkgrp; i++)

fs->no_blkgrp is a uint32_t. On a filesystem with more than 32767
block groups the counter cannot represent every index: incrementing
past SHRT_MAX is signed overflow (undefined behaviour) and the
comparison against the unsigned no_blkgrp never terminates correctly,
so the bitmap/group-descriptor write-back loops misbehave. The mixed
signed/unsigned comparison is also flagged by static analysis.

Use u32 for the loop counter, matching the width of no_blkgrp.

Signed-off-by: Daniel Munic <v-dmunic@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
 fs/ext4/ext4_write.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index 1abedcede72..2fba2197c19 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -67,7 +67,7 @@ static inline void ext4fs_bg_free_blocks_inc
 
 static void ext4fs_update(void)
 {
-	short i;
+	u32 i;
 	ext4fs_update_journal();
 	struct ext_filesystem *fs = get_fs();
 	struct ext2_block_group *bgd = NULL;
-- 
2.49.0


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

* Re: [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer
  2026-09-09 19:20 ` [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer Sriram Sriram
@ 2026-09-10 19:09   ` Tom Rini
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Rini @ 2026-09-10 19:09 UTC (permalink / raw)
  To: Sriram Sriram
  Cc: u-boot, Jerome Forissier, Simon Glass, Drew Kluemke, Daniel Munic

[-- Attachment #1: Type: text/plain, Size: 595 bytes --]

On Wed, Sep 09, 2026 at 12:20:14PM -0700, Sriram Sriram wrote:

> From: Drew Kluemke <ankluemk@microsoft.com>
> 
> Add an overflow check before the 'len * 20' multiplication used to
> compute the maximum decompression buffer size. On platforms where len
> exceeds ULONG_MAX / 20 the multiplication wraps to a small value,
> leading malloc to allocate a tiny buffer while decompression writes the
> full stream -- a heap buffer overflow.

OK, so lets assume an overflow, or just an invalid max_decomp_len,
shouldn't image_decomp handle this case and fail and we catch it?

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing
  2026-09-09 19:20 ` [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing Sriram Sriram
@ 2026-09-10 19:25   ` Tom Rini
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Rini @ 2026-09-10 19:25 UTC (permalink / raw)
  To: Sriram Sriram
  Cc: u-boot, Jerome Forissier, Simon Glass, Drew Kluemke, Daniel Munic

[-- Attachment #1: Type: text/plain, Size: 1227 bytes --]

On Wed, Sep 09, 2026 at 12:20:15PM -0700, Sriram Sriram wrote:

> From: Drew Kluemke <ankluemk@microsoft.com>
> 
> The TFTP OACK handler matches option names in the received packet with
> strcasecmp(), which scans until a NUL byte. A malformed or truncated
> OACK packet may not contain a NUL within the received length, causing
> an out-of-bounds read past the packet buffer.
> 
> Replace each strcasecmp() with a strncasecmp() bounded to the option
> name length plus an explicit check that the name is NUL-terminated at
> the expected position. For the "windowsize" option, whose name and
> value extend beyond the loop's "i + 8 < len" guard, add an explicit
> "i + 11 < len" bound before the comparison.
> 
> Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
> Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
> ---
>  net/tftp.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)

Does the spec/RFC ensure that we're being given a NULL terminated string
here? It certainly makes sense to be using strncasecmp here, but since
we're a size constrained bootloader, we do need to find the right
balance between defense-in-depth and potential exposure.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4
  2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
                   ` (3 preceding siblings ...)
  2026-09-09 19:20 ` [PATCH 4/4] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
@ 2026-09-15 20:52 ` Sriram Sriram
  2026-09-15 20:52   ` [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
                     ` (2 more replies)
  4 siblings, 3 replies; 14+ messages in thread
From: Sriram Sriram @ 2026-09-15 20:52 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Drew Kluemke, Daniel Munic,
	Sriram Sriram

Three independent hardening fixes found by internal static analysis and
code review. They do not depend on each other.

Changes in v2:
 - Dropped "boot: image-fit: add overflow guard for FIT decompression
   buffer" (2/4 in v1). As Tom pointed out, max_decomp_len is used both
   as the allocation size and as the unc_len bound handed to
   image_decomp(), so a wrapped multiply cannot leave the bound larger
   than the buffer, and image_decomp() already fails cleanly on a bound
   that is too small. The claim in that commit message was wrong, so the
   patch is withdrawn rather than reworded.
 - net: tftp: replaced the four bounded strncasecmp() comparisons with a
   single check that the packet ends in a NUL, per Tom's review. It is
   smaller (+16 bytes of .text on am335x_evm_defconfig instead of +24)
   and it also covers the dectoul() calls, which v1 left unbounded.
   Retitled to match.
 - Rebased onto current master (a44f46af0aa).
 - No change to the NFS and ext4 patches.

Daniel Munic (1):
  fs: ext4: widen ext4fs_update() block-group loop counter

Drew Kluemke (2):
  net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt
  net: tftp: verify the OACK packet is NUL terminated

 fs/ext4/ext4_write.c |  2 +-
 net/nfs-common.c     | 10 ++++++++++
 net/tftp.c           |  7 +++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

-- 
2.49.0


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

* [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt
  2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
@ 2026-09-15 20:52   ` Sriram Sriram
  2026-09-17  9:03     ` Jerome Forissier
  2026-09-15 20:52   ` [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated Sriram Sriram
  2026-09-15 20:52   ` [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
  2 siblings, 1 reply; 14+ messages in thread
From: Sriram Sriram @ 2026-09-15 20:52 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Drew Kluemke, Daniel Munic,
	Sriram Sriram

From: Drew Kluemke <ankluemk@microsoft.com>

Multiple NFS reply handlers (rpc_lookup_reply, nfs_mount_reply,
nfs_umountall_reply, nfs_lookup_reply, nfs_readlink_reply) copy network
data into a stack-allocated struct rpc_t without verifying that the UDP
payload length fits within the buffer. A malicious or malformed NFS
server response with len > sizeof(rpc_pkt) overwrites the stack frame.

Add a bounds check before each memcpy to drop oversized packets.

Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
Changes in v2:
 - No change, rebased onto current master.

 net/nfs-common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/net/nfs-common.c b/net/nfs-common.c
index 637fcfd9bb8..226e3fe5798 100644
--- a/net/nfs-common.c
+++ b/net/nfs-common.c
@@ -503,6 +503,8 @@ static int rpc_lookup_reply(int prog, uchar *pkt, unsigned int len)
 {
 	struct rpc_t rpc_pkt;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -532,6 +534,8 @@ static int nfs_mount_reply(uchar *pkt, unsigned int len)
 	struct rpc_t rpc_pkt;
 	int ret;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -561,6 +565,8 @@ static int nfs_umountall_reply(uchar *pkt, unsigned int len)
 {
 	struct rpc_t rpc_pkt;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -584,6 +590,8 @@ static int nfs_lookup_reply(uchar *pkt, unsigned int len)
 	struct rpc_t rpc_pkt;
 	int ret;
 
+	if (len > sizeof(rpc_pkt.u.data))
+		return -NFS_RPC_DROP;
 	memcpy(&rpc_pkt.u.data[0], pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
@@ -645,6 +653,8 @@ static int nfs_readlink_reply(uchar *pkt, unsigned int len)
 	int rlen;
 	int nfsv3_data_offset = 0;
 
+	if (len > sizeof(rpc_pkt))
+		return -NFS_RPC_DROP;
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
 	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
-- 
2.49.0


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

* [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated
  2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
  2026-09-15 20:52   ` [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
@ 2026-09-15 20:52   ` Sriram Sriram
  2026-09-17  8:51     ` Jerome Forissier
  2026-09-15 20:52   ` [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
  2 siblings, 1 reply; 14+ messages in thread
From: Sriram Sriram @ 2026-09-15 20:52 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Drew Kluemke, Daniel Munic,
	Sriram Sriram

From: Drew Kluemke <ankluemk@microsoft.com>

The OACK handler matches option names with strcasecmp() and parses the
values with dectoul(). Both scan until a NUL byte, so a malformed or
truncated OACK that contains no NUL within the received length makes
them read past the end of the packet buffer.

RFC 2347 formats an OACK as a sequence of NUL terminated netascii
strings, so the last byte of a well-formed packet is always a NUL.
Check for it once on entry and drop the packet if it is missing, which
keeps every strcasecmp() and dectoul() below in bounds without having to
bound each one individually.

Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
Changes in v2:
 - Replaced the four bounded strncasecmp() comparisons with a single
   check that the packet ends in a NUL, per Tom's review. RFC 2347
   guarantees the trailing NUL, so one test covers every strcasecmp()
   and, unlike v1, the dectoul() calls as well.
 - Smaller: +16 bytes of .text on am335x_evm_defconfig, against +24 for
   v1 (net/tftp.o 3222 unpatched, 3246 in v1, 3238 here).
 - Retitled from "net: tftp: use bounded string compare for OACK option
   parsing" to match the new approach.

 net/tftp.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/tftp.c b/net/tftp.c
index beb9d08f5a2..73b31b8357d 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -528,6 +528,13 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 #endif
 
 	case TFTP_OACK:
+		/*
+		 * RFC 2347 makes every option name and value a NUL terminated
+		 * string, so a well-formed OACK always ends in a NUL. Checking
+		 * that once keeps the option parsing below in bounds.
+		 */
+		if (!len || pkt[len - 1] != '\0')
+			return;
 		debug("Got OACK: ");
 		for (i = 0; i < len; i++) {
 			if (pkt[i] == '\0')
-- 
2.49.0


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

* [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter
  2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
  2026-09-15 20:52   ` [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
  2026-09-15 20:52   ` [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated Sriram Sriram
@ 2026-09-15 20:52   ` Sriram Sriram
  2026-09-15 21:23     ` Tony Dinh
  2 siblings, 1 reply; 14+ messages in thread
From: Sriram Sriram @ 2026-09-15 20:52 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jerome Forissier, Drew Kluemke, Daniel Munic,
	Sriram Sriram

From: Daniel Munic <v-dmunic@microsoft.com>

ext4fs_update() iterates over all block groups with a signed 16-bit
loop counter:

	short i;
	...
	for (i = 0; i < fs->no_blkgrp; i++)

fs->no_blkgrp is a uint32_t. On a filesystem with more than 32767
block groups the counter cannot represent every index: incrementing
past SHRT_MAX is signed overflow (undefined behaviour) and the
comparison against the unsigned no_blkgrp never terminates correctly,
so the bitmap/group-descriptor write-back loops misbehave. The mixed
signed/unsigned comparison is also flagged by static analysis.

Use u32 for the loop counter, matching the width of no_blkgrp.

Signed-off-by: Daniel Munic <v-dmunic@microsoft.com>
Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
---
Changes in v2:
 - No change, rebased onto current master.

 fs/ext4/ext4_write.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index 1abedcede72..2fba2197c19 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -67,7 +67,7 @@ static inline void ext4fs_bg_free_blocks_inc
 
 static void ext4fs_update(void)
 {
-	short i;
+	u32 i;
 	ext4fs_update_journal();
 	struct ext_filesystem *fs = get_fs();
 	struct ext2_block_group *bgd = NULL;
-- 
2.49.0


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

* Re: [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter
  2026-09-15 20:52   ` [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
@ 2026-09-15 21:23     ` Tony Dinh
  0 siblings, 0 replies; 14+ messages in thread
From: Tony Dinh @ 2026-09-15 21:23 UTC (permalink / raw)
  To: Sriram Sriram
  Cc: u-boot, Tom Rini, Jerome Forissier, Drew Kluemke, Daniel Munic

Hi Sriram and Daniel,

On Tue, Sep 15, 2026 at 1:52 PM Sriram Sriram
<sriramsriram@linux.microsoft.com> wrote:
>
> From: Daniel Munic <v-dmunic@microsoft.com>
>
> ext4fs_update() iterates over all block groups with a signed 16-bit
> loop counter:
>
>         short i;
>         ...
>         for (i = 0; i < fs->no_blkgrp; i++)
>
> fs->no_blkgrp is a uint32_t. On a filesystem with more than 32767
> block groups the counter cannot represent every index: incrementing
> past SHRT_MAX is signed overflow (undefined behaviour) and the
> comparison against the unsigned no_blkgrp never terminates correctly,
> so the bitmap/group-descriptor write-back loops misbehave. The mixed
> signed/unsigned comparison is also flagged by static analysis.
>
> Use u32 for the loop counter, matching the width of no_blkgrp.
>
> Signed-off-by: Daniel Munic <v-dmunic@microsoft.com>
> Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
Reviewed-by: Tony Dinh <mibodhi@gmail.com>

BTW, since you are testing this ext4_write, it might be worthwhile to
see this commit:
https://github.com/u-boot/u-boot/commit/53cc4332b3b37218a7cdab8bdb953da57eec2668

Thanks,
Tony

> ---
> Changes in v2:
>  - No change, rebased onto current master.
>
>  fs/ext4/ext4_write.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
> index 1abedcede72..2fba2197c19 100644
> --- a/fs/ext4/ext4_write.c
> +++ b/fs/ext4/ext4_write.c
> @@ -67,7 +67,7 @@ static inline void ext4fs_bg_free_blocks_inc
>
>  static void ext4fs_update(void)
>  {
> -       short i;
> +       u32 i;
>         ext4fs_update_journal();
>         struct ext_filesystem *fs = get_fs();
>         struct ext2_block_group *bgd = NULL;
> --
> 2.49.0
>

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

* Re: [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated
  2026-09-15 20:52   ` [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated Sriram Sriram
@ 2026-09-17  8:51     ` Jerome Forissier
  0 siblings, 0 replies; 14+ messages in thread
From: Jerome Forissier @ 2026-09-17  8:51 UTC (permalink / raw)
  To: Sriram Sriram, u-boot; +Cc: Tom Rini, Drew Kluemke, Daniel Munic, nd

On 15/09/2026 22:52, Sriram Sriram wrote:
> From: Drew Kluemke <ankluemk@microsoft.com>
> 
> The OACK handler matches option names with strcasecmp() and parses the
> values with dectoul(). Both scan until a NUL byte, so a malformed or
> truncated OACK that contains no NUL within the received length makes
> them read past the end of the packet buffer.
> 
> RFC 2347 formats an OACK as a sequence of NUL terminated netascii
> strings, so the last byte of a well-formed packet is always a NUL.
> Check for it once on entry and drop the packet if it is missing, which
> keeps every strcasecmp() and dectoul() below in bounds without having to
> bound each one individually.
> 
> Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
> Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
> ---
> Changes in v2:
>  - Replaced the four bounded strncasecmp() comparisons with a single
>    check that the packet ends in a NUL, per Tom's review. RFC 2347
>    guarantees the trailing NUL, so one test covers every strcasecmp()
>    and, unlike v1, the dectoul() calls as well.
>  - Smaller: +16 bytes of .text on am335x_evm_defconfig, against +24 for
>    v1 (net/tftp.o 3222 unpatched, 3246 in v1, 3238 here).
>  - Retitled from "net: tftp: use bounded string compare for OACK option
>    parsing" to match the new approach.
> 
>  net/tftp.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/net/tftp.c b/net/tftp.c
> index beb9d08f5a2..73b31b8357d 100644
> --- a/net/tftp.c
> +++ b/net/tftp.c
> @@ -528,6 +528,13 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
>  #endif
>  
>  	case TFTP_OACK:
> +		/*
> +		 * RFC 2347 makes every option name and value a NUL terminated
> +		 * string, so a well-formed OACK always ends in a NUL. Checking
> +		 * that once keeps the option parsing below in bounds.
> +		 */
> +		if (!len || pkt[len - 1] != '\0')
> +			return;
>  		debug("Got OACK: ");
>  		for (i = 0; i < len; i++) {
>  			if (pkt[i] == '\0')

Reviewed-by: Jerome Forissier <jerome.forissier@arm.com>

Thanks,
-- 
Jerome

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

* Re: [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt
  2026-09-15 20:52   ` [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
@ 2026-09-17  9:03     ` Jerome Forissier
  0 siblings, 0 replies; 14+ messages in thread
From: Jerome Forissier @ 2026-09-17  9:03 UTC (permalink / raw)
  To: Sriram Sriram, u-boot; +Cc: Tom Rini, Drew Kluemke, Daniel Munic, nd

On 15/09/2026 22:52, Sriram Sriram wrote:
> From: Drew Kluemke <ankluemk@microsoft.com>
> 
> Multiple NFS reply handlers (rpc_lookup_reply, nfs_mount_reply,
> nfs_umountall_reply, nfs_lookup_reply, nfs_readlink_reply) copy network
> data into a stack-allocated struct rpc_t without verifying that the UDP
> payload length fits within the buffer. A malicious or malformed NFS
> server response with len > sizeof(rpc_pkt) overwrites the stack frame.
> 
> Add a bounds check before each memcpy to drop oversized packets.
> 
> Signed-off-by: Drew Kluemke <ankluemk@microsoft.com>
> Signed-off-by: Sriram Sriram <sriramsriram@linux.microsoft.com>
> ---
> Changes in v2:
>  - No change, rebased onto current master.
> 
>  net/nfs-common.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/net/nfs-common.c b/net/nfs-common.c
> index 637fcfd9bb8..226e3fe5798 100644
> --- a/net/nfs-common.c
> +++ b/net/nfs-common.c
> @@ -503,6 +503,8 @@ static int rpc_lookup_reply(int prog, uchar *pkt, unsigned int len)
>  {
>  	struct rpc_t rpc_pkt;
>  
> +	if (len > sizeof(rpc_pkt.u.data))
> +		return -NFS_RPC_DROP;
>  	memcpy(&rpc_pkt.u.data[0], pkt, len);
>  
>  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
> @@ -532,6 +534,8 @@ static int nfs_mount_reply(uchar *pkt, unsigned int len)
>  	struct rpc_t rpc_pkt;
>  	int ret;
>  
> +	if (len > sizeof(rpc_pkt.u.data))
> +		return -NFS_RPC_DROP;
>  	memcpy(&rpc_pkt.u.data[0], pkt, len);
>  
>  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
> @@ -561,6 +565,8 @@ static int nfs_umountall_reply(uchar *pkt, unsigned int len)
>  {
>  	struct rpc_t rpc_pkt;
>  
> +	if (len > sizeof(rpc_pkt.u.data))
> +		return -NFS_RPC_DROP;
>  	memcpy(&rpc_pkt.u.data[0], pkt, len);
>  
>  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
> @@ -584,6 +590,8 @@ static int nfs_lookup_reply(uchar *pkt, unsigned int len)
>  	struct rpc_t rpc_pkt;
>  	int ret;
>  
> +	if (len > sizeof(rpc_pkt.u.data))
> +		return -NFS_RPC_DROP;
>  	memcpy(&rpc_pkt.u.data[0], pkt, len);
>  
>  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
> @@ -645,6 +653,8 @@ static int nfs_readlink_reply(uchar *pkt, unsigned int len)
>  	int rlen;
>  	int nfsv3_data_offset = 0;
>  
> +	if (len > sizeof(rpc_pkt))
> +		return -NFS_RPC_DROP;
>  	memcpy((unsigned char *)&rpc_pkt, pkt, len);
>  
>  	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)

Reviewed-by: Jerome Forissier <jerome.forissier@arm.com>

Thanks,
-- 
Jerome

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

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

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 19:20 [PATCH 0/4] Bounds/overflow hardening in NFS, FIT, TFTP and ext4 Sriram Sriram
2026-09-09 19:20 ` [PATCH 1/4] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
2026-09-09 19:20 ` [PATCH 2/4] boot: image-fit: add overflow guard for FIT decompression buffer Sriram Sriram
2026-09-10 19:09   ` Tom Rini
2026-09-09 19:20 ` [PATCH 3/4] net: tftp: use bounded string compare for OACK option parsing Sriram Sriram
2026-09-10 19:25   ` Tom Rini
2026-09-09 19:20 ` [PATCH 4/4] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
2026-09-15 20:52 ` [PATCH v2 0/3] Bounds hardening in NFS, TFTP and ext4 Sriram Sriram
2026-09-15 20:52   ` [PATCH v2 1/3] net: nfs: add bounds checks on memcpy into stack-allocated rpc_pkt Sriram Sriram
2026-09-17  9:03     ` Jerome Forissier
2026-09-15 20:52   ` [PATCH v2 2/3] net: tftp: verify the OACK packet is NUL terminated Sriram Sriram
2026-09-17  8:51     ` Jerome Forissier
2026-09-15 20:52   ` [PATCH v2 3/3] fs: ext4: widen ext4fs_update() block-group loop counter Sriram Sriram
2026-09-15 21:23     ` Tony Dinh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).