DF-5507 / verdict.json
{ "finding_id": "DF-5507", "status": "reproduced", "reproduced": true, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED through the unmodified production amdsmb_bread: /dev/smbs SMB_BREAD passes an uninitialized kernel-stack byte as the in/out count (smb.c:317,323 \u2014 DF-5458s defect, amdsmb twin). Truth table (run.log T3): g=0/33/255 -> SMB_EINVAL (SMB_BREAD dead for 224/256 stack bytes); g in [1,32) with a healthy slave (len=32) -> rc=0, out count=32 while only g bytes were stored -> smbioctl copyouts min(rcount<=1024,32) bytes from its 1024-byte kernel-stack buf, disclosing 32-g never-written stack bytes (up to 31/call; >=254 combined with known DF-1091 hostile len). bwrite transmits garbage g as the on-wire block length (T3w). Driver-side fix validated in the same rig (run_fixed.log T3: out count == bytes stored for every g; hostile-len T4 clamped: count=32, register reads stop at 0x24, 0 stale bytes). The complete upstream fix additionally needs smb.c: `bcount = s->rcount;` before smb.c:323. Root-gated (/dev/smb 0600), hardware-gated (AMD-8111) \u2014 Medium per DF-5457/5458 sibling pricing. Distinct from excluded DF-1091/DF-2330: input vector is the caller-side uninit stack count, not the slave-controlled hw count; manifests with a perfectly well-behaved slave.", "exploit_chain": "", "evidence": "run.log T3/T3w (truth table incl. 31/27/1 stale-bytes arithmetic and transmitted_BCNT=g), run_fixed.log T3 (count==stored, 0 stale for all g; T4 hostile len clamped), build.log:1 (production-source byte identity), amdh_harness.c (shared rig, DF-5506 pack has full description), fix.diff (bread clamp hunk), VERDICT.md (distinction from DF-1091)", "kernel_refs": [ "sys/bus/smbus/amdsmb/amdsmb.c:517", "sys/bus/smbus/amdsmb/amdsmb.c:524", "sys/bus/smbus/amdsmb/amdsmb.c:533", "sys/bus/smbus/amdsmb/amdsmb.c:536", "sys/bus/smbus/amdsmb/amdsmb.c:539", "sys/bus/smbus/amdsmb/amdsmb.c:497", "sys/dev/smbus/smb/smb.c:211", "sys/dev/smbus/smb/smb.c:317", "sys/dev/smbus/smb/smb.c:323", "sys/dev/smbus/smb/smb.c:327", "sys/dev/smbus/smb/smb.c:329" ], "poc_changes": "no seed existed (pass-2 fresh finding); shared production-code KLD rig with DF-5506 (T3/T3w tests added for this finding)", "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": 660, "guest_dirty": 0, "build_cmd": "guest# cd /root/amdh && sh build.sh (asserts amdsmb.c == /usr/src production source)", "run_cmd": "guest# sh /root/amdh/run.sh (tests at MOD_LOAD; T3/T3w are this finding)", "code_hash": "b0e9c85827e67bbe351278d8ae6f4af488a5741ef1e6d5a1f1e5d8b1606777c9", "notes": "Shared rig/artifacts with DF-5506 (identical files copied into this pack). Kernel-memory write side is bounded by original *count<=32 (amdsmb.c:536-537) \u2014 disclosure is read-side only. smb.c fix (init bcount) also un-breaks SMB_BREAD on ichsmb (DF-5458) and amdsmb simultaneously.", "recommended_fix": "amdsmb.c:533-539: clamp len to 32 then to the callers capacity so *count == bytes stored (in fix.diff, validated); smb.c:323: initialize `bcount = s->rcount;` before the smbus_bread call (upstream one-liner closing the uninit input for all smbus controllers).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "Baseline: g=1 -> count=32 with 31 stale stack bytes headed for copyout; g in {0,33,255} -> EINVAL. Patched (fix.diff bread clamp): g=1 -> count=1, g=5 -> count=5, g=31 -> count=31, all with 0 stale bytes \u2014 the driver never reports more than it stored, closing the disclosure for the uninit-count vector AND the known DF-1091 hostile-len vector (fixed T4: count=32, highest register read 0x24). EINVAL for invalid g remains (correct) until smb.c initializes bcount.", "fix_evidence": "run.log vs run_fixed.log T3/T3w/T4 lines; fix.diff (amdsmb.c bread hunk); build_fixed.log" } |