amdgpu_dm debugfs: OR-combined valid_input accepts invalid DP lane_count; stored unvalidated and consumed by a lane_settings[LANE_COUNT_DP_MAX=4] write loop -> stack OOB write (LATENT: file not compiled)
Summary
dp_link_settings_write validates lane_count and link_rate with ONE flag - 'echo 5 a' passes with an invalid lane_count, stored verbatim into preferred_link_setting (no validation), and the live consumer returns it verbatim into link training. dp_phy_settings_write then loops r<lane_count writing lane_settings[r] past the [4]-element array - 12 bytes/extra lane, unbounded linear stack smash for 0xffffffff. LATENT: the file is doubly dead (not in SRCS AND CONFIG_DEBUG_FS undefined). Guest-compiled 1:1 logic demo reproduces ACCEPTED/stored/iteration-r=4-OOB. The cross-file amdgpu_dm_color.c:260 lead was verified REAL but is already DF-2083 (not re-filed). Split-the-flag fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4621 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| dp_link_logic_demo.c | β | 4.3 KB | view raw | |
| demo_run.log | β | 476 B | view raw | |
| README.md | β | 3.1 KB | β raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| fix.diff | β | 1.2 KB | view raw | |
| verdict.json | β | 3.7 KB | view raw |
DF-4621 β amdgpu_dm debugfs: OR-combined valid_input accepts invalid lane_count β stack OOB write in dp_phy_settings_write (LATENT: file not compiled)
What
dp_link_settings_write() validates the two user parameters with a single
OR-combined flag (sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:195-221):
switch (param[0]) { /* lane_count */
case LANE_COUNT_ONE: ... valid_input = true; ...
switch (param[1]) { /* link_rate */
case LINK_RATE_LOW: ... valid_input = true; ... /* same flag! */
if (!valid_input) { ... return; }
echo "5 a" > link_settings (or echo ffffffff a) passes with an invalid
lane_count because the link_rate matched. The value is then stored
unvalidated into link->preferred_link_setting by
dc_link_set_preferred_link_settings() (dc/core/dc.c:484), and consumed:
- dp_phy_settings_write (:386-410) β when
test_pattern_enabled,link_lane_settings.link_settings.lane_count = link->preferred_link_setting.lane_count, thenfor (r = 0; r < lane_count; r++) link_lane_settings.lane_settings[r] = β¦writes pastlane_settings[LANE_COUNT_DP_MAX = 4](include/link_service_types.h:71-75; LANE_COUNT_DP_MAX = LANE_COUNT_FOUR, dc/dc_dp_types.h:37). lane_count=5 β 12-byte stack overrun; lane_count=0xffffffff β unbounded linear stack smash (values constrained to enum triples 0..3 per 4-byte slot).link_lane_settingsis a local β stack OOB write (CWE-787). - decide_link_settings() (dc/core/dc_link_dp.c:1517-1525, live code)
returns
*link_setting = link->preferred_link_settingverbatim β invalid lane_count propagates into link training (lt_settings.lane_settings[]walks, DPCD lane writes).
Liveness (verified this run β honest status)
The file is doubly dead in DragonFly: it is absent from
sys/dev/drm/amdgpu/Makefile SRCS (lines 195-201 list amdgpu_dm.c,
amdgpu_dm_irq.c, amdgpu_dm_mst_types.c, amdgpu_dm_color.c, services,
helpers, pp_smu β not this file), and its only two callers are compiled under
#if defined(CONFIG_DEBUG_FS) (amdgpu_dm.c:478-479 dtn_debugfs_init,
:4119-4120 connector_debugfs_init), which is not defined (sys/dev/drm/kconfig.h).
So today this is an enable-day hazard (turning on debugfs builds without
also fixing validation), consistent with DF-1764/DF-1765/DF-4554 precedent.
The guest also has no AMD GPU (pciconf: no AMD devices).
What runs today
dp_link_logic_demo.c transcribes the validation logic (:195-221) and the
consumer loop (:394-410) 1:1 and runs on the guest β gcc itself flags the OOB
iteration (warning: iteration 4 invokes undefined behavior):
input: lane_count=5 (invalid), link_rate=0xa (valid) ACCEPTED by the single valid_input flag (amdgpu_dm_debugfs.c:195-221) stored preferred_link_setting.lane_count = 5 (dc.c:484, unvalidated) loop iteration r=4: OOB write at &lane_settings[4] -- past lane_settings[LANE_COUNT_DP_MAX-1=3]
(demo_run.log; a transcription logic-proof, NOT a kernel run β see VERDICT.md)
Fix
fix.diff splits the flag into valid_lane_count / valid_link_rate and
requires both (if (!valid_lane_count || !valid_link_rate)).
DF-4621 VERDICT
Finding
OR-combined valid_input in dp_link_settings_write
(amdgpu_dm_debugfs.c:195-221) accepts an invalid lane_count whenever the
link_rate is valid; the lane_count is stored unvalidated
(dc/core/dc.c:484) and later drives:
- the lane_settings[r] write loop in dp_phy_settings_write
(amdgpu_dm_debugfs.c:403) β array is lane_settings[LANE_COUNT_DP_MAX=4]
(link_service_types.h:71-75, dc_dp_types.h:37) β stack OOB write
(12 bytes per extra lane; unbounded for lane_count=0xffffffff);
- decide_link_settings (dc_link_dp.c:1517-1525) β verbatim propagation
into link training (LIVE dc code; its only corrupting producer is this
dead debugfs file).
Status: untested (kernel path), logic-proven (guest demo)
- The kernel path CANNOT run on this guest for two independent reasons:
1.
amdgpu_dm_debugfs.cis not compiled in DragonFly: absent fromsys/dev/drm/amdgpu/MakefileSRCS (:195-201); callers #if'd under CONFIG_DEBUG_FS (amdgpu_dm.c:478,4119) which kconfig.h does not define. 2. The guest has no AMD GPU (env.txt: no AMD PCI devices) β amdgpu DM never attaches. - Supporting runtime logic-proof on the guest (
dp_link_logic_demo.c, transcription of :195-221 and :394-410 with the real constants): input "5 a" β ACCEPTED, lane_count=5 stored, consumer loop performs iteration r=4 writing past lane_settings[3] β gcc corroborates with-Waggressive-loop-optimizations: iteration 4 invokes undefined behavior(demo_run.log). This demonstrates the validation flaw at runtime but is NOT a kernel execution; verdict status remainsuntestedhonestly.
Exploitability (if the file is ever built, i.e. enable-day)
Preconditions: AMD display hardware + CONFIG_DEBUG_FS build + the file added
to SRCS + root-writable... actually /sys/kernel/debug/dri files are 0644
(:712) β world-writable from the DRM master's context; debugfs is root-only
mounted (debugfs root, 0700 typically) β effectively a root-or-console
trigger, EXCEPT the invalid lane_count persists in link->preferred_link_
setting and decide_link_settings (live path) then walks it during
unprivileged-triggerable modesets. Even then written values are enum triples
{0..3} per 4-byte slot β crash-grade corruption, not clean pointer control;
lane_count=0xffffffff gives an unbounded low-value stack smash β panic.
Severity kept at Medium because it is latent (project precedent: dead-code
findings DF-1764/1765/DF-4554 = Low; this one is an OOB write primitive,
flagged for anyone enabling the debugfs build).
Fix
fix.diff (mechanically generated, applies to the tree as-is): split valid_lane_count / valid_link_rate, require both.
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_testablefix.diff is the standard upstream-style split (valid_lane_count && valid_link_rate); cannot be kernel-validated on this guest (file not compiled, no AMD GPU). The logic demo rejects lane_count=5 under the split by construction.
fix.diff (mechanically generated, clean apply); demo validates the rejection branch when the flag is split.
Confirmed kernel references
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:195
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:205
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:217
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:227
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:386
- sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c:403
- sys/dev/drm/amd/display/dc/core/dc.c:484
- sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1523
- sys/dev/drm/amd/display/include/link_service_types.h:71
- sys/dev/drm/amd/display/dc/dc_dp_types.h:37
- sys/dev/drm/amd/amdgpu/Makefile:195
Detail
Evidence (decisive lines)
demo_run.log (guest): 'ACCEPTED by the single valid_input flag', 'stored preferred_link_setting.lane_count = 5 (dc.c:484, unvalidated)', 'loop iteration r=4: OOB write at &lane_settings[4] -- past lane_settings[LANE_COUNT_DP_MAX-1=3]' plus gcc -Waggressive-loop-optimizations warning; README/VERDICT cite the dead-build proof (Makefile:195-201, amdgpu_dm.c:478,4119).
PoC changes
no kernel PoC possible (file not in build; no AMD GPU); wrote a 1:1 transcription logic demo (dp_link_logic_demo.c) compiled and run on the guest instead
Verified recommended fix
Split valid_input into valid_lane_count and valid_link_rate and require both before storing preferred link settings (see fix.diff).
Verdict
Kernel path UNTESTABLE on this guest: amdgpu_dm_debugfs.c is not compiled (absent from sys/dev/drm/amd/amdgpu/Makefile SRCS :195-201; callers #if defined(CONFIG_DEBUG_FS) at amdgpu_dm.c:478/:4119, undefined in kconfig.h) and the guest has no AMD GPU (no AMD PCI devices). Source-level analysis is certain: the single OR-combined valid_input flag (amdgpu_dm_debugfs.c:195-221) accepts an invalid lane_count whenever the link_rate parses; it is stored unvalidated (dc.c:484) and consumed by dp_phy_settings_write's lane_settings[LANE_COUNT_DP_MAX=4] write loop (:403 β stack OOB write; unbounded linear smash for lane_count 0xffffffff) and by the LIVE decide_link_settings (dc_link_dp.c:1523 verbatim propagation into link training). Supporting runtime logic-proof ran on the guest: the transcribed validation accepts '5 a', stores lane_count=5, and the consumer loop performs OOB iteration r=4 β gcc itself warns 'iteration 4 invokes undefined behavior' (demo_run.log). Latent enable-day hazard; fix.diff splits the two flags.
No comments yet.