DF-3755 / run.log
== DF-3755 harness: ni_parse_power_table alloc-failure dangling free ==
[A] parse: 8 states, state[2] BOOT, kzalloc fails at i=5
state 2 classified BOOT -> boot_ps = &ps[2] (inside dpm.ps @ 0x8004a30c0)
[kzalloc #5 fails โ memory pressure]
ni_dpm_init returned -ENOMEM, radeon_pm.c:1448 ignores it;
ni_dpm_enable() then ran the UAF chain and returned 0
radeon_pm.c:1448 ignores dpm.init rc; :1449 assigns
current_ps = requested_ps = boot_ps = 0x8004a3120 (DANGLING: ps array freed at ni_dpm.c:4022)
num_ps = 0 (never set -> ps_priv[0..4] leak permanently)
radeon_pm_init error swallowed at ni.c:2432 -> driver keeps loading
[B] UAF read through boot_ps after slab reuse
victim alloc (384 bytes) = 0x8004a30c0 (reuse: SAME chunk)
ni_dpm_enable consumed reused-chunk data: mclk=0xdeadbee
(kernel: garbage/attacker data drives the DPM state machine)
(deeper derefs of reused-chunk pointers fault -> panic)
[C] teardown: ni.c:2489 radeon_pm_fini -> ni_dpm_fini ->
kfree(rdev->pm.dpm.ps) on the dangling pointer (double free)
[kzalloc #5 fails โ memory pressure]
post-corruption allocations: x1=0x8004a30c0 x2=0x8004a30c0 -> ALIAS (same chunk handed out twice)
>>> kernel kmalloc: same silent bin corruption;
two subsystems now share one live object <<<
(child 0 โ no abort: the corruption is silent, as in-kernel)
[C2] double free with live victim: kfree(dangling) frees victim
victim = 0x8004a30c0 == freed dpm.ps = 0x8004a30c0: REUSED
after kfree(victim): next malloc returns 0x8004a30c0 == victim: YES (double-alloc)
-> victim freed while live; next allocation overlays it
[D] Fixed path (fix.diff: free ps_privs, NULL the pointer,
propagate rc; radeon_pm checks dpm.init rc)
[kzalloc #5 fails โ memory pressure]
rc=-ENOMEM propagated; dpm.ps = NULL; ps_privs freed;
radeon_pm_init_dpm aborts before touching boot_ps;
ni_dpm_fini kfree(NULL) โ no double free, no leak