Skip to content

Commit 304da2d

Browse files
committed
drm/framebuffer: Acquire internal references on GEM handles
jira LE-4159 cve CVE-2025-38449 Rebuild_History Non-Buildable kernel-5.14.0-570.42.2.el9_6 commit-author Thomas Zimmermann <tzimmermann@suse.de> commit f6bfc9a 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: Jonathan Maple <jmaple@ciq.com>
1 parent 61a583a commit 304da2d

File tree

5 files changed

+68
-26
lines changed

5 files changed

+68
-26
lines changed

drivers/gpu/drm/drm_framebuffer.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -860,11 +860,23 @@ void drm_framebuffer_free(struct kref *kref)
860860
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
861861
const struct drm_framebuffer_funcs *funcs)
862862
{
863+
unsigned int i;
863864
int ret;
865+
bool exists;
864866

865867
if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
866868
return -EINVAL;
867869

870+
for (i = 0; i < fb->format->num_planes; i++) {
871+
if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
872+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
873+
if (fb->obj[i]) {
874+
exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
875+
if (exists)
876+
fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
877+
}
878+
}
879+
868880
INIT_LIST_HEAD(&fb->filp_head);
869881

870882
fb->funcs = funcs;
@@ -873,15 +885,24 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
873885
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
874886
false, drm_framebuffer_free);
875887
if (ret)
876-
goto out;
888+
goto err;
877889

878890
mutex_lock(&dev->mode_config.fb_lock);
879891
dev->mode_config.num_fb++;
880892
list_add(&fb->head, &dev->mode_config.fb_list);
881893
mutex_unlock(&dev->mode_config.fb_lock);
882894

883895
drm_mode_object_register(dev, &fb->base);
884-
out:
896+
897+
return 0;
898+
899+
err:
900+
for (i = 0; i < fb->format->num_planes; i++) {
901+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
902+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
903+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
904+
}
905+
}
885906
return ret;
886907
}
887908
EXPORT_SYMBOL(drm_framebuffer_init);
@@ -958,6 +979,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
958979
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
959980
{
960981
struct drm_device *dev = fb->dev;
982+
unsigned int i;
983+
984+
for (i = 0; i < fb->format->num_planes; i++) {
985+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
986+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
987+
}
961988

962989
mutex_lock(&dev->mode_config.fb_lock);
963990
list_del(&fb->head);

drivers/gpu/drm/drm_gem.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,23 +197,34 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
197197
}
198198

199199
/**
200-
* drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
200+
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
201201
* @obj: GEM object
202202
*
203-
* Acquires a reference on the GEM buffer object's handle. Required
204-
* to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
205-
* to release the reference.
203+
* Acquires a reference on the GEM buffer object's handle. Required to keep
204+
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
205+
* to release the reference. Does nothing if the buffer object has no handle.
206+
*
207+
* Returns:
208+
* True if a handle exists, or false otherwise
206209
*/
207-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
210+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
208211
{
209212
struct drm_device *dev = obj->dev;
210213

211214
guard(mutex)(&dev->object_name_lock);
212215

213-
drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
216+
/*
217+
* First ref taken during GEM object creation, if any. Some
218+
* drivers set up internal framebuffers with GEM objects that
219+
* do not have a GEM handle. Hence, this counter can be zero.
220+
*/
221+
if (!obj->handle_count)
222+
return false;
223+
214224
drm_gem_object_handle_get(obj);
225+
226+
return true;
215227
}
216-
EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
217228

218229
/**
219230
* drm_gem_object_handle_free - release resources bound to userspace handles
@@ -246,7 +257,7 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
246257
}
247258

248259
/**
249-
* drm_gem_object_handle_put_unlocked - releases reference on user-space handles
260+
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
250261
* @obj: GEM object
251262
*
252263
* Releases a reference on the GEM buffer object's handle. Possibly releases
@@ -257,14 +268,14 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
257268
struct drm_device *dev = obj->dev;
258269
bool final = false;
259270

260-
if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
271+
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
261272
return;
262273

263274
/*
264-
* Must bump handle count first as this may be the last
265-
* ref, in which case the object would disappear before we
266-
* checked for a name
267-
*/
275+
* Must bump handle count first as this may be the last
276+
* ref, in which case the object would disappear before
277+
* we checked for a name.
278+
*/
268279

269280
mutex_lock(&dev->object_name_lock);
270281
if (--obj->handle_count == 0) {
@@ -277,7 +288,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
277288
if (final)
278289
drm_gem_object_put(obj);
279290
}
280-
EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
281291

282292
/*
283293
* 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
@@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
9999
unsigned int i;
100100

101101
for (i = 0; i < fb->format->num_planes; i++)
102-
drm_gem_object_handle_put_unlocked(fb->obj[i]);
102+
drm_gem_object_put(fb->obj[i]);
103103

104104
drm_framebuffer_cleanup(fb);
105105
kfree(fb);
@@ -182,10 +182,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
182182
if (!objs[i]) {
183183
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
184184
ret = -ENOENT;
185-
goto err_gem_object_handle_put_unlocked;
185+
goto err_gem_object_put;
186186
}
187-
drm_gem_object_handle_get_unlocked(objs[i]);
188-
drm_gem_object_put(objs[i]);
189187

190188
min_size = (height - 1) * mode_cmd->pitches[i]
191189
+ drm_format_info_min_pitch(info, i, width)
@@ -195,22 +193,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
195193
drm_dbg_kms(dev,
196194
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
197195
objs[i]->size, min_size, i);
198-
drm_gem_object_handle_put_unlocked(objs[i]);
196+
drm_gem_object_put(objs[i]);
199197
ret = -EINVAL;
200-
goto err_gem_object_handle_put_unlocked;
198+
goto err_gem_object_put;
201199
}
202200
}
203201

204202
ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
205203
if (ret)
206-
goto err_gem_object_handle_put_unlocked;
204+
goto err_gem_object_put;
207205

208206
return 0;
209207

210-
err_gem_object_handle_put_unlocked:
208+
err_gem_object_put:
211209
while (i > 0) {
212210
--i;
213-
drm_gem_object_handle_put_unlocked(objs[i]);
211+
drm_gem_object_put(objs[i]);
214212
}
215213
return ret;
216214
}

drivers/gpu/drm/drm_internal.h

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

154154
/* drm_gem.c */
155155
int drm_gem_init(struct drm_device *dev);
156-
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
156+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
157157
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
158158
int drm_gem_handle_create_tail(struct drm_file *file_priv,
159159
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
* @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock.
193200
*/

0 commit comments

Comments
 (0)