β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5078

irq_source_info_dce120[] leaves DC_IRQ_SOURCE_DC{1..6}_VLINE0 (enum 84..89) zero-initialized with .funcs==NULL; dal_irq_service_set/ack dereference info->funcs unguarded β€” DF-2168/4713/4932/4995/5054 NULL-funcs-dispatch family instance on the DCE120 table

Summary

Designators stop at 83 while the enum runs to 90 - the exact shape noted for maintainers in DF-4932. Latent (no in-tree caller passes 84..89; traced). Verbatim replica: SIGSEGV exit=139 x2 deterministic; six-dummy fix validated via full amdgpu.ko -Werror rebuild.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5078 Β· 16 files
FileTypeDescriptionSize
dce120_vline0gap.c β€” 35.8 KB view raw
build.sh β€” 79 B view raw
run.sh β€” 103 B view raw
build.log β€” 188 B view raw
run.log β€” 2.5 KB view raw
run.2.log β€” 2.5 KB view raw
dmesg.txt β€” 1.2 KB view raw
fix.diff β€” 666 B view raw
amdgpu_module_build.log β€” 1.2 MB ↓ download
fix_build.log β€” 1.2 MB ↓ download
fix_run.log β€” 1.5 KB view raw
env.txt β€” 201 B view raw
VERDICT.md β€” 4.5 KB ↓ raw
README.md β€” 2.0 KB ↓ raw
verdict.json β€” 6.3 KB view raw
manifest.json β€” 1.3 KB view raw

DF-5078 β€” DCE120 irq table VLINE0 gap β†’ NULL .funcs dispatch

File: sys/dev/drm/amd/display/dc/irq/dce120/irq_service_dce120.c:177-263 (DF-2168/DF-4713/DF-4932/DF-4995/DF-5054 family instance on the DCE120 table β€” the shape noted for maintainers in DF-4932's verdict)

Build (on the guest)

mkdir -p /root/df5078 && cp dce120_vline0gap.c build.sh run.sh /root/df5078/
sh /root/df5078/build.sh

Run (on the guest; run twice for determinism)

sh /root/df5078/run.sh     # -> run.log, run.2.log

Expected

  • baseline (dce120_vline0gap_base):
  • static audit: exactly 6 NULL-funcs slots β€” 84..89 (DC_IRQ_SOURCE_DC{1..6}_VLINE0, enum 84..89 < DAL_IRQ_SOURCES_NUMBER=90, irq_types.h:140-148);
  • controls pass: ack(90) rejected; set(PFLIP1) generic; dce120 hpd_ack polarity toggle; VBLANK1..6 through the real conversion path arm pipes 0..5; to_dal sweep (256 src x 13 ext) returns 0 results in 84..89;
  • trigger: dal_irq_service_ack(DC_IRQ_SOURCE_DC1_VLINE0) β†’ child dies signal 11 at the info->funcs->ack deref (irq_service.c:152); dal_irq_service_set(...) in the main process β†’ SIGSEGV exit 139 (:116 acks first β†’ same deref). Kernel-equivalent: page-0 read β‡’ panic.
  • fixed (-DFIX_DF5078, = fix.diff): 0 NULL-funcs slots, dummy handlers log-and-return, exit 0.

Observed (guest, cc 8.3): baseline exit=139 x2 (child signal 11 + main fault), fixed exit=0 x2. Kernel console corroborates the faults (dmesg.txt: pid ... (dce120_vline0gap) ... exited on signal 11).

Fix validation: both dce120 fix.diffs (DF-5078 + DF-5079) applied to guest /usr/src, full make -j6 amdgpu.ko module rebuild rc=0, 0 errors / 0 warnings under -Werror (amdgpu_module_build.log, 777 lines; irq_service_dce110.c + irq_service_dce120.c both recompiled at :571-574); sources reverted md5-verified pristine; make clean.

Reachability is latent (traced in VERDICT.md) and the guest has no AMD GPU β€” family-standard logic-level replica methodology (same as DF-4932/DF-4995/DF-5054).

VERDICT.md
↓ download raw

DF-5078 VERDICT β€” dce120 VLINE0 table gap (NULL .funcs dispatch), replica-reproduced

Status: reproduced (logic level, family-standard replica), impact panic, confidence certain. Same methodology and ceiling as DF-4932 (dce110), DF-4995 (dcn10), DF-5054 (dce80) β€” the DCE120 instance of the family, noted for maintainers in DF-4932's verdict and now filed per-file ("each asic table is its own code").

Root cause (code-certain)

irq_source_info_dce120[DAL_IRQ_SOURCES_NUMBER] (irq_service_dce120.c:177-263) designators cover exactly enum sources 0..83:

INVALID(0); HPD1+0..5(1..6); HPD1RX+0..5(7..12); I2C_DDC1..6(13..18);
DPSINK1..6(19..24); TIMER(25); PFLIP1+0..5(26..31); PFLIP_UNDERLAY0(32);
GPIOPAD0..30(33..63); DC1..6UNDERFLOW(64..69); DMCU_SCP(70); VBIOS_SW(71);
VUPDATE1+0..5(72..77); VBLANK1+0..5(78..83)

The shared enum (irq_types.h:40-148) continues to DC_IRQ_SOURCE_DC{1..6}_LINE0 = 84..89 < DAL_IRQ_SOURCES_NUMBER=90 β€” those six entries stay zero-initialized, .funcs == NULL. find_irq_source_info (irq_service.c:77-86) bounds-checks ONLY the index, so dal_irq_service_ack (:152 β€” invoked FIRST by dal_irq_service_set at :116) dereferences info->funcs->ack on NULL, and dal_irq_service_set (:118) info->funcs->set β€” a read at page-0 offset ~40 β‡’ kernel page fault/panic. DF-2168/DF-4713 is the hub-level family root; this is the dce120 table's own completeness gap.

Reproduction (this run, on the audit guest)

Verbatim userland replica of the dce120 entry macros + FULL table body + dce120 hpd_ack + dummy funcs + dce110_vblank_set + to_dal_irq_source_dce110 + the irq_service.c:77-158 dispatch (see dce120_vline0gap.c header for the path:line map). Results (run.log, run.2.log β€” deterministic x2):

  • static audit: NULL-funcs entries: 84 85 86 87 88 89 (6 NULL-funcs slots)
  • controls: ack(90) rejected; set(PFLIP1) generic path ok; dce120 hpd_ack polarity toggle ok; VBLANK1..6 arm pipes 0..5 through the real conversion; to_dal sweep (256 src x 13 ext incl. 0xdead): 0 returns in 84..89
  • trigger-child ack(84): info->funcs == 0x0 β†’ signal 11
  • trigger-main set(84): Segmentation fault, exit 139
  • fixed mode (six dummy entries = fix.diff): 0 NULL-funcs, dummy handlers log-and-return, exit 0

Kernel console corroborates the faults on the guest (dmesg.txt: four pid ... (dce120_vline0gap) ... exited on signal 11 lines per run).

Reachability (traced honestly β€” latent)

  • IH arrival: amdgpu_dm_irq_handler (amdgpu_dm_irq.c:477-487) converts via to_dal_irq_source_dce110 β€” can only return covered sources or INVALID (dummy entry), never 84..89 (sweep above).
  • dm_irq_state (amdgpu_dm_irq.c:535-556): IRQ_TYPE_PFLIP/IRQ_TYPE_VBLANK + acrtc->otg_inst (hardware-bounded 0..5) β†’ 26..31 / 78..83.
  • HPD init/fini (amdgpu_dm_irq.c:625-645, 515-527): HPD/HPDRX only.
  • amdgpu_dm.c:3014: IRQ_TYPE_VBLANK + acrtc->otg_inst.
  • The service exists only on DCE12 (Vega10/12) hardware (dce120_resource.c:1011); guest has 0 AMD PCI devices.

β‡’ No unprivileged trigger exists today; the panic is one future caller away (a DM change using VLINE0 on DCE12, or any caller gating on the DAL_VALID_IRQ_SRC_NUM off-by-one at irq_types.h:157-158, which admits src == DAL_IRQ_SOURCES_NUMBER).

Ceiling

NULL-page read at a fixed small offset β‡’ hard kernel panic (local DoS). No write primitive, no leak. Severity Low (family-consistent).

Fix validation

fix.diff = six [DC_IRQ_SOURCE_DCx_VLINE0] = dummy_irq_entry() designators completing the table over the shared enum (DF-4932/DF-4995/DF-5054's exact per-asic shape). Applied to guest /usr/src together with DF-5079's diff: patch -V none -p1, hunk #1 succeeded at :260; full make -j6 amdgpu.ko rebuild rc=0, 0 error: / 0 warning: under -Werror (amdgpu_module_build.log 777 lines; irq_service_dce120.c compiled at :574); replica fixed mode exit 0; sources reverted md5-verified pristine (51bd6ea8...), make clean. Guest returned to clean snapshot afterwards.

Artifacts

dce120_vline0gap.c (code_hash d196028e...), build.log, run.log, run.2.log, dmesg.txt, env.txt, fix.diff, amdgpu_module_build.log, fix_build.log, fix_run.log, manifest.json, verdict.json.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched reproduced

fix.diff applied to guest /usr/src (patch -V none -p1, hunk #1 at :260); full make -j6 amdgpu.ko rebuild rc=0 with 0 errors/0 warnings under -Werror (amdgpu_module_build.log; irq_service_dce120.c compiled at :573-574); replica fixed mode (identical shape) exits 0 where baseline exits 139; sources reverted md5-verified pristine (51bd6ea8...), make clean.

fix_build.log (=amdgpu_module_build.log, rc=0, zero diagnostics); fix_run.log (fixed mode: 0 NULL-funcs slots, dummy ack/set log-and-return, exit 0); run.log (baseline exit=139)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026 (amdgpu.ko module rebuilt with fix; not booted β€” no AMD GPU on guest)

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log + run.2.log (deterministic x2: 6 NULL-funcs slots 84..89; controls pass incl. VBLANK1..6 arming pipes 0..5 and to_dal sweep 0 hits in 84..89; child ack(84) signal 11; main set(84) 'Segmentation fault' exit=139; fixed mode exit=0); dmesg.txt (kernel-observed signal-11 exits of the replica); dce120_vline0gap.c header (path:line map); amdgpu_module_build.log (777 lines, rc=0, 0 error:/0 warning:, irq_service_dce120.o at :573-574)

PoC changes

Self-authored from the family template (DF-5055's harness skeleton): instantiated the FULL dce120 designator set (not just the defect region) with the dce120 SRI/IRQ_REG_ENTRY macro forms (SRI collapsed to straight mm_ fake register numbers; per-instance mask defines generated to satisfy the block##reg_num token-paste), dce120 hpd_ack verbatim with a fake register file, plus fork-based ack-path trigger and a main-process set-path trigger, static NULL-funcs audit, and 256x13 to_dal sweep.

Verified recommended fix

Complete the dce120 table over the shared enum: six [DC_IRQ_SOURCE_DCx_VLINE0] = dummy_irq_entry() designators (fix.diff); hub-level hardening (funcs NULL guards in irq_service.c set/ack) tracked by DF-4932.

Verdict

Reproduced at logic level with a verbatim userland replica of the FULL dce120 irq table (irq_service_dce120.c:87-263 entry macros incl. the SRI/IRQ_REG_ENTRY forms, dce120 hpd_ack :40-65, funcs tables :67-85), to_dal_irq_source_dce110 (dce110:315-393, the converter dce120 installs at :266), dce110_vblank_set (dce110:195-219) and the generic dispatch (irq_service.c:77-158), run on the audit guest. Designators cover exactly 0..83 while the shared enum runs to DAL_IRQ_SOURCES_NUMBER=90: DC_IRQ_SOURCE_DC{1..6}_VLINE0 (84..89) stay zero-initialized with .funcs==NULL, and find_irq_source_info (irq_service.c:82) bounds-checks only the index, so dal_irq_service_ack (:152, called first by dal_irq_service_set at :116) and dal_irq_service_set (:118) dereference info->funcs->ack/.set on NULL β€” replica ack(84) child dies signal 11 at the deref and set(84) in the main process SIGSEGVs deterministically (exit 139, both runs), the kernel-equivalent being a page-0 read at ~offsetof(.funcs->ack) => hard panic. This is the DF-2168/DF-4713/DF-4932/DF-4995/DF-5054 NULL-funcs-dispatch family instance on the DCE120 (Vega10/12) table β€” the shape noted for maintainers in DF-4932's verdict; each asic table is its own code. Reachability is latent and traced honestly: every in-tree dc_interrupt_set/ack caller was checked (dm_irq_state PFLIP/VBLANK+otg_inst hardware-bounded 0..5 per amdgpu_dm_irq.c:535-556; hpd_init/fini HPD/HPDRX per amdgpu_dm_irq.c:625-645 and :515-527; amdgpu_dm.c:3014 VBLANK+otg_inst; the IH path amdgpu_dm_irq.c:477-487 can only receive to_dal-mapped covered sources or INVALID β€” the harness to_dal walk (256x13 combos incl. 0xdead) returns 0 results in 84..89), and the service is created only on DCE12 hardware (dce120_resource.c:1011) while the guest has no AMD GPU (0 PCI 1002: devices). No unprivileged trigger exists today; the panic is one future caller away (a DM change using VLINE0 on DCE12, or the DAL_VALID_IRQ_SRC_NUM off-by-one at irq_types.h:157-158 admitting src==90 into any caller gating on it). No write primitive, no leak; ceiling is a kernel NULL-page-read panic (local DoS). FIX VALIDATED: fix.diff (six VLINE0 dummy_irq_entry() designators completing the table, the DF-4932/DF-4995/DF-5054 per-asic shape) applied to guest /usr/src together with DF-5079's (hunk at :260); full amdgpu.ko module rebuild under -Werror rc=0, zero errors, zero warnings, irq_service_dce120.o recompiled and linked (amdgpu_module_build.log:574); replica fixed mode handles VLINE0 via dummy log-and-return handlers, exit 0 vs baseline 139; guest sources reverted md5-verified pristine (51bd6ea8...), make clean, guest returned to clean snapshot.