β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4083

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4083 Β· 4 files
FileTypeDescriptionSize
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 m is 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.

VERDICT.md
↓ download raw

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)

  1. 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.
  2. 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).
  3. if_sis.c:1396 β€” m->m_pkthdr.len = m->m_len = total_len; unconditional on the newbuf success path; 1405 delivers to if_input.
  4. 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).
  5. 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_testable
baseline no→ patch + rebuild →patched clean

Fix validation not possible: no SiS hardware/emulation in QEMU.

Guest pciconf -l: no vendor 0x1039/0x100b devices.
per-fix-DF-4083

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.