DAL_VALID_IRQ_SRC_NUM off-by-one ('<=') accepts irq_source == DAL_IRQ_SOURCES_NUMBER β one-past-end index into amdgpu_dm_irq.c's handler-list tables
Summary
The guard macro accepts src == 90, one past the last valid index of the handler-list tables; register_interrupt then list_add_tail's into tab[90], corrupting the adjacent pflip_params[] with kernel list pointers. Latent (all current callers in-range; unregister has zero callers) - one future caller of the public API gets list corruption. Inherited verbatim from upstream v4.17; every other bounds check in the DC irq layer uses '>'. Guest-executed verbatim-macro harness proves the off-by-one; one-character fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4731 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df4731_proof.c | β | 4.9 KB | view raw | |
| build.sh | β | 130 B | view raw | |
| run.log | β | 561 B | view raw | |
| VERDICT.md | β | 3.8 KB | β raw | |
| fix.diff | β | 484 B | view raw | |
| verdict.json | β | 2.4 KB | view raw | |
| env.txt | β | 483 B | view raw |
DF-4731 VERDICT
Status: untested (kernel path hardware-gated) β guard defect proven by guest-executed logic proof
What was verified
-
The code defect is certain (static, line-cited). -
sys/dev/drm/amd/display/dc/irq_types.h:147β last enum memberDAL_IRQ_SOURCES_NUMBER = 90(counted: INVALID=0 β¦ DC6_VLINE0=89, NUMBER=90). -sys/dev/drm/amd/display/dc/irq_types.h:157-158β#define DAL_VALID_IRQ_SRC_NUM(src) ((src) <= DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)acceptssrc == 90. - Arrays:sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.h:106-107βstruct irq_list_head irq_handler_list_low_tab[DAL_IRQ_SOURCES_NUMBER];struct list_head irq_handler_list_high_tab[DAL_IRQ_SOURCES_NUMBER];β valid indices 0..89. - Consumers in the audited file:amdgpu_dm_irq.c:176(validate_irq_registration_params) β:238/:242(hnd_list = &adev->dm.irq_handler_list_{high,low}_tab[irq_source], thenlist_add_tailat:246);amdgpu_dm_irq.c:193(validate_irq_unregistration_params) β:123/:127(list walk +list_del+kfreeinremove_irq_handler). - DC side is correctly bounded elsewhere:irq_service.c:82(find_irq_source_infouses>=), which shows<=is the outlier. -
Proof-of-logic executed on the DragonFly guest (run.log): with the tree's verbatim enum and macro,
DAL_VALID_IRQ_SRC_NUM(90)== true, (89) == true, (91) == false β an exact off-by-one acceptance window of exactly one out-of-bounds index. -
Upstream comparison: Linux v4.17
drivers/gpu/drm/amd/display/dc/irq_types.hcontains the identical<=macro (fetched and diffed during this audit) β the defect is inherited, not a DragonFly port typo.
Why the kernel path was not exercised
The QEMU guest has no AMD display hardware (/dev/dri absent; only
vgapci0: <VGA-compatible display> chip=0x11111234 QEMU virtual VGA; no drm
kld loaded β env.txt). amdgpu_dm_irq_register_interrupt() is only reachable
behind a functioning amdgpu DC, so triggering the in-kernel OOB list_add_tail
is impossible on this guest.
Reachability on real hardware (why Low, not higher)
Every caller of amdgpu_dm_irq_register_interrupt() on this tree passes an
in-range source:
- amdgpu_dm.c:1274-1292 (register_hpd_handlers): dc_link->irq_source_hpd{,_rx},
both guarded by != DC_IRQ_SOURCE_INVALID.
- amdgpu_dm.c:1334-1345, 1356-1366 (dce110) and :1419-1452 (dcn10):
dc_interrupt_to_irq_source(dc, i, 0) β every to_dal_irq_source_*
implementation returns either a valid enum constant or DC_IRQ_SOURCE_INVALID
(= 0, in-bounds) (irq_service_dce110.c:315-391).
amdgpu_dm_irq_unregister_interrupt() has zero callers tree-wide.
So no user-, hardware-, or packet-derived value currently reaches the guard
with 90 β the finding is a latent guard defect / hardening item, exactly the
kind of bound every future caller will trust.
Fix validation
Not testable (needs AMD GPU to build a baseline kernel scenario). fix.diff
(<= β <) is the minimal correct change; it cannot regress the valid range
(89 still accepted, 0 still rejected β verified by the same harness logic).
Bottom line
Real one-past-end guard bug in the validation macro the audited file trusts for every handler-list index; inherited verbatim from Linux 4.17; latent (no live caller can pass the OOB value today); fixed by one character.
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
not_testableSingle-character fix (fix.diff); cannot be kernel-validated without AMD GPU. The same harness logic confirms the fixed bound still accepts 0<src<90 and rejects 90+.
fix.diff; VERDICT.md 'Fix validation' section
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log lines 'accept src=90 (ONE PAST) : true' and 'RESULT: OFF-BY-ONE CONFIRMED'; VERDICT.md reachability analysis (callers at amdgpu_dm.c:1274-1452 all in-range); env.txt documents absent AMD hardware
PoC changes
n/a - harness authored fresh (verbatim enum+macro extraction from the tree), no seed PoC existed
Verified recommended fix
irq_types.h:158 change '<=' to '<' in DAL_VALID_IRQ_SRC_NUM
Verdict
One-past-end guard defect in DAL_VALID_IRQ_SRC_NUM (irq_types.h:157-158, '<=' instead of '<') trusted by amdgpu_dm_irq.c's register/unregister validation (:176/:193) before indexing irq_handler_list_{low,high}_tab[irq_source] (:238/:242/:123/:127), arrays sized [DAL_IRQ_SOURCES_NUMBER]=90 (amdgpu_dm.h:106-107). The guard math was proven on the DragonFly guest with a verbatim-enum harness (run.log: src=90 accepted, src=89 accepted, src=91 rejected - exactly one OOB index passes). The in-kernel path is untestable on this guest (no AMD GPU; no /dev/dri; only QEMU virtual VGA) and is latent anyway: every register caller passes in-range sources and amdgpu_dm_irq_unregister_interrupt has zero callers tree-wide. Inherited verbatim from upstream Linux v4.17.
No comments yet.