sis_rxeof trusts the 12-bit DMA-written RX descriptor length (SIS_RXBYTES = (sis_ctl & 0xFFF) - 4, up to 4091) into m_len/m_pkthdr.len of a 2048-byte cluster with no clamp: up to ~2 KB kernel heap OOB read delivered to the network stack/BPF (DF-3604 length-trust family)
Summary
SIS_RXBYTES is the NIC-DMA-written sis_cmdsts length field masked to 12 bits minus CRC - range up to 4091 - assigned directly into m_len/m_pkthdr.len with no bound against MCLBYTES (2048) or the programmed SIS_RXLEN (1536). A descriptor with BUFLEN=0xFFF gives m_len=4091 on a 2048-byte cluster; stack consumers with matching in-frame ip_len read up to 2043 bytes past the cluster into adjacent kernel heap delivered to sockets/BPF. Same family as DF-3604 (bce). Lower edge (BUFLEN<4) yields negative lengths dropped by minimum-length checks. Clamp fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4083 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.9 KB | β raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| verdict.json | β | 2.3 KB | view raw | |
| manifest.json | β | 729 B | view raw |
DF-4083 β sis_rxeof trusts the 12-bit DMA-written descriptor length into
m_len of a 2048-byte cluster: up to ~2 KB heap OOB read into the network
stack (DF-3604 length-trust family, sis flavor)
File: sys/dev/netif/sis/if_sis.c (pass 2 β first pass over this file) Class: kernel info leak (kernleak) via RX descriptor length trust Hardware gate: SiS 900/7016 or NS DP83815 NIC; QEMU emulates neither.
Root cause (path:line)
Receive completion path, sis_rxeof (sys/dev/netif/sis/if_sis.c):
- 1373-1374: rxstat = cur_rx->sis_rxstat; / == sis_cmdsts, DMA-written / total_len = SIS_RXBYTES(cur_rx);
- if_sisreg.h:314,324: #define SIS_CMDSTS_BUFLEN 0x00000FFF / 12-bit length field / #define SIS_RXBYTES(x) (((x)->sis_ctl & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN) β total_len β [-4 β¦ 4091], straight from the descriptor the NIC DMA-writes.
- 1395-1397:
if (sis_newbuf(sc, idx, 0) == 0) {
m->m_pkthdr.len = m->m_len = total_len; / NO clamp /
m->m_pkthdr.rcvif = ifp;
}
The replacement buffer is an MCLBYTES (2048) cluster (m_getcl at 1296,
m_len = MCLBYTES at 1302); the completed mbuf
mis the old cluster of the same size, DMA-mapped by sis_newbuf's bus_dmamap_load_mbuf_segment (1305-1306). The descriptor is programmed with SIS_RXLEN = 1536 (if_sisreg.h:472; sis_setup_rxdesc, if_sis.c:1340) but nothing validates the completion length against either 1536 or MCLBYTES. - 1405:
ifp->if_input(ifp, m, NULL, -1);
A descriptor with BUFLEN = 0xFFF (4095) β written by buggy or malicious NIC
firmware/DMA, or any device-side length corruption β yields
m->m_len = m->m_pkthdr.len = 4091 on a 2048-byte cluster. Downstream
consumers that trust these lengths (ether_input with a matching in-frame
ip_len β€ 4091, UDP/TCP delivery, BPF taps) then read up to 2043 bytes past
the cluster β adjacent kernel heap (mbuf-cluster zone neighbors) β and the
data is delivered to sockets / BPF listeners: kernel memory disclosure.
Secondary edge: BUFLEN < 4 makes total_len negative (int) β m_len/pkthdr.len
become negative; the stack drops such frames (length checks), so the lower
edge is benign-but-sloppy.
This is exactly the class of DF-3604 (bce: l2_fhdr_pkt_len trusted into m_len past MCLBYTES; Medium/kernleak), with a 12-bit field instead of 16.
Why the driver must not trust it
The whole descriptor (sis_cmdsts) lives in coherent memory the device writes; the value is only as trustworthy as the device. The clamp costs one comparison.
Fix
if (sis_newbuf(sc, idx, 0) == 0) {
- if (total_len > MCLBYTES) { / or SIS_RXLEN /
- IFNET_STAT_INC(ifp, ierrors, 1);
- m_freem(m);
- continue; / descriptor already re-armed by newbuf /
- } m->m_pkthdr.len = m->m_len = total_len;
(and reject total_len < ETHER_HDR_LEN).
Verification status
UNTESTED β hardware-gated: QEMU has no SiS 900/7016/DP83815 model (guest pciconf shows no vendor 0x1039/0x100b devices). Source-level certainty.
DF-4083 VERDICT β sis_rxeof RX-length trust (heap OOB read)
Status: UNTESTED (hardware-gated, source-level certainty)
The QEMU guest runs neither SiS nor DP83815 hardware: pciconf -l shows no
vendor 0x1039 / 0x100b devices, and QEMU has no model for these chips, so the
RX descriptor whose sis_ctl length field must be shaped cannot be produced.
Verification on hardware would be: DMA-write one completed RX descriptor with
sis_cmdsts = PKT_OK | 0xFFF, frame bytes carrying IPv4 with ip_len = 4091
(β€ m_pkthdr.len so DFly ip_input length checks pass), then read the delivered
datagram from a bound socket (or BPF) β the tail beyond byte 2048 is adjacent
kernel heap.
Source trace (why it is real)
- if_sis.c:1373-1374 β rxstat/total_len taken from
cur_rx->sis_rxstat(= sis_cmdsts, if_sisreg.h:306), the word the NIC DMA-writes on completion. - if_sisreg.h:314/324 β length mask is 12 bits (0xFFF), minus ETHER_CRC_LEN. Range [-4, 4091]. No relation enforced to SIS_RXLEN (1536, the programmed buffer size, if_sisreg.h:472 / if_sis.c:1340) nor to MCLBYTES (2048).
- if_sis.c:1396 β
m->m_pkthdr.len = m->m_len = total_len;unconditional on the newbuf success path; 1405 delivers to if_input. - The mbuf is a 2048-byte cluster (if_sis.c:1296,1302); DMA map loaded for the same (1305-1306). Any total_len > 2048 describes more data than the buffer holds β consumers read past the cluster (mbuf-cluster zone neighbor memory) β disclosure to socket/BPF readers; also feeds m_copydata-style walkers (KASSERT 'offset > size of mbuf chain' / uipc_mbuf.c:1679 β single-mbuf chain here, so the dominant effect is the OOB read, not the panic).
- Lower edge: BUFLEN < 4 β negative total_len β negative m_len/pkthdr.len β dropped by the stack's minimum-length checks (sloppy but benign).
Family precedent: DF-3604 (bce, same trust, 16-bit field, ~63.5 KB past the cluster) rated Medium/kernleak; this one's ceiling is ~2 KB past the cluster per packet, repeatable per descriptor.
Impact ceiling
Kernel heap info leak (limited: 12-bit field β β€ 2043 bytes beyond the cluster per frame) to unprivileged readers of a socket fed by the interface, or BPF listeners; requires the device (firmware/DMA fault or hostile SR-IOV peer) to write an oversized completion length. Not remotely triggerable without the NIC's participation.
Fix
Clamp/reject before assigning lengths (see README diff) β one comparison.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
(No fix.diff for this item: documented recommendation only - see Fix above.)
Fix verification
not_testableFix validation not possible: no SiS hardware/emulation in QEMU.
Guest pciconf -l: no vendor 0x1039/0x100b devices.
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md, VERDICT.md. Key lines: if_sis.c:1374 (SIS_RXBYTES), 1395-1397 (no-clamp assignment), 1405 (if_input), 1296/1302/1305 (2048-byte cluster), if_sisreg.h:314/324 (12-bit mask), 472 (SIS_RXLEN 1536).
PoC changes
No runnable PoC: hardware-gated (no SiS emulation in QEMU). Pack documents the exact descriptor shape (sis_cmdsts = PKT_OK|0xFFF + in-frame ip_len<=4091) needed on real hardware.
Verified recommended fix
In sis_rxeof, reject/clamp total_len to [ETHER_HDR_LEN, MCLBYTES] before assigning m->m_pkthdr.len = m->m_len = total_len.
Verdict
sis_rxeof (if_sis.c:1373-1374,1396) copies SIS_RXBYTES(cur_rx) β a 12-bit DMA-written descriptor field minus 4 (if_sisreg.h:314,324), range [-4,4091] β directly into m_len/m_pkthdr.len of an MCLBYTES (2048) cluster with no clamp against MCLBYTES or the programmed SIS_RXLEN (1536). A device writing BUFLEN=0xFFF produces m_len=4091, so stack consumers read up to 2043 bytes past the cluster into adjacent kernel heap and deliver it to sockets/BPF: kernel info leak (DF-3604 bce family, sis flavor). Untested: QEMU has no SiS 900/7016/DP83815 model; guest pciconf shows no 0x1039/0x100b devices. Source-level certainty.
No comments yet.