[PATCH RFC] firmware_loader: Reject 0-size firmware in batched requests
"syzbot" <[email protected]> Mon, 3 Aug 2026 09:28:40 +0000 (UTC)
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
When multiple concurrent requests are made for the same firmware name, the
firmware loader batches them. The first request allocates a struct fw_priv
and proceeds to load the firmware (e.g., via the sysfs fallback).
Subsequent requests find the existing fw_priv and wait for the first
request to finish.
In the sysfs fallback mechanism, if user space writes 1 to the loading
attribute and then immediately writes 0 without writing any data,
fw_priv->size remains 0 and fw_priv->data remains NULL. The sysfs fallback
mechanism completes and sets the state to FW_STATUS_DONE.
The first request wakes up, explicitly checks for a 0-size firmware, and
correctly returns -ENOENT. However, the batched requests wake up from
fw_state_wait(), see the FW_STATUS_DONE state, and assume success.
_request_firmware_prepare() then blindly copies the 0 size and NULL data
pointer into the struct firmware and returns success.
Drivers receiving this invalid firmware can crash when attempting to parse
it. For example, the emi26 driver calls request_ihex_firmware(), which
passes the 0-size, NULL-data firmware to ihex_validate_fw(). Because
fw->size is 0, fw->size - sizeof(*end) underflows to a huge positive value,
causing the loop condition to evaluate to true. The loop executes and
attempts to read from the NULL pointer, resulting in a KASAN
null-ptr-deref:
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
CPU: 0 UID: 0 PID: 5720 Comm: kworker/0:3 Not tainted
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS
1.16.3-debian-1.16.3-2 04/01/2014
Workqueue: usb_hub_wq hub_event
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
Call Trace:
<TASK>
usb_probe_interface+0x653/0xc60 drivers/usb/core/driver.c:396
call_driver_probe drivers/base/dd.c:-1 [inline]
really_probe+0x254/0xae0 drivers/base/dd.c:706
To fix this, enforce the same validation rules for batched requests as for
the primary request. In _request_firmware_prepare(), after fw_state_wait()
returns successfully, explicitly check if fw_priv->size is 0. If it is,
return -ENOENT instead of blindly calling fw_set_page_data(). This properly
aborts any remaining batched requests and cleans up the state.
Fixes: 1f2b79599ee8 ("firmware loader: always let firmware_buf own the pages buffer")
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=cb67625c47fe4d6dd7c8
Link: https://syzkaller.appspot.com/ai_job?id=c8fc1a4f-643b-4169-a624-9871d2c011bd
To: "Danilo Krummrich" <[email protected]>
To: <[email protected]>
To: "Greg Kroah-Hartman" <[email protected]>
To: "Luis Chamberlain" <[email protected]>
To: "Rafael J. Wysocki" <[email protected]>
To: "Russ Weight" <[email protected]>
To: "Ming Lei" <[email protected]>
Cc: <[email protected]>
---
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index 24213a0ea..b1521a1da 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -771,6 +771,8 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
if (ret > 0) {
ret = fw_state_wait(fw_priv);
if (!ret) {
+ if (!fw_priv->size)
+ return -ENOENT;
fw_set_page_data(fw_priv, firmware);
return 0; /* assigned */
}
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].