⬢ DragonFlyBSD Kernel Audit
DF-5778 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5778",
  "file": "sys/dev/drm/amd/display/dc/irq/irq_service.c",
  "title": "Unguarded svc->funcs->to_dal_irq_source double-deref in dal_irq_service_to_irq_source + swallowed dal_irq_service_construct failure \u2014 latent NULL-deref hardening gap (Info)",
  "verdict_summary": "Latent CWE-476: irq_service.c:165 double-derefs the service object with no guard (asymmetric with every sibling entry point and with dc_interrupt_set), and construct-failure (:53-63) is swallowed by family constructors. Reachability traced dead via all 8 in-tree create-sites and dc.c ctx ordering; executed as a structural KLD-harness proof.",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Structural/latent finding verified statically and by production-code KLD harness on the DragonFly guest (no AMD GPU; synthetic-table family standard). The harness compiles the verbatim dispatcher (irq_service.c:77-169, irq_service.h structs, irq_types.h enum+macro) and proves: T1 the exact irq_service.c:165 deref chain on a zero-initialised irq_service hits svc->funcs (off+16)==NULL with NO guard on the path (fault-free probe); B1 find_irq_source_info accepts exactly 0..89 and rejects one-past-end 90 and all larger/(enum)-1 values with canaries intact (table walk in-bounds \u2014 executable negative result for the pass-2 bounds question); B3 the DF-4731 DAL_VALID_IRQ_SRC_NUM off-by-one is defused at this files set/ack paths by the `>=` bound; B4 upstream Linux v4.17 used `>` (accepts 90 \u2192 &info[90] one-past-end) while the DFly trees `>=` (irq_service.c:82) is stricter/correct \u2014 no port-introduced defect, byte-identical otherwise; T2-T4 verbatim happy path, dummy-slot log-and-fail with zero register traffic, and generic RMW confined to in-table regs. The in-kernel NULL-deref manifestation cannot be exercised: no AMD hardware on the guest and no in-tree caller can produce the NULL object (all 8 resource create-sites NULL-check pool->base.irqs; dc->ctx is kzalloc-checked at core/dc.c:602-607 before pool creation at :671). Severity Info, defense-in-depth.",
  "exploit_chain": "",
  "evidence": "run.log: T1 zeroed irq_service=... svc->funcs (off+16) = 0 + T1 VERDICT: ... NO guard; run.log B1 RESULT: PASS (bounds) and B2 ... PASS (intact); run.log B3/B4 lines; VERDICT.md section 2 reachability trace with path:line for all 8 create-sites; env.txt (no AMD GPU); fix.diff",
  "kernel_refs": [
    "sys/dev/drm/amd/display/dc/irq/irq_service.c:53",
    "sys/dev/drm/amd/display/dc/irq/irq_service.c:160",
    "sys/dev/drm/amd/display/dc/irq/irq_service.c:165",
    "sys/dev/drm/amd/display/dc/core/dc.c:1673",
    "sys/dev/drm/amd/display/dc/core/dc.c:1690",
    "sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c:398",
    "sys/dev/drm/amd/display/dc/dm_services.h:68"
  ],
  "poc_changes": "no seed PoC; harness authored fresh. Build iterations on guest: (1) <kmod.mk> not on out-of-tree include path -> absolute /usr/src/sys/conf/kmod.mk; (2) no sys/stddef.h on DFly -> address arithmetic for the member offset; (3)(4) -Werror=missing-prototypes -> added verbatim prototypes from irq_service_interface.h:28-47 and irq_service.h:72-83; (5) guest root shell is csh -> run.sh pipes commands through /bin/sh (as vm.sh does).",
  "attempts": 5,
  "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": 210,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df5778 && make SYSDIR=/usr/src/sys KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC",
  "run_cmd": "kldload /root/df5778/df5778_harness.ko; sleep 1; dmesg | grep DF5778; kldunload df5778_harness",
  "code_hash": "f73d899c322abd1a372c59e125f0c57422aaac434668fa2997f1c2ec774c3ad0",
  "notes": "Guest /root/df5778 removed after capture; module cleanly unloaded (kldstat back to kernel+ehci+xhci). Upstream comparison fetched live from torvalds/linux v4.17 during this audit (find_irq_source_info used `>` there; DFly `>=` is stricter \u2014 positive divergence, documented in VERDICT.md B4). Pass-2 knowns not re-reported: DF-2168 + DF-4932/4995/5054/5078 (zero-filled VLINE0 slots, funcs==NULL), DF-4933/5055/5079 (dce110_vblank_set pipe_offset underflow), DF-4731 (DAL_VALID_IRQ_SRC_NUM off-by-one, adjacent file), DF-4732 (DFly lockmgr IRQ-path divergence, adjacent file).",
  "recommended_fix": "Guard dal_irq_service_to_irq_source (reject !irq_service/!funcs/!member with DC_IRQ_SOURCE_INVALID) and give dc_interrupt_to_irq_source/dc_interrupt_ack the same dc/res_pool->irqs NULL check dc_interrupt_set already has (fix.diff)",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Pure-hardening early-return guards on paths provably non-NULL in-tree; no AMD GPU on the guest to build an amdgpu kernel and no way to drive the objects to NULL, so a fix-build validation is not possible (house precedent DF-4731). Guard logic desk-checked against every cited call site; callers already tolerate DC_IRQ_SOURCE_INVALID (dummy slot).",
  "fix_evidence": "fix.diff (guards at irq_service.c:165 and dc.c:1673/1690); VERDICT.md section 5"
}