⬢ DragonFlyBSD Kernel Audit
DF-5498 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5498",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Reproduced with the production ROM builder compiled for userland (fwcrom.cs own non-_KERNEL/-DTEST path, as fwcontrol(8) links it). crom_add_simple_text() sets tl->crc_len = howmany(sizeof(struct csrtext)+len, 4) = 3+ceil(len/4) (fwcrom.c:459), counting the 12-byte header although crc_len must count only the quadlets after the crc quadlet (the directory builders semantic, fwcrom.c:394-407) and crom_load() adds the crc quadlet back (fwcrom.c:520-522). crom_load()/crom_crc() therefore always consume one quadlet past the text: every locally-built text leaf is published with a spurious trailing quadlet (stale bytes of chunk->data.buf[]) and a crc_len off by one against IEEE 1212 (demonstrated: leaf header crc_len field=21 where 20 is correct, and 20 where 19 is correct); for text lengths 69..72 (MAX_TEXT=72, fwcrom.c:442) the read reaches one quadlet past chunk->data[] -- a sub-object OOB read of 4 bytes (inside struct crom_chunks tail padding; KASAN-visible, latent out-of-object read). Model: bytes past data[] pre-filled with 0xCAFEBABE -> after production crom_add_simple_text(72 chars)+crom_load(), the pattern is present verbatim in the generated ROM (29 vs 28 quadlets); 68-char control: exact fit, pattern absent. Impact Info: current kernel callers pass static strings / the root-settable hostname (firewire.c:624-626, dcons_crom.c:117-119), the over-read bytes are zeroed padding in every current layout (no leak), so this is correctness/interop (spec-wrong text leaves broadcast to bus peers) plus a latent hardening defect. Fix validated: with fix.diff (crc_len = howmany(len,4)+2) applied to guest /usr/src, crc_len=20 == spec-correct, pattern absent, ROM one quadlet shorter per leaf.",
  "exploit_chain": "",
  "evidence": "run.log (baseline: crc_len=21/20 vs correct 20/19, PATTERN FOUND in generated ROM, exit 42; control absent), fix_run.log (patched: crc_len==spec-correct, PATTERN absent both cases), build.log/fix_build.log, c5498_user.c, fix.diff",
  "kernel_refs": [
    "sys/bus/firewire/fwcrom.c:442",
    "sys/bus/firewire/fwcrom.c:459",
    "sys/bus/firewire/fwcrom.c:517",
    "sys/bus/firewire/fwcrom.c:518",
    "sys/bus/firewire/fwcrom.c:520",
    "sys/bus/firewire/fwcrom.c:522",
    "sys/bus/firewire/iec13213.h:232",
    "sys/bus/firewire/iec13213.h:241",
    "sys/bus/firewire/firewire.c:624",
    "sys/bus/firewire/firewire.c:626"
  ],
  "poc_changes": "Model written fresh. Bring-up fixes: (1) #include <sys/queue.h> before iec13213.h (its -DTEST builder structs use STAILQ_*); (2) -Dmain=fwcrom_test_main applied only to the fwcrom.c translation unit (a global -D renamed the harness main too and duplicated the symbol); (3) offset arithmetic via offsetof(struct crom_chunk, data)+sizeof(data) so the pre-fill marks exactly the bytes past data[].",
  "attempts": 3,
  "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": 180,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (cc -DTEST -Dmain=fwcrom_test_main -c /usr/src/sys/bus/firewire/fwcrom.c; cc -DTEST -c c5498_user.c; cc -o c5498_user ...)",
  "run_cmd": "sh run.sh  (./c5498_user; exit 42 == REPRODUCED)",
  "code_hash": "dc0bd7e485173ae853c137728f581f97fffadb71bf2449e23e11cb476e60180e",
  "notes": "Info-grade by the mission rubric (hardening/correctness, no demonstrated confidentiality/integrity impact in current layouts: the over-read bytes are zeroed tail padding and no attacker-controlled string reaches the builder). Verified anyway because the userspace model was free in the same session; evidence class = production-code userspace model (fwdev/firewire precedent family). The spurious-quadlet/short-string stale-byte aspect affects EVERY text length, not just 69..72.",
  "recommended_fix": "tl->crc_len = howmany(len, sizeof(u_int32_t)) + 2; in crom_add_simple_text (fwcrom.c:459) so crc_len counts only the quadlets after the crc quadlet (fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Baseline: pattern quadread past chunk->data[] published in the ROM (exit 42), leaf crc_len off by one at every length. Patched (fix.diff on /usr/src, model rebuilt): crc_len == IEEE-1212-correct (20/19), pattern absent in both cases, ROM one quadlet shorter per text leaf.",
  "fix_evidence": "fix_run.log, fix_build.log, fix.diff"
}