DF-2931 / verdict.json
{ "finding_id": "DF-2931", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED end-to-end as unprivileged uid 1001: uuidgen(2) v1 UUIDs on the stock vtnet guest carry node 01:00:00:00:00:00, which is the 6 bytes at first_ether_softc+offsetof(struct arpcom,ac_enaddr)=sc+928 (vtnet_vlan_shadow[100..101]) with the multicast bit ORed โ NOT the interface MAC (52:54:00:12:34:56). if_getanyethermac (sys/net/if.c:3033) type-confuses if_softc with struct arpcom*; the offset is valid only for arpcom-first softcs, which vtnet/ena/oce violate, so driver-internal kernel memory (or, for a sub-928-byte softc, adjacent heap) is disclosed to any local user, jail included. KLD module uuidoff.ko proves the address arithmetic (sizeof(ifnet)=928=offsetof(ac_enaddr), sizeof(vtnet_softc)=1040) and the counter-control: for arpcom-first tap0 the same read returns its exact MAC 00:bd:e8:3f:01:00 (that MAC branch is DF-2932).", "exploit_chain": "", "evidence": [ "run.first.log โ uid 1001: 4ร v1 UUIDs, node 01:00:00:00:00:00, decoded timestamp == wall clock", "run.determinism.log โ node constant across 3 runs (fixed memory read, not read_random)", "module.log โ in-kernel proof: bytes at vtnet_softc+928 = 00:00:00:00:00:00 vs real MAC 52:54:00:12:34:56", "module.tap.log โ conforming tap0: bytes at sc+928 == exact MAC 00:bd:e8:3f:01:00 (both branches in one dump)", "VERDICT.md โ full narrative incl. run.vlan.log negative mutation attempt (VLAN filter not negotiated by QEMU)" ], "kernel_refs": [ "sys/kern/kern_uuid.c:88", "sys/kern/kern_uuid.c:90", "sys/net/if.c:3033", "sys/net/if_arp.h:117", "sys/net/if_var.h:153", "sys/dev/virtual/virtio/net/if_vtnetvar.h:57", "sys/dev/virtual/amazon/ena/ena.h:315", "sys/dev/netif/oce/oce_if.h:797" ], "poc_changes": "No orchestrator seed existed (new pass-2 finding); trigger written from scratch: direct syscall(392) since libc uuidgen(3) wrapper availability was uncertain; added RFC4122 v1 timestamp decoding to simultaneously demonstrate the wall-clock disclosure; structural proof module uuidoff.ko written and iterated 4 compile rounds (device_if.h/bus_if.h generation, if_media.h/ifq_var.h/sys/bus.h includes).", "attempts": 4, "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": 480, "guest_dirty": 0, "build_cmd": "cc -O2 -o /tmp/uuidleak /tmp/uuidleak.c ; (root) cd /tmp/uuidoffmod && make", "run_cmd": "/tmp/uuidleak (as uid 1001); kldload /tmp/uuidoffmod/uuidoff.ko && dmesg | tail", "code_hash": "3da1904abf6ab697031ccb4a7b40e69c4f2100f0f04147c98d6434ee2032bd72", "notes": "Read-only disclosure primitive (fixed offset, no attacker-controlled index) โ no uid=0 route exists for this class; primary objective (2) satisfied: leak manifests, ceiling = 6 bytes of driver-softc kernel memory per call, unlimited rate, jail-reachable (sys_uuidgen has no prison check). OOB variant (softc < 928 bytes) is speculative for current in-tree violators (vtnet=1040, ena/oce larger); wrong-field leak is certain and live. Side effect: all vtnet VMs share node 01:00:00:00:00:00, voiding v1 cross-host uniqueness. Guest state reverted after run (vlan/tap destroyed, module unloaded; if_vlan.ko/if_tap.ko remain autoloaded, /tmp artifacts remain โ no kernel-state dirt).", "recommended_fix": "if_getanyethermac: copy the MAC from the link-level sockaddr (bcopy(LLADDR(sdl), node, minlen)) instead of the arpcom type-confusion cast on if_softc.", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "3-line fix.diff authored and verified git-apply-clean against sys/net/if.c; kernel rebuild validation skipped per contract (mandatory only for memory-corruption findings; this is leak-class) to keep the single-tenant guest clean.", "fix_evidence": "findings/poc/DF-2931/fix.diff (git apply --check: clean)" } |