[PATCH RFC] ihex: Fix integer underflow and out-of-bounds read

"syzbot" <[email protected]> Mon, 3 Aug 2026 09:08:10 +0000 (UTC)
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
When loading a 0-byte firmware, ihex_validate_fw() calculates the end
pointer by subtracting sizeof(*end) from fw->size. Since fw->size is 0,
this results in an integer underflow, making end a huge pointer far past
the end of the buffer. The validation loop then executes with a NULL rec
pointer, leading to a NULL pointer dereference when ihex_binrec_size()
attempts to read rec->len.

Oops: general protection fault, probably for non-canonical address
0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
...
RIP: 0010:ihex_binrec_size include/linux/ihex.h:26 [inline]
RIP: 0010:__ihex_next_binrec include/linux/ihex.h:35 [inline]
RIP: 0010:ihex_validate_fw include/linux/ihex.h:54 [inline]
RIP: 0010:request_ihex_firmware include/linux/ihex.h:74 [inline]
RIP: 0010:emi26_load_firmware drivers/usb/misc/emi26.c:86 [inline]
RIP: 0010:emi26_probe+0x283/0x1690 drivers/usb/misc/emi26.c:232

Additionally, if a firmware file consists only of the 6-byte EOF record,
ihex_validate_fw() successfully validates it. However, when iterating over
the records, ihex_next_binrec() blindly advances past the current record.
If the current record is the EOF record, __ihex_next_binrec() advances the
pointer past the end of the firmware buffer, and the subsequent read of
rec->len results in an out-of-bounds read.

Fix both issues by adding a size check in ihex_validate_fw() to ensure the
firmware is at least large enough to contain a single IHEX record, and by
updating ihex_next_binrec() to check the current record's length before
advancing so it returns NULL immediately when encountering the EOF record.

Fixes: bacfe09dd754 ("ihex.h: binary representation of ihex records")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=baf3cbba7dd980984f0d
Link: https://syzkaller.appspot.com/ai_job?id=a0c10e66-d30e-44f1-8ad1-c7f25ff69b04
To: <[email protected]>
To: "David Woodhouse" <[email protected]>

---
diff --git a/include/linux/ihex.h b/include/linux/ihex.h
index b824877e6..4ee4b5960 100644
--- a/include/linux/ihex.h
+++ b/include/linux/ihex.h
@@ -38,9 +38,13 @@ __ihex_next_binrec(const struct ihex_binrec *rec)
 static inline const struct ihex_binrec *
 ihex_next_binrec(const struct ihex_binrec *rec)
 {
-	rec = __ihex_next_binrec(rec);
+	const struct ihex_binrec *next;
 
-	return be16_to_cpu(rec->len) ? rec : NULL;
+	if (!be16_to_cpu(rec->len))
+		return NULL;
+
+	next = __ihex_next_binrec(rec);
+	return be16_to_cpu(next->len) ? next : NULL;
 }
 
 /* Check that ihex_next_binrec() won't take us off the end of the image... */
@@ -48,6 +52,9 @@ static inline int ihex_validate_fw(const struct firmware *fw)
 {
 	const struct ihex_binrec *end, *rec;
 
+	if (fw->size < sizeof(*end))
+		return -EINVAL;
+
 	rec = (const void *)fw->data;
 	end = (const void *)&fw->data[fw->size - sizeof(*end)];
 


base-commit: 075b74841bd0065a3bda3440873c747938e69b68
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].