DF-2525 / verdict.json
{ "finding_id": "DF-2525", "status": "reproduced", "reproduced": 1, "impact": "limited_write", "confidence": "certain", "verdict": "The verbatim trm_check_eeprom default-load writes u_long (8 bytes on x86_64) per store into a schema of 4-byte NVRAMTARGETTYPE words: 16 + 2 + 12 stores starting at &NvramTarget (offset 10) span offsets 10..257 of a 128-byte NVRAMTYPE. With a failed checksum the verbatim function smashed EXACTLY 122 guard bytes past the struct end (first=128, last=249; guard values 128..383 monitored) - the exact figure in the finding - writing constants (0x77/0x07/0x0f/0x15/0) into what is really trm_eepromBuf[unit+1..] (the following adapters EEPROM image) or, for the last adapter, past the array in BSS. Control (checksum good) touches nothing. Fixed source (u_int32_t stores + 11-word zero loop - the original also overran by 2 bytes even on ILP32) A/B: zero guard bytes touched.", "exploit_chain": "attach-time constant-data corruption of adjacent NVRAM images (not attacker-valued); triggered by a bad EEPROM checksum; Low as filed.", "evidence": "run.log: smashed=122 first=128 last=249 with hex dump of the spill; control clean; fixed clean.", "kernel_refs": [ "sys/dev/disk/trm/trm.c:3304", "sys/dev/disk/trm/trm.c:3315", "sys/dev/disk/trm/trm.h:937", "sys/dev/disk/trm/trm.h:959" ], "poc_changes": "NVRAM accessors interposed to force checksum fail/succeed; guard region after the struct in one allocation.", "attempts": 1, "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": 500, "guest_dirty": 0, "build_cmd": "sh /root/rigs/dfv_trm/gen.sh && make -m /usr/src/share/mk (in dfv_trm)", "run_cmd": "kldload dfv_trm.ko; sysctl kern.dfv_trm_run=0; sysctl -n kern.dfv_trm_status; sysctl kern.dfv_trm_run=1; sysctl -n kern.dfv_trm_status", "code_hash": "4d7c3c1a587e752a269a1339473cc58bd9b400079ded62404901af7e8c7805f6", "notes": "122 bytes past the 128-byte NVRAMTYPE exactly as filed (first=128, last=249). Values written are constants (0x77/0x07/0x0f/0x15/0). NOTE: the original ILP32 code itself also overran by 2 bytes (12 zero words cover 48 bytes but only 46 remain); the fix both shrinks stores to u_int32 and the zero loop to 11 words.", "recommended_fix": "use u_int32_t stores and 11 (not 12) zero words in the EEPROM default load", "fix_status": "fixed" } |