DF-2357 / verdict.json
{ "finding_id": "DF-2357", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "Primitive reproduced deterministically on the stock 6.5-DEVELOPMENT guest with a verbatim sha256-gated if_rum.c compiled into a kld module and only the USB transfer engine and node completion interposed: rum_bulk_write_callback copies 24 desc bytes plus the frame from offset 24, the bound at if_rum.c:1057 admits frames up to 2072 bytes and truncates larger ones to 2072, so frames 2057..2072 (and any truncated frame, e.g. 2346 or 3000 reduced to 2072) overwrite exactly 1..16 fully attacker-controlled bytes past the 2080-byte transfer buffer (canary bytes equal frame pattern bytes 2056..2071), and the submitted transfer length itself reaches 2096 > 2080. Exploitation ceiling is honestly capped: reach needs the Ralink USB dongle plus CAP_NET_RAW or a monitor vap (already privileged), and on the stock x86_64 allocation path the 2080-byte request lands in a 2304-byte kmalloc chunk (zoneindex rounds 2080 to 2304; the M_POWEROF2 retry gives 4096; contigmalloc gives whole pages), so the 16 overrun bytes stay inside the same chunk slack and cannot corrupt an adjacent kernel object; no panic, no leak verified, no uid=0 route on this kernel. Real but latent CWE-787 contract violation worth fixing: Medium confirmed. Fix validated A/B at module level (the stock kernel image contains zero rum symbols, the driver is module-only, so a kernel rebuild adds nothing): patched driver drops all overflow-window and oversized frames with a clean canary and error completion, while in-range frames 2048 and 2056 produce byte-identical buffer contents to the stock driver.", "exploit_chain": "", "evidence": "run.baseline.log lines len=2057/2060/2064/2072 (canary_hits 1/4/8/16, canary bytes 6f 7c 89 96 ... = frame pattern 2056..2071, submit_len EXCEEDS-BUFSIZE), len=2073 and 2346 (post_len=2072 proving truncation then 16-byte overflow), direct 3000 (clamped, 16 bytes); run.fixed.log (DROPPED for all overflow-window lengths, canary clean, tx_complete err=1) with RUMTESTHEX len=2048/2056 bit-identical to baseline; VERDICT.md carries the allocator analysis (kern_slaballoc.c:668-671, busdma_machdep.c:88,481-537)", "kernel_refs": [ "sys/bus/u4b/wlan/if_rum.c:438", "sys/bus/u4b/wlan/if_rum.c:1057", "sys/bus/u4b/wlan/if_rum.c:1060", "sys/bus/u4b/wlan/if_rum.c:1064", "sys/bus/u4b/wlan/if_rum.c:1080", "sys/bus/u4b/usb_busdma.c:132", "sys/bus/u4b/usb_busdma.c:204", "sys/bus/u4b/usb_busdma.c:486", "sys/platform/pc64/x86_64/busdma_machdep.c:481", "sys/kern/kern_slaballoc.c:668", "sys/bus/u4b/wlan/if_run.c:3091" ], "poc_changes": "Harness written from scratch (the finding had no seed PoC). Fixes vs the first draft: kmod.mk clobbers CFLAGS so -D/-I moved to COPTS; generated headers (opt_usb.h device_if.h bus_if.h usbdevs.h) added to SRCS; interposition defines moved before all declaring headers; usb_core.h/usb_busdma.h pre-included in usb_transfer.c order for full struct usb_xfer/usb_page_cache definitions; USB_ERR_OK replaced by the DragonFly name USB_ERR_NORMAL_COMPLETION; fake functions made non-static to match renamed prototypes; oerrors printf cast to int", "attempts": 5, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 1140, "guest_dirty": 1, "build_cmd": "cd /root/DF-2357 && sh build.sh", "run_cmd": "cd /root/DF-2357 && sh run.sh", "code_hash": "b2d8a864ac152f917d1230d2ab295e71cab4e13b55b0599624e2a07ec43027de", "notes": "Fix validation done at module level by explicit design: nm shows zero rum_ symbols in /boot/kernel/kernel, the driver ships only as /boot/kernel/if_rum.ko, so the patched-TU module against the running stock kernel exercises the exact fixed code; a full kernel rebuild would test nothing additional for this driver. The over-long submitted transfer length (2096 vs 2080) would additionally DMA 16 bytes of uninitialized heap slack to the device and over the air on real hardware; unverified (no Ralink dongle on the guest) and counted only as a marginal secondary effect. Guest reset (vm.sh reset with-src) performed after evidence collection", "recommended_fix": "Replace the wrong bound and truncation in rum_bulk_write_callback with a correct bound of MCLBYTES + 8 (frame must fit bufsize minus the 24-byte descriptor) and DROP oversized frames via rum_tx_free(data, 1) + goto tr_setup, matching if_run.c" } |