DF-4810 / verdict.json
{ "finding_id": "DF-4810", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Latent-hazard (Info) finding, not guest-verified because it is unreachable as-is: the AHCI command-table stride ATA_AHCI_CT_SIZE=256 (ata-all.h:239) disagrees with sizeof(struct ata_ahci_cmd_tab)=1152 (ata-all.h:249-255, __packed: 128-byte header + 64 PRDs x 16). All table placements and the hardware-visible cmd_table_phys (ata-ahci.c:254-255, 286-287) use the wrong stride and are held in-bounds only by the hardcoded tag=0 (ata-ahci.c:250, 343) within the 8192-byte work area (MAXWSPCSZ, ata-dma.c:55-56, 130-145). tag>=1 aliases live tables; tag>=28 writes prd_tab past the end of the bus_dmamem_allocd work area and programs the OOB physical address into the AHCI command list. Would become memory corruption the moment NCQ/per-tag dispatch is added. Also: ata_ahci_dmasetprd KASSERTs nsegs<=64 only AFTER the write loop (ata-ahci.c:538-544) and the true bound rests solely on max_iosize=63*PAGE_SIZE == exactly 64 page-spans == prd_tab[64] (ata-ahci.c:558) with the dma tag itself allowing 256 segments (ata-dma.c:99,112).", "exploit_chain": "", "evidence": "findings/poc/DF-4810/VERDICT.md (arithmetic proof); findings/poc/DF-4810/fix.diff (constant fix + _Static_assert + KASSERT reorder)", "kernel_refs": [ "sys/dev/disk/nata/ata-all.h:239", "sys/dev/disk/nata/ata-all.h:249", "sys/dev/disk/nata/ata-all.h:253", "sys/dev/disk/nata/chipsets/ata-ahci.c:250", "sys/dev/disk/nata/chipsets/ata-ahci.c:254", "sys/dev/disk/nata/chipsets/ata-ahci.c:286", "sys/dev/disk/nata/chipsets/ata-ahci.c:343", "sys/dev/disk/nata/chipsets/ata-ahci.c:538", "sys/dev/disk/nata/chipsets/ata-ahci.c:544", "sys/dev/disk/nata/chipsets/ata-ahci.c:558", "sys/dev/disk/nata/ata-dma.c:55", "sys/dev/disk/nata/ata-dma.c:130" ], "poc_changes": "not applicable (no seed PoC; finding produced by pass-2 static analysis)", "attempts": 0, "guest_uname": "", "runtime_sec": 0, "guest_dirty": 0, "fix_status": "not_applicable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff corrects ATA_AHCI_CT_SIZE to 1152, adds a _Static_assert tying the constant to the struct, and moves the dmasetprd KASSERT before the write loop; runtime-neutral today (only tag 0 used, CT_OFFSET+0*CT_SIZE unchanged); not build-validated on the guest because no code path can exercise tag!=0", "fix_evidence": "findings/poc/DF-4810/fix.diff", "notes": "Phase V skipped per contract: Info/hardening, no runnable PoC possible (tag hardcoded 0). QEMU guest not used for this finding.", "recommended_fix": "Set ATA_AHCI_CT_SIZE=1152 with _Static_assert(ATA_AHCI_CT_SIZE == sizeof(struct ata_ahci_cmd_tab)) and hoist the nsegs KASSERT above the PRD write loop" } |