gen6_ppgtt_create() stores the result of gen6_alloc_top_pd() directly into ppgtt->base.pd, and on failure the ERR_PTR stays in the field. i915_vm_put() runs vm->cleanup = gen6_ppgtt_cleanup(), where gen6_ppgtt_free_pd() dereferences pd via gen6_for_all_pdes() - with an ERR_PTR that is an invalid dereference and a crash (in the async release worker).
Assign to a local first and store into the field only after it is validated, so the field never holds an error pointer; on the failure path it stays NULL, and gen6_ppgtt_free_pd() now bails out on a NULL pd. Found by static analysis. Cc: [email protected] Signed-off-by: Chengyu Liu <[email protected]> --- drivers/gpu/drm/i915/gt/gen6_ppgtt.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c index 438cd4724ac4..f747ee1f96d7 100644 --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c @@ -259,6 +259,9 @@ static void gen6_ppgtt_free_pd(struct gen6_ppgtt *ppgtt) struct i915_page_table *pt; u32 pde; + if (!pd) + return; + gen6_for_all_pdes(pt, pd, pde) if (pt) free_pt(&ppgtt->base.vm, pt); @@ -427,6 +430,7 @@ void gen6_ppgtt_unpin(struct i915_ppgtt *base) struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt) { + struct i915_page_directory *pd; struct i915_ggtt * const ggtt = gt->ggtt; struct gen6_ppgtt *ppgtt; int err; @@ -455,11 +459,12 @@ struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt) if (err) goto err_put; - ppgtt->base.pd = gen6_alloc_top_pd(ppgtt); - if (IS_ERR(ppgtt->base.pd)) { - err = PTR_ERR(ppgtt->base.pd); + pd = gen6_alloc_top_pd(ppgtt); + if (IS_ERR(pd)) { + err = PTR_ERR(pd); goto err_put; } + ppgtt->base.pd = pd; return &ppgtt->base; -- 2.25.1
