--- a/drivers/rknpu/rknpu_gem.c +++ b/drivers/rknpu/rknpu_gem.c @@ -878,10 +878,25 @@ { struct rknpu_mem_create *args = data; struct rknpu_gem_object *rknpu_obj = NULL; + struct drm_gem_object *obj = NULL; int ret = -EINVAL; - rknpu_obj = rknpu_gem_object_find(file_priv, args->handle); - if (!rknpu_obj) { + /* #patch38: hold a real reference, same reasoning as #patch37 in + * rknpu_gem_destroy_ioctl(). rknpu_gem_object_find() is lookup-then-put and returns an + * UNREFERENCED pointer kept alive only by the handle table, so every dereference below + * raced a concurrent close of that handle. The window here is far shorter than the + * destroy path's (nothing sleeps between the lookup and the last use), which is why this + * one is a hardening fix rather than a suspected crash source -- but the object is read + * four times after the lookup, and correctness should not rest on "probably not + * preempted there". + * + * Both branches below leave exactly ONE reference owned by us, dropped at the end. Net + * refcount across the ioctl is unchanged from before: the handle keeps the object alive + * afterwards, exactly as it always did. */ + obj = drm_gem_object_lookup(file_priv, args->handle); + if (obj) { + rknpu_obj = to_rknpu_obj(obj); + } else { rknpu_obj = rknpu_gem_object_create(drm, args->flags, args->size, args->sram_size, args->iommu_domain_id, @@ -895,15 +910,19 @@ rknpu_gem_object_destroy(rknpu_obj); return ret; } + /* rknpu_gem_handle_create() dropped the allocation reference (the handle owns it + * now), so take our own to match the lookup branch. */ + obj = &rknpu_obj->base; + drm_gem_object_get(obj); } - // rknpu_gem_object_get(&rknpu_obj->base); - args->size = rknpu_obj->size; args->sram_size = rknpu_obj->sram_size; args->obj_addr = (__u64)(uintptr_t)rknpu_obj; args->dma_addr = rknpu_obj->dma_addr; + rknpu_gem_object_put(obj); + return 0; }