From: Hyunjung Ko <hj351016@gmail.com>
To: Hans Verkuil <hverkuil@kernel.org>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>,
linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
Hyunjung Ko <hj351016@gmail.com>
Subject: [PATCH] media: gspca: etoms: bound device-provided length in sd_pkt_scan
Date: Thu, 5 Nov 2026 15:57:28 +0900 [thread overview]
Message-ID: <20261105065728.1351098-1-hj351016@gmail.com> (raw)
etoms sd_pkt_scan() is the gspca pkt_scan callback, invoked from the isoc
URB completion (fill_frame() in gspca.c) with (gspca_dev, data, len) where
data points into the URB coherent transfer buffer at this packet's slot and
len is iso_frame_desc[i].actual_length, i.e. the number of bytes the device
actually sent in that isoc packet.
The subdriver overwrites the real packet length with a value taken straight
from the first two device-supplied header bytes:
len = (int)(((data[0] & 0xc0) << 2) | data[1]); /* 0 .. 1023 */
and then hands that count to gspca_frame_add() for a header packet
(data += 30) or an inter packet (data += 8):
gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
...
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
gspca_frame_add() only bounds the *destination* frame
(image_len + len > PAGE_ALIGN(sizeimage) -> discard); it applies no bound to
the *source*, doing memcpy(image + image_len, data, len) directly. Nothing
clamps the device-declared length against the bytes actually present in the
packet slot.
The isoc transfer buffer is usb_alloc_coherent(psize * npkt) where psize is
the device's reported wMaxPacketSize and npkt defaults to 32; this driver
sets neither cam.npkt nor pkt_size, so both derive from the device. A
malicious camera can declare a small wMaxPacketSize and send a short packet
in the last slot while setting the header bytes to request len up to 1023.
gspca_frame_add() then reads up to ~1023 bytes starting at data+8 (or
data+30) -- past actual_length, past the packet slot, and past the end of
the transfer-buffer allocation -- and copies that adjacent kernel memory
into the vb2 video frame, which is handed to userspace: an out-of-bounds
read / kernel information leak reachable by plugging in a crafted USB
webcam.
A 1-byte over-read of data[1] also occurs when a 1-byte packet is delivered
(fill_frame() only drops zero-length packets).
Keep the real packet length, reject runt packets, and clamp the
device-declared length to the bytes remaining after the header offset
before passing it to gspca_frame_add().
Found by code review; not reproduced (no device/USB-redir setup on hand).
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
drivers/media/usb/gspca/etoms.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c
--- a/drivers/media/usb/gspca/etoms.c
+++ b/drivers/media/usb/gspca/etoms.c
@@ -659,24 +659,37 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
int seqframe;
+ int datalen;
+ if (len < 2) /* need the 2-byte packet header */
+ return;
seqframe = data[0] & 0x3f;
- len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+ datalen = (int) (((data[0] & 0xc0) << 2) | data[1]);
if (seqframe == 0x3f) {
gspca_dbg(gspca_dev, D_FRAM,
- "header packet found datalength %d !!\n", len);
+ "header packet found datalength %d !!\n", datalen);
+ if (len < 30)
+ return;
gspca_dbg(gspca_dev, D_FRAM, "G %d R %d G %d B %d",
data[2], data[3], data[4], data[5]);
data += 30;
- /* don't change datalength as the chips provided it */
+ len -= 30;
+ /* the chip-provided length must not exceed the packet */
+ if (datalen > len)
+ datalen = len;
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
- gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen);
return;
}
- if (len) {
+ if (datalen) {
+ if (len < 8)
+ return;
data += 8;
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+ len -= 8;
+ if (datalen > len)
+ datalen = len;
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen);
} else { /* Drop Packet */
gspca_dev->last_packet_type = DISCARD_PACKET;
}
next reply other threads:[~2026-11-05 6:57 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 6:57 Hyunjung Ko [this message]
2026-11-05 10:32 ` [PATCH v2] " hyunjungg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105065728.1351098-1-hj351016@gmail.com \
--to=hj351016@gmail.com \
--cc=hverkuil@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®