Skip to content

Commit a381709

Browse files
pvts-matPlaidCat
authored andcommitted
drm/framebuffer: Acquire internal references on GEM handles
jira VULN-136703 cve-bf CVE-2025-38449 commit-author Thomas Zimmermann <tzimmermann@suse.de> commit f6bfc9a upstream-diff Adapted `drm_gem_object_handle_get_unlocked()' (now `drm_gem_object_handle_get_if_exists_unlocked()') to use mutex_lock / mutex_unlock instead of guard(mutex). Resolved context conflicts in include/drm/drm_framebuffer.h due to missing bce3dab. Acquire GEM handles in drm_framebuffer_init() and release them in the corresponding drm_framebuffer_cleanup(). Ties the handle's lifetime to the framebuffer. Not all GEM buffer objects have GEM handles. If not set, no refcounting takes place. This is the case for some fbdev emulation. This is not a problem as these GEM objects do not use dma-bufs and drivers will not release them while fbdev emulation is running. Framebuffer flags keep a bit per color plane of which the framebuffer holds a GEM handle reference. As all drivers use drm_framebuffer_init(), they will now all hold dma-buf references as fixed in commit 5307dce ("drm/gem: Acquire references on GEM handles for framebuffers"). In the GEM framebuffer helpers, restore the original ref counting on buffer objects. As the helpers for handle refcounting are now no longer called from outside the DRM core, unexport the symbols. v3: - don't mix internal flags with mode flags (Christian) v2: - track framebuffer handle refs by flag - drop gma500 cleanup (Christian) Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Fixes: 5307dce ("drm/gem: Acquire references on GEM handles for framebuffers") Reported-by: Bert Karwatzki <spasswolf@web.de> Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/ Tested-by: Bert Karwatzki <spasswolf@web.de> Tested-by: Mario Limonciello <superm1@kernel.org> Tested-by: Borislav Petkov (AMD) <bp@alien8.de> Cc: Thomas Zimmermann <tzimmermann@suse.de> Cc: Anusha Srivatsa <asrivats@redhat.com> Cc: Christian König <christian.koenig@amd.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Maxime Ripard <mripard@kernel.org> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: "Christian König" <christian.koenig@amd.com> Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Cc: <stable@vger.kernel.org> Reviewed-by: Christian König <christian.koenig@amd.com> Link: https://lore.kernel.org/r/20250707131224.249496-1-tzimmermann@suse.de (cherry picked from commit f6bfc9a) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent 723499e commit a381709

5 files changed

Lines changed: 71 additions & 26 deletions

File tree

drivers/gpu/drm/drm_framebuffer.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -841,11 +841,23 @@ void drm_framebuffer_free(struct kref *kref)
841841
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
842842
const struct drm_framebuffer_funcs *funcs)
843843
{
844+
unsigned int i;
844845
int ret;
846+
bool exists;
845847

846848
if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
847849
return -EINVAL;
848850

851+
for (i = 0; i < fb->format->num_planes; i++) {
852+
if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
853+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
854+
if (fb->obj[i]) {
855+
exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
856+
if (exists)
857+
fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
858+
}
859+
}
860+
849861
INIT_LIST_HEAD(&fb->filp_head);
850862

851863
fb->funcs = funcs;
@@ -854,15 +866,24 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
854866
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
855867
false, drm_framebuffer_free);
856868
if (ret)
857-
goto out;
869+
goto err;
858870

859871
mutex_lock(&dev->mode_config.fb_lock);
860872
dev->mode_config.num_fb++;
861873
list_add(&fb->head, &dev->mode_config.fb_list);
862874
mutex_unlock(&dev->mode_config.fb_lock);
863875

864876
drm_mode_object_register(dev, &fb->base);
865-
out:
877+
878+
return 0;
879+
880+
err:
881+
for (i = 0; i < fb->format->num_planes; i++) {
882+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
883+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
884+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
885+
}
886+
}
866887
return ret;
867888
}
868889
EXPORT_SYMBOL(drm_framebuffer_init);
@@ -939,6 +960,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
939960
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
940961
{
941962
struct drm_device *dev = fb->dev;
963+
unsigned int i;
964+
965+
for (i = 0; i < fb->format->num_planes; i++) {
966+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
967+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
968+
}
942969

943970
mutex_lock(&dev->mode_config.fb_lock);
944971
list_del(&fb->head);

drivers/gpu/drm/drm_gem.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,25 +193,39 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
193193
}
194194

195195
/**
196-
* drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
196+
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
197197
* @obj: GEM object
198198
*
199-
* Acquires a reference on the GEM buffer object's handle. Required
200-
* to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
201-
* to release the reference.
199+
* Acquires a reference on the GEM buffer object's handle. Required to keep
200+
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
201+
* to release the reference. Does nothing if the buffer object has no handle.
202+
*
203+
* Returns:
204+
* True if a handle exists, or false otherwise
202205
*/
203-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
206+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
204207
{
205208
struct drm_device *dev = obj->dev;
206209

207210
mutex_lock(&dev->object_name_lock);
208211

209-
drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
212+
/*
213+
* First ref taken during GEM object creation, if any. Some
214+
* drivers set up internal framebuffers with GEM objects that
215+
* do not have a GEM handle. Hence, this counter can be zero.
216+
*/
217+
if (!obj->handle_count) {
218+
mutex_unlock(&dev->object_name_lock);
219+
return false;
220+
}
221+
210222
drm_gem_object_handle_get(obj);
211223

212224
mutex_unlock(&dev->object_name_lock);
225+
226+
return true;
213227
}
214-
EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
228+
215229

216230
/**
217231
* drm_gem_object_handle_free - release resources bound to userspace handles
@@ -244,7 +258,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
244258
}
245259

246260
/**
247-
* drm_gem_object_handle_put_unlocked - releases reference on user-space handles
261+
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
248262
* @obj: GEM object
249263
*
250264
* Releases a reference on the GEM buffer object's handle. Possibly releases
@@ -255,14 +269,14 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
255269
struct drm_device *dev = obj->dev;
256270
bool final = false;
257271

258-
if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
272+
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
259273
return;
260274

261275
/*
262-
* Must bump handle count first as this may be the last
263-
* ref, in which case the object would disappear before we
264-
* checked for a name
265-
*/
276+
* Must bump handle count first as this may be the last
277+
* ref, in which case the object would disappear before
278+
* we checked for a name.
279+
*/
266280

267281
mutex_lock(&dev->object_name_lock);
268282
if (--obj->handle_count == 0) {
@@ -275,7 +289,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
275289
if (final)
276290
drm_gem_object_put(obj);
277291
}
278-
EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
279292

280293
/*
281294
* Called at device or object close to release the file's

drivers/gpu/drm/drm_gem_framebuffer_helper.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
9292
unsigned int i;
9393

9494
for (i = 0; i < fb->format->num_planes; i++)
95-
drm_gem_object_handle_put_unlocked(fb->obj[i]);
95+
drm_gem_object_put(fb->obj[i]);
9696

9797
drm_framebuffer_cleanup(fb);
9898
kfree(fb);
@@ -167,10 +167,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
167167
if (!objs[i]) {
168168
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
169169
ret = -ENOENT;
170-
goto err_gem_object_handle_put_unlocked;
170+
goto err_gem_object_put;
171171
}
172-
drm_gem_object_handle_get_unlocked(objs[i]);
173-
drm_gem_object_put(objs[i]);
174172

175173
min_size = (height - 1) * mode_cmd->pitches[i]
176174
+ drm_format_info_min_pitch(info, i, width)
@@ -180,22 +178,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
180178
drm_dbg_kms(dev,
181179
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
182180
objs[i]->size, min_size, i);
183-
drm_gem_object_handle_put_unlocked(objs[i]);
181+
drm_gem_object_put(objs[i]);
184182
ret = -EINVAL;
185-
goto err_gem_object_handle_put_unlocked;
183+
goto err_gem_object_put;
186184
}
187185
}
188186

189187
ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
190188
if (ret)
191-
goto err_gem_object_handle_put_unlocked;
189+
goto err_gem_object_put;
192190

193191
return 0;
194192

195-
err_gem_object_handle_put_unlocked:
193+
err_gem_object_put:
196194
while (i > 0) {
197195
--i;
198-
drm_gem_object_handle_put_unlocked(objs[i]);
196+
drm_gem_object_put(objs[i]);
199197
}
200198
return ret;
201199
}

drivers/gpu/drm/drm_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ void drm_sysfs_lease_event(struct drm_device *dev);
158158

159159
/* drm_gem.c */
160160
int drm_gem_init(struct drm_device *dev);
161-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
161+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
162162
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
163163
int drm_gem_handle_create_tail(struct drm_file *file_priv,
164164
struct drm_gem_object *obj,

include/drm/drm_framebuffer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#ifndef __DRM_FRAMEBUFFER_H__
2424
#define __DRM_FRAMEBUFFER_H__
2525

26+
#include <linux/bits.h>
2627
#include <linux/ctype.h>
2728
#include <linux/list.h>
2829
#include <linux/sched.h>
@@ -100,6 +101,8 @@ struct drm_framebuffer_funcs {
100101
unsigned num_clips);
101102
};
102103

104+
#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i))
105+
103106
/**
104107
* struct drm_framebuffer - frame buffer object
105108
*
@@ -188,6 +191,10 @@ struct drm_framebuffer {
188191
* DRM_MODE_FB_MODIFIERS.
189192
*/
190193
int flags;
194+
/**
195+
* @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF.
196+
*/
197+
unsigned int internal_flags;
191198
/**
192199
* @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
193200
* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR

0 commit comments

Comments
 (0)