Divide-by-zero DoS in evergreen_cs_track_validate_cb via user-controlled CB_COLOR_PITCH
Summary
evergreen_cs_handle_reg at evergreen_cs.c:1396 stores raw IB dword to cb_color_pitch[id] unmasked (unlike depth path G_028058_PITCH_TILE_MAX 11-bit at :568, texture G_030000_PITCH 12-bit at :777). validate_cb at :401-404: pitch=cb_color_pitch[id], surf.nbx=(pitch+1)*8, surf.nby=((slice+1)*64)/surf.nbx. pitch=0xFFFFFFFF -> (pitch+1)*8 wraps to 0 -> divide-by-zero #DE kernel panic. DRM_AUTH local user on Evergreen+. CB_COLOR0_INFO valid + CB_COLOR0_BASE reloc + CB_TARGET_MASK=0xF + DRAW. Fix: mask pitch to 0x7FF (PITCH_TILE_MAX), add surf.nbx==0 check.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1245 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source trace, mechanism, fix rationale | 2.3 KB | β raw |
| fix.diff | suggested-fix | guard surf.nbx==0 before division in evergreen_cs_track_validate_cb | 607 B | view raw |
| fix_build_radeon.log | build-log | evergreen_cs.o compiled with fix, RC=0, no warnings | 1.3 KB | view raw |
| build.sh | build-log | repro: apply-check + note | 395 B | view raw |
| run.sh | run-log | no runtime trigger (no HW) | 374 B | view raw |
| env.txt | environment | uname, cc version, module state | 359 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1245 β Divide-by-zero DoS in evergreen_cs_track_validate_cb via CB_COLOR_PITCH
Verdict
SOURCE-CONFIRMED (real bug), INCONCLUSIVE at runtime β the radeon.ko module is not loaded (no AMD Evergreen GPU in the QEMU guest) and is not compiled into the GENERIC kernel, so the divide-by-zero path is dormant. Fix authored and compile-validated.
Mechanism (source trace)
The radeon DRM command-submission parser stores the raw user IB dword for CB_COLORn_PITCH unmasked into the track state, unlike the depth and texture paths which mask first:
sys/dev/drm/radeon/evergreen_cs.c:1396βtrack->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);(raw 32-bit, no& PITCH_TILE_MAXmask). Compare: the depth path usesG_028058_PITCH_TILE_MAX(11-bit,evergreen_cs.c:568); the texture path usesG_030000_PITCH(12-bit). The CB color path has no equivalent mask.sys/dev/drm/radeon/evergreen_cs.c:401-404:pitch = track->cb_color_pitch[id]; /* unsigned, raw */ slice = track->cb_color_slice[id]; surf.nbx = (pitch + 1) * 8; surf.nby = ((slice + 1) * 64) / surf.nbx; /* DIVIDE BY ZERO if nbx==0 */- If a DRM_AUTH client submits
CB_COLORn_PITCH = 0xFFFFFFFF, then(pitch+1)*8 = 0(32-bit wrap) and the division at line 404 faults with a kernel#DE(divide error) β panic.
Why not reproduced at runtime
radeon.kois not loaded on the guest (kldstatshows only kernel + ehci.ko + xhci.ko) and is not in X86_64_GENERIC (nodevice radeonin the kernel config).- Requires an AMD Evergreen-class (Radeon HD 5xxx/6xxx) GPU attached; the QEMU guest uses
-vga none/stdvga, no AMD GPU. - Requires
DRM_AUTH(an authenticated DRM client, i.e. a local X user). This is a local DoS via GPU command submission, reachable only on systems with the affected hardware.
Fix (fix.diff, compile-validated)
Guard surf.nbx == 0 before the division, returning -EINVAL (matching the existing dev_warn + return -EINVAL pattern used elsewhere in the function). The patched evergreen_cs.c compiles cleanly with gcc 8.3, -Werror, no warnings.
Realistic impact ceiling
Local kernel panic (DoS) by a DRM-authenticated user on a machine with an AMD Evergreen GPU. No memory-corruption primitive β purely a divide-by-zero fault. On this guest: not reachable (no AMD GPU).
Fix verification
not_testablecompile validated
module/object build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. evergreen_cs_track_validate_cb pitch+1 wraps to 0 -> div-by-zero. radeon not in GENERIC.
No comments yet.