[PATCH] media: as102: bound firmware hex-line parsing by buffer and data sizes
From: Shengzhuo Wei
Date: Wed Aug 26 2026 - 17:21:05 EST
parse_hex_line() walks the Intel HEX firmware image two characters at a
time until the next '\n', writing every decoded byte past the sixth pair
into fw_pkt->raw.data[], a 58-byte array inside a 64-byte heap object.
Nothing bounds the line length: a firmware file with a hex line longer
than 64 data bytes writes past the end of the kmalloc-64 object, byte by
byte, with fully controlled contents. A file without a trailing newline
additionally makes the walk run past the end of the firmware buffer
itself. A malformed or replaced firmware file can thus corrupt adjacent
heap memory during device probe.
Bound the walk by the remaining firmware size and reject lines whose
payload does not fit in data[]. Verified with a KASAN reproducer of the
loop: the overflow disappears and the oversized line is rejected with
-EFAULT.
Fixes: 41b44e041811 ("[media] staging: as102: Initial import from Abilis")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Shengzhuo Wei <me@xxxxxxxx>
Assisted-by: GLM:5.3
---
parse_hex_line() has no bound on the hex-line length it walks in the
firmware image: every decoded byte pair past the sixth is written into
fw_pkt->raw.data[], a 58-byte array in a 64-byte heap object. An
oversized line (or a firmware file with no trailing newline) writes
past the object / reads past the firmware buffer during probe.
Verified with a KASAN reproducer of the loop (write of size 1,
slab-out-of-bounds on kmalloc-64); silenced by the fix.
---
drivers/media/usb/as102/as102_fw.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c
index d2d432789f55..0cba1ac7fb05 100644
--- a/drivers/media/usb/as102/as102_fw.c
+++ b/drivers/media/usb/as102/as102_fw.c
@@ -37,20 +37,28 @@ static unsigned char atohx(unsigned char *dst, char *src)
/*
* Parse INTEL HEX firmware file to extract address and data.
*/
-static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
- unsigned char *data, int *dataLength,
- unsigned char *addr_has_changed) {
+static int parse_hex_line(unsigned char *fw_data, size_t fw_size,
+ unsigned char *addr, unsigned char *data,
+ size_t data_size, int *dataLength,
+ unsigned char *addr_has_changed)
+{
int count = 0;
unsigned char *src, dst;
- if (*fw_data++ != ':') {
+ if (fw_size < 1 || *fw_data++ != ':') {
pr_err("invalid firmware file\n");
return -EFAULT;
}
+ fw_size--;
/* locate end of line */
for (src = fw_data; *src != '\n'; src += 2) {
+ if (src + 1 >= fw_data + fw_size ||
+ count >= 4 + (int)data_size) {
+ pr_err("invalid firmware file\n");
+ return -EFAULT;
+ }
atohx(&dst, src);
/* parse line to split addr / data */
switch (count) {
@@ -107,8 +115,9 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
/* parse intel hex line */
read_bytes = parse_hex_line(
(u8 *) (firmware->data + total_read_bytes),
+ firmware->size - total_read_bytes,
fw_pkt->raw.address,
- fw_pkt->raw.data,
+ fw_pkt->raw.data, sizeof(fw_pkt->raw.data),
&data_len,
&addr_has_changed);
---
base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
change-id: 20260827-as102-fw-overflow-4c75d973083a
Best regards,
--
Shengzhuo Wei <me@xxxxxxxx>