[BUG] pegasus: RX length confusion and Pegasus-II heap corruption

From: Jurre van Bergen <hidden>
Date: 2026-09-14 19:25:43
Also in: linux-usb

Hello,

I would like to report two issues in drivers/net/usb/pegasus.c,
read_bulk_callback(). A malicious USB device that emulates as a supported
Pegasus adapter can trigger the two issues.

First issue, the driver trusts the packet length stored in data supplied 
by the USB
device. It checks the length against PEGASUS_MTU, but does not check 
that the
claimed packet is present in urb->actual_length. A short USB transfer can
therefore make skb_put() expose unwritten skb tailroom to the network stack.
The device can receive some of this kernel data through ICMP error 
responses.

Second issue, on Pegasus-II (chip 0x8513), the driver advances 
rx_skb->data by two
bytes before it rejects an oversized packet. The rejected skb is then reused
as the destination of the next 1536-byte RX URB. Repeated rejected packets
move the destination forward through the allocation. This allows 
cross-object
reads and a repeatable, device-controlled linear overwrite of 
skb_shared_info
and later heap memory. RX-error packets can keep the destination at the 
chosen
offset while writing new data.

The important code pattern is:
if (pegasus->chip == 0x8513) {
     /* Length comes from the USB device. */
     pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer) & 0x0fff;
     pegasus->rx_skb->data += 2;
}

if (pkt_len > PEGASUS_MTU)
     goto goon;                 /* skb is reused with shifted data */

skb_put(pegasus->rx_skb, pkt_len); /* no actual_length check */

goon:
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, pipe,
          pegasus->rx_skb->data, PEGASUS_MTU,
          read_bulk_callback, pegasus);
The issues were reproduced with raw_gadget and dummy_hcd using the built-in
ADM8513 ID (07a6:8513) as emulation target.

The Pegasus-II overwrite is confirmed exploitable: 
https://x.com/DrWhax/status/2098408939507351760

Possible fix directions:

- Convert the device length into an Ethernet frame length. Reject it if 
it is
   smaller than ETH_HLEN, larger than PEGASUS_MTU, or larger than the bytes
   present after the device-specific prefix and trailer. Check minimum wire
   lengths before subtraction to avoid integer underflow.
- Remove the direct rx_skb->data adjustment. After validation succeeds, use
   skb_put(), skb_pull(), and skb_trim(), or an equivalent sequence that 
keeps
   data, tail, and len consistent.
- Make every rejected-packet path leave the skb unchanged, so the next 
RX URB
   always uses the original buffer address. If this cannot be guaranteed,
   discard the skb and allocate a fresh one.
- Before each URB submission, verify that PEGASUS_MTU bytes fit between the
   exact transfer-buffer address and skb_end_pointer().
- Read the Pegasus-II length with get_unaligned_le32().

Groetjes,

Jurre van Bergen

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help