DF-5230 / df5230.c
/* * DF-5230 synthetic trigger: NULL rdev->uvd_fw dereference in * uvd_v4_2_resume() (sys/dev/drm/radeon/uvd_v4_2.c:51). * * Production trigger chain (all links verified path:line in VERDICT.md): * * suspend / dpm-disable / pm_fini * -> radeon_pm_suspend_dpm() radeon_pm.c:1257 * -> radeon_dpm_disable(rdev) radeon.h:2797 * -> kv_dpm_disable() kv_dpm.c:1305,1316 (bound at * radeon_asic.c:2285) * -> kv_dpm_powergate_uvd(rdev,false) kv_dpm.c:1608 * [caps_uvd_pg==true unconditionally kv_dpm.c:2773; * uvd_power_gated was set true at boot by kv_dpm_late_enable() * kv_dpm.c:1300] * -> uvd_v4_2_resume(rdev) kv_dpm.c:1628 <-- NO has_uvd / * uvd_fw guard here * -> rdev->uvd_fw->datasize uvd_v4_2.c:51 uvd_fw == NULL * * This harness reproduces the exact device state a CIK APU has when * radeon_uvd_init() failed for lack of the radeonkmsfw_*_uvd firmware kmod * (radeon_uvd.c:137 fw_header_present=false; :141/:176 request_firmware * failed -> uvd_fw stays NULL; cik.c:8150-8157 has_uvd=0 -- which guards * the cik.c:8175 caller but NOT the kv_dpm.c:1628 caller) while DPM was * enabled from the SMC firmware, and calls the production * uvd_v4_2_resume() compiled into radeon.ko. * * Expected: immediate kernel panic -- page fault reading * offsetof(struct firmware, datasize) == 0x10 from NULL at uvd_v4_2.c:51, * BEFORE the first WREG32 (uvd_v4_2.c:52), so no MMIO is touched. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/malloc.h> #include <linux/firmware.h> #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" static int df5230_modevent(module_t mod, int type, void *data) { struct radeon_device *fake; int r; switch (type) { case MOD_LOAD: /* zeroed == post-failed-radeon_uvd_init() state: * uvd.fw_header_present == false (radeon_uvd.c:137) * uvd.gpu_addr == 0 (pin never happened) * uvd_fw == NULL (request_firmware failed) * has_uvd == 0 (cik.c:8156; guards only * the cik.c:8175 caller) */ fake = kmalloc(sizeof(*fake), M_DRM, M_WAITOK | M_ZERO); fake->uvd.max_handles = 10; /* radeon_uvd.c:138 */ kprintf("DF5230: pre uvd_fw=%p fw_header_present=%d " "gpu_addr=0x%jx max_handles=%u\n", fake->uvd_fw, fake->uvd.fw_header_present, (uintmax_t)fake->uvd.gpu_addr, fake->uvd.max_handles); kprintf("DF5230: calling production uvd_v4_2_resume() " "(radeon.ko) -- expect panic at uvd_v4_2.c:51\n"); r = uvd_v4_2_resume(fake); /* <-- uvd_v4_2.c:51 */ /* only reachable with the DF-5230 guard applied */ kprintf("DF5230: survived, uvd_v4_2_resume returned %d\n", r); /* fake deliberately leaked: one-shot test module */ return (0); default: return (ENOTSUP); } } static moduledata_t df5230_mod = { "df5230", df5230_modevent, NULL }; DECLARE_MODULE(df5230, df5230_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(df5230, 1); /* no MODULE_DEPEND: radeon.ko declares no MODULE_VERSION, so a versioned * dependency always fails; drm.ko + radeon.ko are pre-loaded manually and * DFBSD's linker resolves uvd_v4_2_resume against the loaded files. */ |