DF-5055 / verdict.json
{ "finding_id": "DF-5055", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "Reproduced at logic level with a verbatim userland replica of the dce80 vupdate/vblank entry macros + the dce80-local vblank_irq_info_funcs {.set=dce110_vblank_set} (irq_service_dce80.c:82-85,132-163), dce110_vblank_set itself (irq_service_dce110.c:195-219), to_dal_irq_source_dce110, and the set dispatch (irq_service.c:77-124), run on the audit guest against a 0x5a-poisoned 8MiB current_state with valid timing generators in pipes 0..5. The vupdate entries carry src_id=0/ext_id=0 (macro initializes no .src_id, unlike the vblank entries 19..24), so dce110_vblank_sets re-derivation to_dal_irq_source_dce110(0,0) returns DC_IRQ_SOURCE_INVALID and `uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK underflows to 178; core_dc->current_state->res_ctx.pipe_ctx[178] reads the poisoned mapping (tg=0x5a5a5a5a5a5a5a5a) and the very next `tg->funcs->arm_vert_intr(tg,2) faults \u2014 SIGBUS exit 138, deterministic x2. VBLANK1..6 controls arm pipes 0..5 through the REAL conversion path, proving the in-tree-reachable vblank path healthy \u2014 this is the DF-4933 (dce110) twin wired independently by the DCE80 tables own macros. Latent like DF-4933: no in-tree caller ever .sets a VUPDATE source (suspend/resume HPD/HPDRX-only, vblank enable = IRQ_TYPE_VBLANK+otg_inst, pflip = IRQ_TYPE_PFLIP; the IH converter returns VUPDATE only for V_UPDATE src_ids 7,9,..,17 which amdgpu_dm never registers), and the guest has no AMD GPU. The defect is double-baked upstream (even a correctly remapped VUPDATE source underflows, since the base is IRQ_TYPE_VBLANK not IRQ_TYPE_VUPDATE). Ceiling if a future caller appears: far-OOB read feeding a wild indirect call \u2014 a groomed heap around the dc_state allocation could in principle aim tg (not demonstrated; honest ceiling is a kernel panic). FIX VALIDATED: fix.diff (vblank_pipe_offset helper deriving the pipe from the TABLE INDEX \u2014 provably 0..5 for both ranges, DF-4933s fix shape) -> replica fixed mode arms the correct pipe for all 12 VUPDATE/VBLANK sources, exit 0; full amdgpu.ko rebuild with the fix on guest /usr/src under -Werror RC=0, zero diagnostics, irq_service_dce110.o linked; sources reverted md5-verified pristine.", "exploit_chain": "", "evidence": "run.log (decisive: table: vupdate1 src_id=0 ext_id=0 | vblank1 src_id=19; controls control VBLANK1..6 set arming pipes 0..5; trigger pipe_offset = (uint8_t)(0-78) = 178 -> Bus error exit 138; ---- SECOND BASELINE RUN ---- second=138; fixed [fixed] VUPDATE1 -> pipe 0 armed via index-derived offset; exit 0); dce80_vupd.c (verbatim replica); amd_fix_apply.log + amdgpu_module_build.log (-Werror amdgpu.ko rebuild RC=0); fix.diff; VERDICT.md", "kernel_refs": [ "sys/dev/drm/amd/display/dc/irq/dce80/irq_service_dce80.c:82", "sys/dev/drm/amd/display/dc/irq/dce80/irq_service_dce80.c:132", "sys/dev/drm/amd/display/dc/irq/dce80/irq_service_dce80.c:145", "sys/dev/drm/amd/display/dc/irq/dce80/irq_service_dce80.c:162", "sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c:195", "sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c:205", "sys/dev/drm/amd/display/dc/irq/dce110/irq_service_dce110.c:207", "sys/dev/drm/amd/display/dc/irq_types.h:154", "sys/dev/drm/amd/include/ivsrcid/ivsrcid_vislands30.h:30", "sys/dev/drm/amd/display/dc/core/dc.c:1672" ], "poc_changes": "Authored fresh (no seed), mirroring DF-4933s dce110_vupd replica onto the DCE80 wiring: two compile/logic iterations (forward-decl ordering; stub signature mismatch; fixed-mode exit logic initially treated a successful return as BAD and was corrected to expect index-derived success).", "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": 400, "guest_dirty": 0, "build_cmd": "sh build.sh (cc -O2 -Wall -std=gnu11 [-DFIX_DF5055])", "run_cmd": "sh run.sh (baseline then fixed; second baseline inside run.log)", "code_hash": "c0d135b447e536d538c0583b7723d03fdb6e26ac211a131c209085e3c1503bef", "notes": "Twin of DF-4933 (dce110 table); the fix lands in the shared callee dce110_vblank_set and therefore covers both tables at once; giving dce80/dce110 vupdate_int_entry a proper .src_id is optional consistency only (V_UPDATE ids are non-consecutive 7,9,..,17, and a correct src_id alone would NOT fix the underflow because the subtraction base is IRQ_TYPE_VBLANK). Full dce80 pass-2 negatives live in DF-5054s VERDICT.md.", "recommended_fix": "Derive pipe_offset from the table index instead of re-mapping info->src_id: source = (enum dc_irq_source)(info - irq_service->info); pipe = (source in VUPDATE1..VUPDATE6) ? source - DC_IRQ_SOURCE_VUPDATE1 : source - DC_IRQ_SOURCE_VBLANK1 (covers dce80 and dce110 tables alike).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fixed: fix.diff (vblank_pipe_offset index-derived helper + one-line call-site change in dce110_vblank_set) applied to guest /usr/src (patched md5 f6754cc7d3bac717925e9e1cc398a902, together with DF-5054s diff); full make -j6 amdgpu.ko rebuild under -Werror RC=0, zero diagnostics, irq_service_dce110.o linked (amdgpu_module_build.log); replica fixed mode arms the correct pipe for all 12 VUPDATE/VBLANK sources (exit 0) vs baseline SIGBUS 138; sources reverted md5-verified pristine (35607b1aeb1dc71fa3108f6573b6c5fd), module objects cleaned, guest reset to the with-src snapshot.", "fix_evidence": "fix.diff; amd_fix_apply.log; amdgpu_module_build.log; run.log (baseline crash + fixed exit 0); VERDICT.md" } |