dce110_create_resource_pool leaks the kzalloc'd pool on construct() failure (DF-4318 twin) and dc->fbc_compressor is never destroyed anywhere (dce110_compressor_destroy has zero callers)
Summary
On construct() failure the function returns NULL without kfree(pool) - construct's fail arm already ran destruct(pool) which frees only sub-objects, and the caller never received the pointer. Plus the fbc_compressor is created but its destroy function has zero callers tree-wide. Guest allocation-accounting model: live_allocs=2 baseline vs 0 fixed. kfree + compressor-destroy fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4353 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df4353.c | β | 5.2 KB | view raw | |
| build.sh | β | 86 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 496 B | view raw | |
| run.log | β | 614 B | view raw | |
| env.txt | β | 966 B | view raw | |
| fix.diff | β | 712 B | view raw | |
| VERDICT.md | β | 3.1 KB | β raw | |
| README.md | β | 1.3 KB | β raw |
DF-4353 β dce110_create_resource_pool leaks the pool on construct() failure; dc->fbc_compressor is never destroyed (DF-4318/DF-4309 family)
Build / Run (guest model)
cc -O2 -Wall -o df4353 df4353.c ./df4353
Expected: LEAK CONFIRMED (model) β after a failed construct the
kzalloc'd struct dce110_resource_pool and the fbc compressor remain
live (2 orphaned allocations); the fixed failure arm leaves 0.
Root cause
- dce110_resource.c:1398-1414 β on
construct()failure the function returns NULL withoutkfree(pool). construct's failure arm already randestruct(pool)(:1394), which frees only the sub-objects; the caller (core/dc.c dc_construct) never received the pointer. The DF- 4318 twin at the dce110 instance (pool embeds the whole resource_pool base, core_types.h:120-198 β ~KB per failed bind). - Sibling:
dc->fbc_compressor = dce110_compressor_create(ctx)(:1372-1373) βdce110_compressor_destroy()(dce110_compressor.c:439) has zero callers in the tree; the compressor outlives teardown on every path (DF-4309 flavor).
Fix
fix.diff (git apply --check clean): kfree(pool) in the failure arm
(destruct already ran inside construct) + destroy the compressor in
construct's res_create_fail arm.
DF-4353 VERDICT
Status: untested (kernel path) β code defect certain; guest model demonstrates the orphaned allocations and the fix accounting.
Root cause (line-accurate)
-
dce110_create_resource_pool(dce110_resource.c:1398-1414):1403: pool = kzalloc(sizeof(struct dce110_resource_pool)); 1409: if (construct(num_virtual_links, dc, pool, asic_id)) 1410: return &pool->base; 1412: BREAK_TO_DEBUGGER(); 1413: return NULL; <-- no kfree(pool)construct()'sres_create_failarm (:1393-1395) runsdestruct(pool)which frees only the sub-objects (opps/transforms/ipps/mis/tgs, engines/i2cs, stream encs, clock sources, audios, abm, dmcu, dccg, irqs β :703-773). The pool allocation itself is orphaned; the caller (core/dc.c dc_construct β dce110_create_resource_pool) never received the pointer and can only destruct(dc). This is the exact DF-4318 error-path shape at the DCE11 (Carrizo/Stoney) instance; the pool embeds the fullstruct resource_poolbase (core_types.h:120-198, incl. 12-pointer stream_enc[] and the engine arrays) β ~KB per failed pool build. Failure triggers include any sub-object create failure (OOM), irq-service create failure (:1307-1310), resource_construct failure (:1378-1380), and a VBIOS reporting no external DP clock source (:1253-1257); rebind/hotplug loops amplify. -
Sibling asymmetry (DF-4309 flavor): construct() also does
if (dc->config.fbc_support) dc->fbc_compressor = dce110_compressor_create(ctx);(:1372-1373).grep -rn dce110_compressor_destroyβ the destroy function (dce110_compressor.c:439) has zero callers anywhere in the tree: the compressor is allocated on dc and never freed on any teardown path.
Verification
- Kernel path untestable on the audit guest: no AMD GPU (pciconf as root shows i440FX/PIIX + virtio only; env.txt); amdgpu.ko present but unbindable.
- Guest model
df4353.c(cc 8.3; build.log/run.log) reproduces the allocation accounting of the failure arm (DF-4318's methodology): baseline failure leaveslive_allocs=2(pool + compressor) β "LEAK CONFIRMED (model)"; the fixed arm leaves 0 β "FIX MODEL CLEAN (model)".
Fix validation
Kernel-level validation impossible on this guest. fix.diff (git apply
--check clean) adds kfree(pool) after the existing
BREAK_TO_DEBUGGER in the failure arm (destruct already ran inside
construct β no double free) and destroys dc->fbc_compressor in
construct's res_create_fail arm. Note: the successful-path lifecycle
gap (dc_destroy never freeing fbc_compressor) lives in core/dc.c and is
not reachable from this file; the local fix closes the error arm, the
model shows both allocations accounted.
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_testableKernel fix validation impossible on this guest (no DCE11 hardware). fix.diff is git-apply-clean against sys/; destruct() already ran inside construct's failure arm so the added kfree cannot double-free, and the model shows the patched failure arm ends at 0 live allocations.
fix.diff; df4353.c fixed arm ('FIX MODEL CLEAN (model)')
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log ('LEAK CONFIRMED (model)', live_allocs=2 baseline vs 0 fixed); VERDICT.md (line-accurate accounting incl. zero-caller grep for dce110_compressor_destroy); env.txt (no AMD GPU); fix.diff (git apply --check clean)
PoC changes
No seed PoC (pass-2 checklist hint only). Authored df4353.c: control-flow model of dce110_create_resource_pool/construct/destruct with explicit allocation accounting, methodology identical to DF-4318's accepted model.
Verified recommended fix
kfree(pool) in dce110_create_resource_pool's failure arm and dce110_compressor_destroy(dc->fbc_compressor) in construct's res_create_fail arm (see fix.diff).
Verdict
Code defect certain: dce110_create_resource_pool (dce110_resource.c:1398-1414) kzallocs the pool and on construct() failure returns NULL without kfree - construct's res_create_fail arm already ran destruct(pool) (:1394) which frees only sub-objects, so the ~KB struct dce110_resource_pool (embeds the full resource_pool base, core_types.h:120-198) leaks per failed amdgpu pool build on Carrizo/Stoney (any sub-create OOM, irq-service failure :1307-1310, resource_construct failure :1378-1380, VBIOS without external DP clock :1253-1257; rebind loops amplify). DF-4318 twin at the dce110 instance. Sibling asymmetry (DF-4309 flavor): dc->fbc_compressor created at :1372-1373 is never destroyed - dce110_compressor_destroy (dce110_compressor.c:439) has zero callers tree-wide. Kernel-path reproduction impossible: the audit guest has no AMD GPU (pciconf: i440FX+virtio only). Guest-built allocation-accounting model (cc 8.3) confirms the failure arm orphans both allocations (run.log, 'LEAK CONFIRMED (model)') and the fix drives it to zero. Hardening-class leak, no privilege boundary crossed.
No comments yet.