Skip to content

Commit 6a6dbf0

Browse files
author
CKI KWF Bot
committed
Merge: CVE-2025-38449: drm/gem: Acquire references on GEM handles for framebuffers
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1323 # Merge Request Required Information This MR backport the fix for CVE-2025-38449 and the follow up fixes required. It includes the patch backported by the CKI Backport Bot in https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1276 but included other required changes. ## Summary of Changes 1. Commit `drm/gem: Acquire references on GEM handles for framebuffers` fixes the actual CVE 2. Commit `drm/framebuffer: Acquire internal references on GEM handles` is a follow up fix of 1. 3. The other 4 commits are patches 4/7, 5/7, 6/7 and 7/7 of [this upstream series](https://lore.kernel.org/all/20250715155934.150656-1-tzimmermann@suse.de/). Patches 1 to 3 are not required because they revert changes not present in RHEL yet. Therefore: Omitted-fix: 0ecfb8d Omitted-fix: 1e9d2ae Omitted-fix: bb7f497 ## Conflicts Only commit `Revert "drm/gem-shmem: Use dma_buf from GEM object instance"` conflicted, check it for more information ## Approved Development Ticket(s) JIRA: https://issues.redhat.com/browse/RHEL-106712 CVE: CVE-2025-38449 Signed-off-by: José Expósito <jexposit@redhat.com> Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com> Approved-by: Robert Foss <rfoss@kernel.org> Approved-by: Jocelyn Falempe <jfalempe@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents bf8f222 + d6bb626 commit 6a6dbf0

File tree

8 files changed

+110
-18
lines changed

8 files changed

+110
-18
lines changed

drivers/gpu/drm/drm_framebuffer.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,11 +862,23 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
862862
int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
863863
const struct drm_framebuffer_funcs *funcs)
864864
{
865+
unsigned int i;
865866
int ret;
867+
bool exists;
866868

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

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

872884
fb->funcs = funcs;
@@ -875,15 +887,24 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
875887
ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
876888
false, drm_framebuffer_free);
877889
if (ret)
878-
goto out;
890+
goto err;
879891

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

885897
drm_mode_object_register(dev, &fb->base);
886-
out:
898+
899+
return 0;
900+
901+
err:
902+
for (i = 0; i < fb->format->num_planes; i++) {
903+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
904+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
905+
fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
906+
}
907+
}
887908
return ret;
888909
}
889910
EXPORT_SYMBOL(drm_framebuffer_init);
@@ -960,6 +981,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
960981
void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
961982
{
962983
struct drm_device *dev = fb->dev;
984+
unsigned int i;
985+
986+
for (i = 0; i < fb->format->num_planes; i++) {
987+
if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
988+
drm_gem_object_handle_put_unlocked(fb->obj[i]);
989+
}
963990

964991
mutex_lock(&dev->mode_config.fb_lock);
965992
list_del(&fb->head);

drivers/gpu/drm/drm_gem.c

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,46 @@ void drm_gem_private_object_fini(struct drm_gem_object *obj)
212212
}
213213
EXPORT_SYMBOL(drm_gem_private_object_fini);
214214

215+
static void drm_gem_object_handle_get(struct drm_gem_object *obj)
216+
{
217+
struct drm_device *dev = obj->dev;
218+
219+
drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock));
220+
221+
if (obj->handle_count++ == 0)
222+
drm_gem_object_get(obj);
223+
}
224+
225+
/**
226+
* drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
227+
* @obj: GEM object
228+
*
229+
* Acquires a reference on the GEM buffer object's handle. Required to keep
230+
* the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
231+
* to release the reference. Does nothing if the buffer object has no handle.
232+
*
233+
* Returns:
234+
* True if a handle exists, or false otherwise
235+
*/
236+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
237+
{
238+
struct drm_device *dev = obj->dev;
239+
240+
guard(mutex)(&dev->object_name_lock);
241+
242+
/*
243+
* First ref taken during GEM object creation, if any. Some
244+
* drivers set up internal framebuffers with GEM objects that
245+
* do not have a GEM handle. Hence, this counter can be zero.
246+
*/
247+
if (!obj->handle_count)
248+
return false;
249+
250+
drm_gem_object_handle_get(obj);
251+
252+
return true;
253+
}
254+
215255
/**
216256
* drm_gem_object_handle_free - release resources bound to userspace handles
217257
* @obj: GEM object to clean up.
@@ -242,20 +282,26 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
242282
}
243283
}
244284

245-
static void
246-
drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
285+
/**
286+
* drm_gem_object_handle_put_unlocked - releases reference on user-space handle
287+
* @obj: GEM object
288+
*
289+
* Releases a reference on the GEM buffer object's handle. Possibly releases
290+
* the GEM buffer object and associated dma-buf objects.
291+
*/
292+
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
247293
{
248294
struct drm_device *dev = obj->dev;
249295
bool final = false;
250296

251-
if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
297+
if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
252298
return;
253299

254300
/*
255-
* Must bump handle count first as this may be the last
256-
* ref, in which case the object would disappear before we
257-
* checked for a name
258-
*/
301+
* Must bump handle count first as this may be the last
302+
* ref, in which case the object would disappear before
303+
* we checked for a name.
304+
*/
259305

260306
mutex_lock(&dev->object_name_lock);
261307
if (--obj->handle_count == 0) {
@@ -389,8 +435,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
389435
int ret;
390436

391437
WARN_ON(!mutex_is_locked(&dev->object_name_lock));
392-
if (obj->handle_count++ == 0)
393-
drm_gem_object_get(obj);
438+
439+
drm_gem_object_handle_get(obj);
394440

395441
/*
396442
* Get the user-visible handle using idr. Preload and perform

drivers/gpu/drm/drm_gem_dma_helper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj)
230230

231231
if (drm_gem_is_imported(gem_obj)) {
232232
if (dma_obj->vaddr)
233-
dma_buf_vunmap_unlocked(gem_obj->dma_buf, &map);
233+
dma_buf_vunmap_unlocked(gem_obj->import_attach->dmabuf, &map);
234234
drm_prime_gem_destroy(gem_obj, dma_obj->sgt);
235235
} else if (dma_obj->vaddr) {
236236
if (dma_obj->map_noncoherent)

drivers/gpu/drm/drm_gem_framebuffer_helper.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ EXPORT_SYMBOL(drm_gem_fb_vunmap);
419419
static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir,
420420
unsigned int num_planes)
421421
{
422+
struct dma_buf_attachment *import_attach;
422423
struct drm_gem_object *obj;
423424
int ret;
424425

@@ -427,9 +428,10 @@ static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_dat
427428
obj = drm_gem_fb_get_obj(fb, num_planes);
428429
if (!obj)
429430
continue;
431+
import_attach = obj->import_attach;
430432
if (!drm_gem_is_imported(obj))
431433
continue;
432-
ret = dma_buf_end_cpu_access(obj->dma_buf, dir);
434+
ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
433435
if (ret)
434436
drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n",
435437
ret, num_planes, dir);
@@ -452,6 +454,7 @@ static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_dat
452454
*/
453455
int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
454456
{
457+
struct dma_buf_attachment *import_attach;
455458
struct drm_gem_object *obj;
456459
unsigned int i;
457460
int ret;
@@ -462,9 +465,10 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct
462465
ret = -EINVAL;
463466
goto err___drm_gem_fb_end_cpu_access;
464467
}
468+
import_attach = obj->import_attach;
465469
if (!drm_gem_is_imported(obj))
466470
continue;
467-
ret = dma_buf_begin_cpu_access(obj->dma_buf, dir);
471+
ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir);
468472
if (ret)
469473
goto err___drm_gem_fb_end_cpu_access;
470474
}

drivers/gpu/drm/drm_gem_shmem_helper.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,10 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
339339
int ret = 0;
340340

341341
if (drm_gem_is_imported(obj)) {
342-
ret = dma_buf_vmap(obj->dma_buf, map);
342+
ret = dma_buf_vmap(obj->import_attach->dmabuf, map);
343343
if (!ret) {
344344
if (drm_WARN_ON(obj->dev, map->is_iomem)) {
345-
dma_buf_vunmap(obj->dma_buf, map);
345+
dma_buf_vunmap(obj->import_attach->dmabuf, map);
346346
return -EIO;
347347
}
348348
}
@@ -405,7 +405,7 @@ void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
405405
struct drm_gem_object *obj = &shmem->base;
406406

407407
if (drm_gem_is_imported(obj)) {
408-
dma_buf_vunmap(obj->dma_buf, map);
408+
dma_buf_vunmap(obj->import_attach->dmabuf, map);
409409
} else {
410410
dma_resv_assert_held(shmem->base.resv);
411411

drivers/gpu/drm/drm_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
161161

162162
/* drm_gem.c */
163163
int drm_gem_init(struct drm_device *dev);
164+
bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
165+
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
164166
int drm_gem_handle_create_tail(struct drm_file *file_priv,
165167
struct drm_gem_object *obj,
166168
u32 *handlep);

drivers/gpu/drm/drm_prime.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,13 @@ struct dma_buf *drm_gem_prime_handle_to_dmabuf(struct drm_device *dev,
453453
}
454454

455455
mutex_lock(&dev->object_name_lock);
456-
/* re-export the original imported/exported object */
456+
/* re-export the original imported object */
457+
if (obj->import_attach) {
458+
dmabuf = obj->import_attach->dmabuf;
459+
get_dma_buf(dmabuf);
460+
goto out_have_obj;
461+
}
462+
457463
if (obj->dma_buf) {
458464
get_dma_buf(obj->dma_buf);
459465
dmabuf = obj->dma_buf;

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)