Skip to content

Commit 4217c6a

Browse files
author
Steven Price
committed
drm/panfrost: Fix GEM handle creation ref-counting
panfrost_gem_create_with_handle() previously returned a BO but with the only reference being from the handle, which user space could in theory guess and release, causing a use-after-free. Additionally if the call to panfrost_gem_mapping_get() in panfrost_ioctl_create_bo() failed then a(nother) reference on the BO was dropped. The _create_with_handle() is a problematic pattern, so ditch it and instead create the handle in panfrost_ioctl_create_bo(). If the call to panfrost_gem_mapping_get() fails then this means that user space has indeed gone behind our back and freed the handle. In which case just return an error code. Reported-by: Rob Clark <[email protected]> Fixes: f3ba912 ("drm/panfrost: Add initial panfrost driver") Signed-off-by: Steven Price <[email protected]> Reviewed-by: Rob Clark <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 4e699e3 commit 4217c6a

File tree

3 files changed

+20
-28
lines changed

3 files changed

+20
-28
lines changed

drivers/gpu/drm/panfrost/panfrost_drv.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
8282
struct panfrost_gem_object *bo;
8383
struct drm_panfrost_create_bo *args = data;
8484
struct panfrost_gem_mapping *mapping;
85+
int ret;
8586

8687
if (!args->size || args->pad ||
8788
(args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP)))
@@ -92,21 +93,29 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
9293
!(args->flags & PANFROST_BO_NOEXEC))
9394
return -EINVAL;
9495

95-
bo = panfrost_gem_create_with_handle(file, dev, args->size, args->flags,
96-
&args->handle);
96+
bo = panfrost_gem_create(dev, args->size, args->flags);
9797
if (IS_ERR(bo))
9898
return PTR_ERR(bo);
9999

100+
ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
101+
if (ret)
102+
goto out;
103+
100104
mapping = panfrost_gem_mapping_get(bo, priv);
101-
if (!mapping) {
102-
drm_gem_object_put(&bo->base.base);
103-
return -EINVAL;
105+
if (mapping) {
106+
args->offset = mapping->mmnode.start << PAGE_SHIFT;
107+
panfrost_gem_mapping_put(mapping);
108+
} else {
109+
/* This can only happen if the handle from
110+
* drm_gem_handle_create() has already been guessed and freed
111+
* by user space
112+
*/
113+
ret = -EINVAL;
104114
}
105115

106-
args->offset = mapping->mmnode.start << PAGE_SHIFT;
107-
panfrost_gem_mapping_put(mapping);
108-
109-
return 0;
116+
out:
117+
drm_gem_object_put(&bo->base.base);
118+
return ret;
110119
}
111120

112121
/**

drivers/gpu/drm/panfrost/panfrost_gem.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,8 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t
235235
}
236236

237237
struct panfrost_gem_object *
238-
panfrost_gem_create_with_handle(struct drm_file *file_priv,
239-
struct drm_device *dev, size_t size,
240-
u32 flags,
241-
uint32_t *handle)
238+
panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags)
242239
{
243-
int ret;
244240
struct drm_gem_shmem_object *shmem;
245241
struct panfrost_gem_object *bo;
246242

@@ -256,16 +252,6 @@ panfrost_gem_create_with_handle(struct drm_file *file_priv,
256252
bo->noexec = !!(flags & PANFROST_BO_NOEXEC);
257253
bo->is_heap = !!(flags & PANFROST_BO_HEAP);
258254

259-
/*
260-
* Allocate an id of idr table where the obj is registered
261-
* and handle has the id what user can see.
262-
*/
263-
ret = drm_gem_handle_create(file_priv, &shmem->base, handle);
264-
/* drop reference from allocate - handle holds it now. */
265-
drm_gem_object_put(&shmem->base);
266-
if (ret)
267-
return ERR_PTR(ret);
268-
269255
return bo;
270256
}
271257

drivers/gpu/drm/panfrost/panfrost_gem.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ panfrost_gem_prime_import_sg_table(struct drm_device *dev,
6969
struct sg_table *sgt);
7070

7171
struct panfrost_gem_object *
72-
panfrost_gem_create_with_handle(struct drm_file *file_priv,
73-
struct drm_device *dev, size_t size,
74-
u32 flags,
75-
uint32_t *handle);
72+
panfrost_gem_create(struct drm_device *dev, size_t size, u32 flags);
7673

7774
int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv);
7875
void panfrost_gem_close(struct drm_gem_object *obj,

0 commit comments

Comments
 (0)