Unchecked rxcd->len vs cluster size yields mbuf OOB read (guest kernel heap info leak) on RX
Summary
vmxnet3_rxq_eof(): length=rxcd->len (14-bit 0-16383) written directly to m->m_len/m_pkthdr.len at :2266/:2300 without checking vs cluster size. HEAD descriptors backed by MCLBYTES(2048)-ETHER_ALIGN(2)=2046, BODY by MJUMPAGESIZE(4096). len=8192 on HEAD -> m_len exceeds cluster -> if_input reads 6KB+ past cluster into adjacent kernel heap -> info leak to guest sockets. Malicious hypervisor injects crafted RX completion. Fix: clamp length to cluster size based on btype.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1214 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full narrative + path:line trace | 3.7 KB | β raw |
| README.md | readme | reproduce / preconditions | 1.0 KB | β raw |
| fix.diff | suggested-fix | clamp rxcd->len to cluster size based on btype | 1.1 KB | view raw |
| build.sh | build-log | nativekernel build validation | 318 B | view raw |
| run.sh | run-log | no runtime trigger; static trace | 147 B | view raw |
| env.txt | environment | guest uname, PCI devices, GENERIC config | 587 B | view raw |
| build.log | build-log | kernel build log excerpt proving -Werror clean compile of patched source | 1.1 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1214 β vmxnet3 RX length unchecked vs cluster size
Reproduce
Not runnable on the audit guest β no vmxnet3 NIC is attached (the guest uses
virtio-net). The verification is a static source trace + a compiling
fix.diff; see VERDICT.md.
To validate the fix compiles, after applying fix.diff to /usr/src:
cd /usr/src
make -j6 nativekernel KERNCONF=X86_64_GENERIC
Bug location
sys/dev/virtual/vmware/vmxnet3/if_vmx.c:2216 β length = rxcd->len
(hypervisor-supplied, 14-bit) is written into m->m_len / m->m_pkthdr.len
at :2266 (HEAD, MCLBYTES-2 max) and :2300 (BODY, MJUMPAGESIZE max) with no
clamp. An oversized length makes if_input() read past the cluster into
kernel heap β guest info leak / corruption.
Trigger preconditions (NOT met on this guest)
- A vmxnet3 NIC (VMware) that emits an RX completion with
lenexceeding the backing cluster size β i.e. a malicious or buggy hypervisor.
Files
VERDICT.md,fix.diff,env.txt,build.log(kernel-build excerpt).
DF-1214 β vmxnet3 RX length unchecked vs cluster size (OOB read / heap info leak)
Verdict
INCONCLUSIVE (not_testable on this guest) β bug confirmed in source; runtime
not triggerable on this guest (no vmxnet3 NIC). Fix authored, applied, and
compiled clean as part of a single-fix nativekernel build.
Finding summary
vmxnet3_rxq_eof() (sys/dev/virtual/vmware/vmxnet3/if_vmx.c) writes
length = rxcd->len (a 14-bit field, 0β16383, supplied by the hypervisor)
directly into m->m_len / m->m_pkthdr.len at :2266 (HEAD) and :2300 (BODY)
without checking it against the backing cluster size. HEAD descriptors are
backed by an MCLBYTES (2048) cluster with ETHER_ALIGN (2) bytes consumed
by m_adj() in vmxnet3_newbuf() (only MCLBYTES - ETHER_ALIGN = 2046 bytes
are usable). BODY descriptors are backed by MJUMPAGESIZE (4096).
A malicious or buggy hypervisor that injects an RX completion with len larger
than the cluster (e.g. len=8192 on a HEAD descriptor) makes if_input()
later read past the cluster into adjacent kernel heap and deliver those bytes
to a guest socket β a guest-kernel heap information leak. The guest has no way
to validate rxcd->len independently; the host is trusted today.
Source confirmation (audited tree)
- if_vmx.c:2000β2005 β cluster sizing in
vmxnet3_newbuf(): HEAD=MCLBYTES, BODY=MJUMPAGESIZE. - if_vmx.c:2014β2018 β HEAD cluster has
ETHER_ALIGN(2) consumed bym_adj(). - if_vmx.c:2216 β
length = rxcd->len;β hypervisor-supplied, no clamp. - if_vmx.c:2221 β
rxd = &rxr->vxrxr_rxd[idx];βrxd->btypeavailable, tells us HEAD vs BODY. - if_vmx.c:2266 β
m->m_pkthdr.len = m->m_len = length;β HEAD path, no clamp. - if_vmx.c:2300 β
m->m_len = length;β BODY path, no clamp. - No bounds check anywhere between
length = rxcd->lenand the assignment tom_len.
Why not runtime-reproduced on this guest
The QEMU/KVM guest uses a virtio-net NIC (chip=0x10001af4,
vendor='Red Hat, Inc.'). There is no vmxnet3 device attached, so the
vmx driver's attach() never runs, no vmxnet3_softc / RX ring is created,
and vmxnet3_rxq_eof() is unreachable at runtime on this guest. The driver
is statically compiled into GENERIC (device vmx), and
vmxnet3_rxq_eof_discard.isra.8 is present as a symbol in /boot/kernel/kernel,
but there is no live softc.
Triggering the bug requires a vmxnet3 device that emits RX completions with
len exceeding the backing cluster size β i.e. a malicious or buggy VMware
hypervisor. Not exercisable on the audit guest.
Fix (fix.diff)
Clamp length to the backing cluster size based on rxd->btype immediately
after it is read from the descriptor, before it reaches m_len:
length = rxcd->len;
/*
* rxcd->len is 14-bit hypervisor-supplied... clamp to the backing
* cluster so a malicious/buggy host cannot make if_input() walk
* past the cluster into adjacent kernel heap.
*/
if (rxd->btype == VMXNET3_BTYPE_HEAD) {
if (length > MCLBYTES - ETHER_ALIGN)
length = MCLBYTES - ETHER_ALIGN;
} else if (length > MJUMPAGESIZE)
length = MJUMPAGESIZE;
The clamp affects only the over-sized case; well-formed packets are unchanged.
Fix validation
git apply --check -p1β clean.- Applied to in-guest
/usr/src, built as part of a single combinedmake -j6 nativekernel(with DF-1212 and DF-1223) β compiled clean,NK_DONE rc=0. fix_status: not_testableβ no vmxnet3 hardware on this guest.
Run / reproduce
Not runnable on this guest. On a VMware host with a malicious hypervisor (or a custom vmxnet3 emulation that issues oversized RX completions), the bug would manifest as guest-kernel heap bytes delivered to a receiving socket.
Fix verification
not_testablecompile validated
kernel/module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. vmxnet3 rxcd->len no clamp -> m_len past cluster -> heap OOB. vmx in GENERIC, no vmxnet3 NIC.
No comments yet.