From 729cde74bfe41391d0fb08e42a5efac4b4abcc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 21:53:06 +0100 Subject: [PATCH 01/13] drm/gem: Provide drm_gem_fb_{begin,end}_cpu_access() helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 37408cd825a47b89c2302b88ad3c071f796a2ec0 Implement helpers drm_gem_fb_begin_cpu_access() and _end_cpu_access(), which call the rsp dma-buf functions for all GEM BOs of the given framebuffer. Calls to dma_buf_end_cpu_access() can return an error code on failure, while drm_gem_fb_end_cpu_access() does not. The latter runs during DRM's atomic commit or during cleanup. Both cases don't allow for errors, so leave out the return value. v2: * fix typo in docs (Daniel) Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Reviewed-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20210716140801.1215-2-tzimmermann@suse.de (cherry picked from commit 37408cd825a47b89c2302b88ad3c071f796a2ec0) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 89 ++++++++++++++++++++ include/drm/drm_gem_framebuffer_helper.h | 6 ++ 2 files changed, 95 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index e2c68822e05cc..67bc9edc1d987 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -306,6 +306,95 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, } EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); +/** + * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access + * @fb: the framebuffer + * @dir: access mode + * + * Prepares a framebuffer's GEM buffer objects for CPU access. This function + * must be called before accessing the BO data within the kernel. For imported + * BOs, the function calls dma_buf_begin_cpu_access(). + * + * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) +{ + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + size_t i; + int ret, ret2; + + for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir); + if (ret) + goto err_dma_buf_end_cpu_access; + } + + return 0; + +err_dma_buf_end_cpu_access: + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret2 = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret2) { + drm_err(fb->dev, + "dma_buf_end_cpu_access() failed during error handling: %d\n", + ret2); + } + } + + return ret; +} +EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); + +/** + * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects + * @fb: the framebuffer + * @dir: access mode + * + * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This + * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access(). + * For imported BOs, the function calls dma_buf_end_cpu_access(). + * + * See also drm_gem_fb_begin_cpu_access(). + */ +void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) +{ + size_t i = ARRAY_SIZE(fb->obj); + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + int ret; + + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret) + drm_err(fb->dev, "dma_buf_end_cpu_access() failed: %d\n", ret); + } +} +EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); + static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd) { diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 6bdffc7aa1248..5705722f0855a 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -1,6 +1,9 @@ #ifndef __DRM_GEM_FB_HELPER_H__ #define __DRM_GEM_FB_HELPER_H__ +#include +#include + struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -34,6 +37,9 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); +void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); + #define drm_is_afbc(modifier) \ (((modifier) & AFBC_VENDOR_AND_TYPE_MASK) == DRM_FORMAT_MOD_ARM_AFBC(0)) From cbe59325cdde0ce5efe42c6f47d06e961711223c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 18:25:20 +0100 Subject: [PATCH 02/13] drm: Define DRM_FORMAT_MAX_PLANES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 279cc2e9543eb357c0ef299cf398b2e74a021f6b DRM uses a magic number of 4 for the maximum number of planes per color format. Declare this constant via DRM_FORMAT_MAX_PLANES and update the related code. Some code depends on the length of arrays that are now declared with DRM_FORMAT_MAX_PLANES. Convert it from '4' to ARRAY_SIZE. v2: * mention usage of ARRAY_SIZE() in the commit message (Maxime) * also fix error handling in drm_gem_fb_init_with_funcs() (kernel test robot) * include for DRM_FORMAT_MAX_PLANES Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-2-tzimmermann@suse.de (cherry picked from commit 279cc2e9543eb357c0ef299cf398b2e74a021f6b) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 19 +++++++++++-------- include/drm/drm_fourcc.h | 13 +++++++++---- include/drm/drm_framebuffer.h | 8 ++++---- include/drm/drm_gem_atomic_helper.h | 3 ++- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 67bc9edc1d987..421e029a6b3e9 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -48,7 +48,7 @@ struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb, unsigned int plane) { - if (plane >= 4) + if (plane >= ARRAY_SIZE(fb->obj)) return NULL; return fb->obj[plane]; @@ -62,7 +62,8 @@ drm_gem_fb_init(struct drm_device *dev, struct drm_gem_object **obj, unsigned int num_planes, const struct drm_framebuffer_funcs *funcs) { - int ret, i; + unsigned int i; + int ret; drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); @@ -86,9 +87,9 @@ drm_gem_fb_init(struct drm_device *dev, */ void drm_gem_fb_destroy(struct drm_framebuffer *fb) { - int i; + size_t i; - for (i = 0; i < 4; i++) + for (i = 0; i < ARRAY_SIZE(fb->obj); i++) drm_gem_object_put(fb->obj[i]); drm_framebuffer_cleanup(fb); @@ -145,8 +146,9 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, const struct drm_framebuffer_funcs *funcs) { const struct drm_format_info *info; - struct drm_gem_object *objs[4]; - int ret, i; + struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES]; + unsigned int i; + int ret; info = drm_get_format_info(dev, mode_cmd); if (!info) { @@ -187,9 +189,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, return 0; err_gem_object_put: - for (i--; i >= 0; i--) + while (i > 0) { + --i; drm_gem_object_put(objs[i]); - + } return ret; } EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs); diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 3b138d4ae67e4..22aa64d07c790 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -25,6 +25,11 @@ #include #include +/** + * DRM_FORMAT_MAX_PLANES - maximum number of planes a DRM format can have + */ +#define DRM_FORMAT_MAX_PLANES 4u + /* * DRM formats are little endian. Define host endian variants for the * most common formats here, to reduce the #ifdefs needed in drivers. @@ -78,7 +83,7 @@ struct drm_format_info { * triplet @char_per_block, @block_w, @block_h for better * describing the pixel format. */ - u8 cpp[4]; + u8 cpp[DRM_FORMAT_MAX_PLANES]; /** * @char_per_block: @@ -104,7 +109,7 @@ struct drm_format_info { * information from their drm_mode_config.get_format_info hook * if they want the core to be validating the pitch. */ - u8 char_per_block[4]; + u8 char_per_block[DRM_FORMAT_MAX_PLANES]; }; /** @@ -113,7 +118,7 @@ struct drm_format_info { * Block width in pixels, this is intended to be accessed through * drm_format_info_block_width() */ - u8 block_w[4]; + u8 block_w[DRM_FORMAT_MAX_PLANES]; /** * @block_h: @@ -121,7 +126,7 @@ struct drm_format_info { * Block height in pixels, this is intended to be accessed through * drm_format_info_block_height() */ - u8 block_h[4]; + u8 block_h[DRM_FORMAT_MAX_PLANES]; /** @hsub: Horizontal chroma subsampling factor */ u8 hsub; diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index be658ebbec72b..f67c5b7bcb686 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -27,12 +27,12 @@ #include #include +#include #include struct drm_clip_rect; struct drm_device; struct drm_file; -struct drm_format_info; struct drm_framebuffer; struct drm_gem_object; @@ -147,7 +147,7 @@ struct drm_framebuffer { * @pitches: Line stride per buffer. For userspace created object this * is copied from drm_mode_fb_cmd2. */ - unsigned int pitches[4]; + unsigned int pitches[DRM_FORMAT_MAX_PLANES]; /** * @offsets: Offset from buffer start to the actual pixel data in bytes, * per buffer. For userspace created object this is copied from @@ -165,7 +165,7 @@ struct drm_framebuffer { * data (even for linear buffers). Specifying an x/y pixel offset is * instead done through the source rectangle in &struct drm_plane_state. */ - unsigned int offsets[4]; + unsigned int offsets[DRM_FORMAT_MAX_PLANES]; /** * @modifier: Data layout modifier. This is used to describe * tiling, or also special layouts (like compression) of auxiliary @@ -210,7 +210,7 @@ struct drm_framebuffer { * This is used by the GEM framebuffer helpers, see e.g. * drm_gem_fb_create(). */ - struct drm_gem_object *obj[4]; + struct drm_gem_object *obj[DRM_FORMAT_MAX_PLANES]; }; #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index cfc5adee3d133..09445ebd93f53 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -5,6 +5,7 @@ #include +#include #include struct drm_simple_display_pipe; @@ -40,7 +41,7 @@ struct drm_shadow_plane_state { * The memory mappings stored in map should be established in the plane's * prepare_fb callback and removed in the cleanup_fb callback. */ - struct dma_buf_map map[4]; + struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; }; /** From 5620d67fa35ccdf6031a76fc8b231ba8c9943b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 18:26:36 +0100 Subject: [PATCH 03/13] drm/gem: Provide drm_gem_fb_{vmap,vunmap}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit f6424ecdb3c8aba18997a6992f780ab9c27734bc Move framebuffer vmap code from shadow-buffered plane state into the new interfaces drm_gem_fb_vmap() and drm_gem_fb_vunmap(). These functions provide mappings of a framebuffer's BOs into kernel address space. No functional changes. v4: * remove duplicated blank line v2: * using [static N] for array parameters enables compile-time checks * include for DRM_FORMAT_MAX_PLANES (kernel test robot) Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-3-tzimmermann@suse.de (cherry picked from commit f6424ecdb3c8aba18997a6992f780ab9c27734bc) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_atomic_helper.c | 35 +--------- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 72 ++++++++++++++++++++ include/drm/drm_gem_framebuffer_helper.h | 6 ++ 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index a27135084ae5c..1fbf9380cbd40 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -278,10 +278,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p { struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; - struct drm_gem_object *obj; - struct dma_buf_map map; int ret; - size_t i; if (!fb) return 0; @@ -290,27 +287,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p if (ret) return ret; - for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) { - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - ret = drm_gem_vmap(obj, &map); - if (ret) - goto err_drm_gem_vunmap; - shadow_plane_state->map[i] = map; - } - - return 0; - -err_drm_gem_vunmap: - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - drm_gem_vunmap(obj, &shadow_plane_state->map[i]); - } - return ret; + return drm_gem_fb_vmap(fb, shadow_plane_state->map); } EXPORT_SYMBOL(drm_gem_prepare_shadow_fb); @@ -328,19 +305,11 @@ void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state * { struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; - size_t i = ARRAY_SIZE(shadow_plane_state->map); - struct drm_gem_object *obj; if (!fb) return; - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - drm_gem_vunmap(obj, &shadow_plane_state->map[i]); - } + drm_gem_fb_vunmap(fb, shadow_plane_state->map); } EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 421e029a6b3e9..2bc0605c8bcad 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -15,6 +15,8 @@ #include #include +#include "drm_internal.h" + #define AFBC_HEADER_SIZE 16 #define AFBC_TH_LAYOUT_ALIGNMENT 8 #define AFBC_HDR_ALIGN 64 @@ -309,6 +311,76 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, } EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); +/** + * drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space + * @fb: the framebuffer + * @map: returns the mapping's address for each BO + * + * This function maps all buffer objects of the given framebuffer into + * kernel address space and stores them in struct dma_buf_map. If the + * mapping operation fails for one of the BOs, the function unmaps the + * already established mappings automatically. + * + * See drm_gem_fb_vunmap() for unmapping. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_fb_vmap(struct drm_framebuffer *fb, + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]) +{ + struct drm_gem_object *obj; + unsigned int i; + int ret; + + for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + ret = drm_gem_vmap(obj, &map[i]); + if (ret) + goto err_drm_gem_vunmap; + } + + return 0; + +err_drm_gem_vunmap: + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + drm_gem_vunmap(obj, &map[i]); + } + return ret; +} +EXPORT_SYMBOL(drm_gem_fb_vmap); + +/** + * drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space + * @fb: the framebuffer + * @map: mapping addresses as returned by drm_gem_fb_vmap() + * + * This function unmaps all buffer objects of the given framebuffer. + * + * See drm_gem_fb_vmap() for more information. + */ +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]) +{ + unsigned int i = DRM_FORMAT_MAX_PLANES; + struct drm_gem_object *obj; + + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + drm_gem_vunmap(obj, &map[i]); + } +} +EXPORT_SYMBOL(drm_gem_fb_vunmap); + /** * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access * @fb: the framebuffer diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 5705722f0855a..ff2024dd7b77c 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -4,6 +4,8 @@ #include #include +#include + struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -37,6 +39,10 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +int drm_gem_fb_vmap(struct drm_framebuffer *fb, + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); From 839849912421ceb6dfa2bdc9669e216ade41ea0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 18:28:12 +0100 Subject: [PATCH 04/13] drm/gem: Clear mapping addresses for unused framebuffer planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 0ec77bd92b513aa4e556e5b92ccd993677d21cbc Set the returned mapping address to NULL if a framebuffer plane does not have a BO associated with it. Likewise, ignore mappings of NULL during framebuffer unmap operations. Allows users of the functions to perform unmap operations of certain BOs by themselfes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-4-tzimmermann@suse.de (cherry picked from commit 0ec77bd92b513aa4e556e5b92ccd993677d21cbc) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 2bc0605c8bcad..5731a6a1dfa5f 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -335,8 +335,10 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { obj = drm_gem_fb_get_obj(fb, i); - if (!obj) + if (!obj) { + dma_buf_map_clear(&map[i]); continue; + } ret = drm_gem_vmap(obj, &map[i]); if (ret) goto err_drm_gem_vunmap; @@ -376,6 +378,8 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, obj = drm_gem_fb_get_obj(fb, i); if (!obj) continue; + if (dma_buf_map_is_null(&map[i])) + continue; drm_gem_vunmap(obj, &map[i]); } } From 23bce07c14a56f2b73fc970690ed387a04716078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 18:44:01 +0100 Subject: [PATCH 05/13] drm/gud: Map framebuffer BOs with drm_gem_fb_vmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 0029d3182969d8dc67e4fedb00d6cf50eee74670 upstream-diff Included drm/drm_gem_framebuffer_helper.h which was incorporated in 08b7ef0524f52cfd7f247270e0f95480709f210a on upstream, not backported to LTS 8.6. It was needed for the newly used functions `drm_gem_fb_vmap()' and `drm_gem_fb_vunmap()' Abstract the framebuffer details by mapping its BOs with a call to drm_gem_fb_vmap(). Unmap with drm_gem_fb_vunmap(). The call to drm_gem_fb_vmap() ensures that all BOs are mapped correctly. Gud still only supports single-plane formats. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Noralf Trønnes Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-5-tzimmermann@suse.de (cherry picked from commit 0029d3182969d8dc67e4fedb00d6cf50eee74670) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/gud/gud_pipe.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 2f83ab6b8e61c..d4f6129ebdbf0 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -15,7 +15,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -139,7 +140,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, { struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach; u8 compression = gdrm->compression; - struct dma_buf_map map; + struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; void *vaddr, *buf; size_t pitch, len; int ret = 0; @@ -149,11 +150,11 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, if (len > gdrm->bulk_len) return -E2BIG; - ret = drm_gem_shmem_vmap(fb->obj[0], &map); + ret = drm_gem_fb_vmap(fb, map); if (ret) return ret; - vaddr = map.vaddr + fb->offsets[0]; + vaddr = map[0].vaddr + fb->offsets[0]; if (import_attach) { ret = dma_buf_begin_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE); @@ -215,7 +216,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, if (import_attach) dma_buf_end_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE); vunmap: - drm_gem_shmem_vunmap(fb->obj[0], &map); + drm_gem_fb_vunmap(fb, map); return ret; } From 1b6de45eb2d9c1b245e8929d749c4e5eb6db6576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 19:00:43 +0100 Subject: [PATCH 06/13] drm/vkms: Map output framebuffer BOs with drm_gem_fb_vmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 50fff206c5e3a04fcb239ad58d89cad166711b7f upstream-diff Included drm/drm_gem_atomic_helper.h in drivers/gpu/drm/vkms/vkms_drv.h, which was done on upstream in 7602d4221842c12777363591df04672e2c8b6a61, not backported to LTS 8.6. It was needed for the definition of `dma_buf_map'. Abstract the framebuffer details by mappings its BOs with a call to drm_gem_fb_vmap(). Unmap with drm_gem_fb_vunamp(). Before, the output address with stored as raw pointer in the priv field of struct drm_writeback_job. Introduce the new type struct vkms_writeback_job, which holds the output mappings addresses while the writeback job is active. The patchset also cleans up some internal casting an setup of the output addresses. No functional changes. v3: * free instances of struct vkms_writeback_job on cleanup or errors Signed-off-by: Thomas Zimmermann Reviewed-by: Rodrigo Siqueira Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-6-tzimmermann@suse.de (cherry picked from commit 50fff206c5e3a04fcb239ad58d89cad166711b7f) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/vkms/vkms_composer.c | 2 +- drivers/gpu/drm/vkms/vkms_drv.h | 7 ++++++- drivers/gpu/drm/vkms/vkms_writeback.c | 28 +++++++++++++++------------ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index e49523866e1d4..a30d81727084f 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -259,7 +259,7 @@ void vkms_composer_worker(struct work_struct *work) return; if (wb_pending) - vaddr_out = crtc_state->active_writeback; + vaddr_out = crtc_state->active_writeback->map[0].vaddr; ret = compose_active_planes(&vaddr_out, primary_composer, crtc_state); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index ac8c9c2fa4ed9..d5d622d680a8e 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -19,6 +20,10 @@ #define XRES_MAX 8192 #define YRES_MAX 8192 +struct vkms_writeback_job { + struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; +}; + struct vkms_composer { struct drm_framebuffer fb; struct drm_rect src, dst; @@ -55,7 +60,7 @@ struct vkms_crtc_state { int num_active_planes; /* stack of active planes for crc computation, should be in z order */ struct vkms_plane_state **active_planes; - void *active_writeback; + struct vkms_writeback_job *active_writeback; /* below four are protected by vkms_output.composer_lock */ bool crc_pending; diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 0935686475a01..425b6c6b8cad8 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -65,41 +65,45 @@ static int vkms_wb_connector_get_modes(struct drm_connector *connector) static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector, struct drm_writeback_job *job) { - struct drm_gem_object *gem_obj; - struct dma_buf_map map; + struct vkms_writeback_job *vkmsjob; int ret; if (!job->fb) return 0; - gem_obj = drm_gem_fb_get_obj(job->fb, 0); - ret = drm_gem_shmem_vmap(gem_obj, &map); + vkmsjob = kzalloc(sizeof(*vkmsjob), GFP_KERNEL); + if (!vkmsjob) + return -ENOMEM; + + ret = drm_gem_fb_vmap(job->fb, vkmsjob->map); if (ret) { DRM_ERROR("vmap failed: %d\n", ret); - return ret; + goto err_kfree; } - job->priv = map.vaddr; + job->priv = vkmsjob; return 0; + +err_kfree: + kfree(vkmsjob); + return ret; } static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector, struct drm_writeback_job *job) { - struct drm_gem_object *gem_obj; + struct vkms_writeback_job *vkmsjob = job->priv; struct vkms_device *vkmsdev; - struct dma_buf_map map; if (!job->fb) return; - gem_obj = drm_gem_fb_get_obj(job->fb, 0); - dma_buf_map_set_vaddr(&map, job->priv); - drm_gem_shmem_vunmap(gem_obj, &map); + drm_gem_fb_vunmap(job->fb, vkmsjob->map); - vkmsdev = drm_device_to_vkms_device(gem_obj->dev); + vkmsdev = drm_device_to_vkms_device(job->fb->dev); vkms_set_composer(&vkmsdev->output, false); + kfree(vkmsjob); } static void vkms_wb_atomic_commit(struct drm_connector *conn, From e2687dd68fa2431635fa775f0f98ba8de14637a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 19:05:33 +0100 Subject: [PATCH 07/13] drm/gem: Provide offset-adjusted framebuffer BO mappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 43b36232ded23ce943224df3d1451f981446ae23 Add an additional argument to drm_gem_fb_vmap() to return each BO's mapping adjusted by the respective offset. Update all callers. The newly returned values point to the first byite of the data stored in the framebuffer BOs. Drivers that access the BO data should use it. Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210803125928.27780-2-tzimmermann@suse.de (cherry picked from commit 43b36232ded23ce943224df3d1451f981446ae23) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_atomic_helper.c | 2 +- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 17 ++++++++++++++++- drivers/gpu/drm/gud/gud_pipe.c | 2 +- drivers/gpu/drm/vkms/vkms_writeback.c | 2 +- include/drm/drm_gem_atomic_helper.h | 8 ++++++++ include/drm/drm_gem_framebuffer_helper.h | 3 ++- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 1fbf9380cbd40..84e6023551e33 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -287,7 +287,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p if (ret) return ret; - return drm_gem_fb_vmap(fb, shadow_plane_state->map); + return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data); } EXPORT_SYMBOL(drm_gem_prepare_shadow_fb); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 5731a6a1dfa5f..3c75d79dbb651 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -315,19 +315,25 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space * @fb: the framebuffer * @map: returns the mapping's address for each BO + * @data: returns the data address for each BO, can be NULL * * This function maps all buffer objects of the given framebuffer into * kernel address space and stores them in struct dma_buf_map. If the * mapping operation fails for one of the BOs, the function unmaps the * already established mappings automatically. * + * Callers that want to access a BO's stored data should pass @data. + * The argument returns the addresses of the data stored in each BO. This + * is different from @map if the framebuffer's offsets field is non-zero. + * * See drm_gem_fb_vunmap() for unmapping. * * Returns: * 0 on success, or a negative errno code otherwise. */ int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]) + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], + struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]) { struct drm_gem_object *obj; unsigned int i; @@ -344,6 +350,15 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, goto err_drm_gem_vunmap; } + if (data) { + for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + memcpy(&data[i], &map[i], sizeof(data[i])); + if (dma_buf_map_is_null(&data[i])) + continue; + dma_buf_map_incr(&data[i], fb->offsets[i]); + } + } + return 0; err_drm_gem_vunmap: diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index d4f6129ebdbf0..b270a82d58915 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -150,7 +150,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, if (len > gdrm->bulk_len) return -E2BIG; - ret = drm_gem_fb_vmap(fb, map); + ret = drm_gem_fb_vmap(fb, map, NULL); if (ret) return ret; diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 425b6c6b8cad8..3a8e2ed93e7c6 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -75,7 +75,7 @@ static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector, if (!vkmsjob) return -ENOMEM; - ret = drm_gem_fb_vmap(job->fb, vkmsjob->map); + ret = drm_gem_fb_vmap(job->fb, vkmsjob->map, NULL); if (ret) { DRM_ERROR("vmap failed: %d\n", ret); goto err_kfree; diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index 09445ebd93f53..ac026314f679e 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -42,6 +42,14 @@ struct drm_shadow_plane_state { * prepare_fb callback and removed in the cleanup_fb callback. */ struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; + + /** + * @data: Address of each framebuffer BO's data + * + * The address of the data stored in each mapping. This is different + * for framebuffers with non-zero offset fields. + */ + struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; }; /** diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index ff2024dd7b77c..905727719ead3 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -40,7 +40,8 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); + struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], + struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]); void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); From 053c2ee69a129790b9fae73b4801cbbc952237bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 18:29:23 +0100 Subject: [PATCH 08/13] drm/gem: Share code between drm_gem_fb_{begin,end}_cpu_access() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit f159b1b22c8a2d3d7c1fa877fafc8aacff0deeba The error-recovery code in drm_gem_fb_begin() is of the same pattern as drm_gem_fb_end(). Implement both of them using an internal helper. No functional changes. v2: * print additional information in error message (Javier) * fix commit description (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-2-tzimmermann@suse.de (cherry picked from commit f159b1b22c8a2d3d7c1fa877fafc8aacff0deeba) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 3c75d79dbb651..a4a98c607c758 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -400,6 +400,28 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_gem_fb_vunmap); +static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir, + unsigned int num_planes) +{ + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + int ret; + + while (num_planes) { + --num_planes; + obj = drm_gem_fb_get_obj(fb, num_planes); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret) + drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n", + ret, num_planes, dir); + } +} + /** * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access * @fb: the framebuffer @@ -419,7 +441,7 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct struct dma_buf_attachment *import_attach; struct drm_gem_object *obj; size_t i; - int ret, ret2; + int ret; for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { obj = drm_gem_fb_get_obj(fb, i); @@ -430,28 +452,13 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct continue; ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir); if (ret) - goto err_dma_buf_end_cpu_access; + goto err___drm_gem_fb_end_cpu_access; } return 0; -err_dma_buf_end_cpu_access: - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - import_attach = obj->import_attach; - if (!import_attach) - continue; - ret2 = dma_buf_end_cpu_access(import_attach->dmabuf, dir); - if (ret2) { - drm_err(fb->dev, - "dma_buf_end_cpu_access() failed during error handling: %d\n", - ret2); - } - } - +err___drm_gem_fb_end_cpu_access: + __drm_gem_fb_end_cpu_access(fb, dir, i); return ret; } EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); @@ -469,23 +476,7 @@ EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); */ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) { - size_t i = ARRAY_SIZE(fb->obj); - struct dma_buf_attachment *import_attach; - struct drm_gem_object *obj; - int ret; - - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - import_attach = obj->import_attach; - if (!import_attach) - continue; - ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); - if (ret) - drm_err(fb->dev, "dma_buf_end_cpu_access() failed: %d\n", ret); - } + __drm_gem_fb_end_cpu_access(fb, dir, ARRAY_SIZE(fb->obj)); } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); From 3690f57d9b07ff7a9f783b5f342d4039093de4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 19:33:40 +0100 Subject: [PATCH 09/13] drm/gem: Ignore color planes that are unused by framebuffer format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-pre CVE-2025-38449 commit-author Thomas Zimmermann commit 746b9c62cc8614fa59c23f3332682b5e9e1d801c upstream-diff | drivers/gpu/drm/drm_gem_atomic_helper.c Ignored the change to `drm_gem_plane_helper_prepare_fb()' function. They are relevant to the functional change introduced in 1ea28bc5542d607ff7c806e409a72862c5af8f5e ("drm: handle kernel fences in drm_gem_plane_helper_prepare_fb v2"), which is missing from LTS 8.6 drivers/gpu/drm/drm_gem_framebuffer_helper.c Used the existing `dma_buf_map' name of the struct instead of `iosys_map'. The struct renaming was done in 7938f4218168ae9fc4bdddb15976f9ebbae41999 ("dma-buf-map: Rename to iosys-map"), missing from LTS 8.6. It cannot be backported due to its scope, also the change it introduces is purely syntactic and can be corrected for easily. include/drm/drm_gem_framebuffer_helper.h Same as above. Only handle color planes that exist in a framebuffer's color format. Ignore non-existing planes. So far, several helpers assumed that all 4 planes are available and silently ignored non-existing planes. This lead to subtil bugs with uninitialized data in instances of struct iosys_map. [1] Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://lore.kernel.org/dri-devel/20210730183511.20080-1-tzimmermann@suse.de/T/#md0172b10bb588d8f20f4f456e304f08d2a4505f7 # 1 Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-3-tzimmermann@suse.de (cherry picked from commit 746b9c62cc8614fa59c23f3332682b5e9e1d801c) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 37 +++++++++++--------- include/drm/drm_gem_framebuffer_helper.h | 10 ++---- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index a4a98c607c758..7005b00b5475a 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -89,9 +89,9 @@ drm_gem_fb_init(struct drm_device *dev, */ void drm_gem_fb_destroy(struct drm_framebuffer *fb) { - size_t i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(fb->obj); i++) + for (i = 0; i < fb->format->num_planes; i++) drm_gem_object_put(fb->obj[i]); drm_framebuffer_cleanup(fb); @@ -326,24 +326,26 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * The argument returns the addresses of the data stored in each BO. This * is different from @map if the framebuffer's offsets field is non-zero. * + * Both, @map and @data, must each refer to arrays with at least + * fb->format->num_planes elements. + * * See drm_gem_fb_vunmap() for unmapping. * * Returns: * 0 on success, or a negative errno code otherwise. */ -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]) +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct dma_buf_map *map, + struct dma_buf_map *data) { struct drm_gem_object *obj; unsigned int i; int ret; - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); if (!obj) { - dma_buf_map_clear(&map[i]); - continue; + ret = -EINVAL; + goto err_drm_gem_vunmap; } ret = drm_gem_vmap(obj, &map[i]); if (ret) @@ -351,7 +353,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, } if (data) { - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { memcpy(&data[i], &map[i], sizeof(data[i])); if (dma_buf_map_is_null(&data[i])) continue; @@ -382,10 +384,9 @@ EXPORT_SYMBOL(drm_gem_fb_vmap); * * See drm_gem_fb_vmap() for more information. */ -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]) +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct dma_buf_map *map) { - unsigned int i = DRM_FORMAT_MAX_PLANES; + unsigned int i = fb->format->num_planes; struct drm_gem_object *obj; while (i) { @@ -440,13 +441,15 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct { struct dma_buf_attachment *import_attach; struct drm_gem_object *obj; - size_t i; + unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; + if (!obj) { + ret = -EINVAL; + goto err___drm_gem_fb_end_cpu_access; + } import_attach = obj->import_attach; if (!import_attach) continue; @@ -476,7 +479,7 @@ EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); */ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) { - __drm_gem_fb_end_cpu_access(fb, dir, ARRAY_SIZE(fb->obj)); + __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes); } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 905727719ead3..dd8249668a241 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -4,8 +4,6 @@ #include #include -#include - struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -39,11 +37,9 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]); -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct dma_buf_map *map, + struct dma_buf_map *data); +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct dma_buf_map *map); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); From 4281100bfce6845dcb7f12a0d817969bd1a690f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Tue, 17 Mar 2026 17:13:52 +0100 Subject: [PATCH 10/13] drm/gem: Acquire references on GEM handles for framebuffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve CVE-2025-38449 commit-author Thomas Zimmermann commit 5307dce878d4126e1b375587318955bd019c3741 upstream-diff In `drm_gem_object_handle_get_unlocked()' used `mutex_lock()' and `mutex_unlock()' instead of `guard()' - it was introduced in 54da6a0924311c7cf5015533991e44fb8eb12773 ("locking: Introduce __cleanup() based infrastructure"), not backported to LTS 8.6. A GEM handle can be released while the GEM buffer object is attached to a DRM framebuffer. This leads to the release of the dma-buf backing the buffer object, if any. [1] Trying to use the framebuffer in further mode-setting operations leads to a segmentation fault. Most easily happens with driver that use shadow planes for vmap-ing the dma-buf during a page flip. An example is shown below. [ 156.791968] ------------[ cut here ]------------ [ 156.796830] WARNING: CPU: 2 PID: 2255 at drivers/dma-buf/dma-buf.c:1527 dma_buf_vmap+0x224/0x430 [...] [ 156.942028] RIP: 0010:dma_buf_vmap+0x224/0x430 [ 157.043420] Call Trace: [ 157.045898] [ 157.048030] ? show_trace_log_lvl+0x1af/0x2c0 [ 157.052436] ? show_trace_log_lvl+0x1af/0x2c0 [ 157.056836] ? show_trace_log_lvl+0x1af/0x2c0 [ 157.061253] ? drm_gem_shmem_vmap+0x74/0x710 [ 157.065567] ? dma_buf_vmap+0x224/0x430 [ 157.069446] ? __warn.cold+0x58/0xe4 [ 157.073061] ? dma_buf_vmap+0x224/0x430 [ 157.077111] ? report_bug+0x1dd/0x390 [ 157.080842] ? handle_bug+0x5e/0xa0 [ 157.084389] ? exc_invalid_op+0x14/0x50 [ 157.088291] ? asm_exc_invalid_op+0x16/0x20 [ 157.092548] ? dma_buf_vmap+0x224/0x430 [ 157.096663] ? dma_resv_get_singleton+0x6d/0x230 [ 157.101341] ? __pfx_dma_buf_vmap+0x10/0x10 [ 157.105588] ? __pfx_dma_resv_get_singleton+0x10/0x10 [ 157.110697] drm_gem_shmem_vmap+0x74/0x710 [ 157.114866] drm_gem_vmap+0xa9/0x1b0 [ 157.118763] drm_gem_vmap_unlocked+0x46/0xa0 [ 157.123086] drm_gem_fb_vmap+0xab/0x300 [ 157.126979] drm_atomic_helper_prepare_planes.part.0+0x487/0xb10 [ 157.133032] ? lockdep_init_map_type+0x19d/0x880 [ 157.137701] drm_atomic_helper_commit+0x13d/0x2e0 [ 157.142671] ? drm_atomic_nonblocking_commit+0xa0/0x180 [ 157.147988] drm_mode_atomic_ioctl+0x766/0xe40 [...] [ 157.346424] ---[ end trace 0000000000000000 ]--- Acquiring GEM handles for the framebuffer's GEM buffer objects prevents this from happening. The framebuffer's cleanup later puts the handle references. Commit 1a148af06000 ("drm/gem-shmem: Use dma_buf from GEM object instance") triggers the segmentation fault easily by using the dma-buf field more widely. The underlying issue with reference counting has been present before. v2: - acquire the handle instead of the BO (Christian) - fix comment style (Christian) - drop the Fixes tag (Christian) - rename err_ gotos - add missing Link tag Suggested-by: Christian König Signed-off-by: Thomas Zimmermann Link: https://elixir.bootlin.com/linux/v6.15/source/drivers/gpu/drm/drm_gem.c#L241 # [1] Cc: Thomas Zimmermann Cc: Anusha Srivatsa Cc: Christian König Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Cc: Reviewed-by: Christian König Link: https://lore.kernel.org/r/20250630084001.293053-1-tzimmermann@suse.de (cherry picked from commit 5307dce878d4126e1b375587318955bd019c3741) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_gem.c | 46 ++++++++++++++++++-- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 ++++--- drivers/gpu/drm/drm_internal.h | 2 + 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index d62fb1a3c9167..4d0e897d8c854 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -182,6 +182,37 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) mutex_unlock(&filp->prime.lock); } +static void drm_gem_object_handle_get(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + + drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock)); + + if (obj->handle_count++ == 0) + drm_gem_object_get(obj); +} + +/** + * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles + * @obj: GEM object + * + * Acquires a reference on the GEM buffer object's handle. Required + * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked() + * to release the reference. + */ +void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + + mutex_lock(&dev->object_name_lock); + + drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */ + drm_gem_object_handle_get(obj); + + mutex_unlock(&dev->object_name_lock); +} +EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked); + /** * drm_gem_object_handle_free - release resources bound to userspace handles * @obj: GEM object to clean up. @@ -212,8 +243,14 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj) } } -static void -drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) +/** + * drm_gem_object_handle_put_unlocked - releases reference on user-space handles + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases + * the GEM buffer object and associated dma-buf objects. + */ +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; bool final = false; @@ -238,6 +275,7 @@ drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) if (final) drm_gem_object_put(obj); } +EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked); /* * Called at device or object close to release the file's @@ -366,8 +404,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, int ret; WARN_ON(!mutex_is_locked(&dev->object_name_lock)); - if (obj->handle_count++ == 0) - drm_gem_object_get(obj); + + drm_gem_object_handle_get(obj); /* * Get the user-visible handle using idr. Preload and perform diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 7005b00b5475a..100016c3fb7b5 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -92,7 +92,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb) unsigned int i; for (i = 0; i < fb->format->num_planes; i++) - drm_gem_object_put(fb->obj[i]); + drm_gem_object_handle_put_unlocked(fb->obj[i]); drm_framebuffer_cleanup(fb); kfree(fb); @@ -167,8 +167,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, if (!objs[i]) { drm_dbg_kms(dev, "Failed to lookup GEM object\n"); ret = -ENOENT; - goto err_gem_object_put; + goto err_gem_object_handle_put_unlocked; } + drm_gem_object_handle_get_unlocked(objs[i]); + drm_gem_object_put(objs[i]); min_size = (height - 1) * mode_cmd->pitches[i] + drm_format_info_min_pitch(info, i, width) @@ -178,22 +180,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, drm_dbg_kms(dev, "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n", objs[i]->size, min_size, i); - drm_gem_object_put(objs[i]); + drm_gem_object_handle_put_unlocked(objs[i]); ret = -EINVAL; - goto err_gem_object_put; + goto err_gem_object_handle_put_unlocked; } } ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); if (ret) - goto err_gem_object_put; + goto err_gem_object_handle_put_unlocked; return 0; -err_gem_object_put: +err_gem_object_handle_put_unlocked: while (i > 0) { --i; - drm_gem_object_put(objs[i]); + drm_gem_object_handle_put_unlocked(objs[i]); } return ret; } diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 17f3548c8ed25..a8ef6f7a40aa7 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -158,6 +158,8 @@ void drm_sysfs_lease_event(struct drm_device *dev); /* drm_gem.c */ int drm_gem_init(struct drm_device *dev); +void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj); +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj); int drm_gem_handle_create_tail(struct drm_file *file_priv, struct drm_gem_object *obj, u32 *handlep); From 8e84f01240da50f981615102491436aa12f09965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Wcis=C5=82o?= Date: Mon, 7 Jul 2025 15:11:55 +0200 Subject: [PATCH 11/13] drm/framebuffer: Acquire internal references on GEM handles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jira VULN-136703 cve-bf CVE-2025-38449 commit-author Thomas Zimmermann commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280 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 bce3dab7eb6ee596388699e8a052a7d58954c472. 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 5307dce878d4 ("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 Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers") Reported-by: Bert Karwatzki Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/ Tested-by: Bert Karwatzki Tested-by: Mario Limonciello Tested-by: Borislav Petkov (AMD) Cc: Thomas Zimmermann Cc: Anusha Srivatsa Cc: Christian König Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Sumit Semwal Cc: "Christian König" Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Cc: Reviewed-by: Christian König Link: https://lore.kernel.org/r/20250707131224.249496-1-tzimmermann@suse.de (cherry picked from commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280) Signed-off-by: Marcin Wcisło --- drivers/gpu/drm/drm_framebuffer.c | 31 ++++++++++++++- drivers/gpu/drm/drm_gem.c | 41 +++++++++++++------- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 ++++---- drivers/gpu/drm/drm_internal.h | 2 +- include/drm/drm_framebuffer.h | 7 ++++ 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 4d01464b6f950..0700f8699d73e 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -841,11 +841,23 @@ void drm_framebuffer_free(struct kref *kref) int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs) { + unsigned int i; int ret; + bool exists; if (WARN_ON_ONCE(fb->dev != dev || !fb->format)) return -EINVAL; + for (i = 0; i < fb->format->num_planes; i++) { + if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))) + fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + if (fb->obj[i]) { + exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]); + if (exists) + fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + } + } + INIT_LIST_HEAD(&fb->filp_head); fb->funcs = funcs; @@ -854,7 +866,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB, false, drm_framebuffer_free); if (ret) - goto out; + goto err; mutex_lock(&dev->mode_config.fb_lock); dev->mode_config.num_fb++; @@ -862,7 +874,16 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, mutex_unlock(&dev->mode_config.fb_lock); drm_mode_object_register(dev, &fb->base); -out: + + return 0; + +err: + for (i = 0; i < fb->format->num_planes; i++) { + if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) { + drm_gem_object_handle_put_unlocked(fb->obj[i]); + fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i); + } + } return ret; } EXPORT_SYMBOL(drm_framebuffer_init); @@ -939,6 +960,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; + unsigned int i; + + for (i = 0; i < fb->format->num_planes; i++) { + if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) + drm_gem_object_handle_put_unlocked(fb->obj[i]); + } mutex_lock(&dev->mode_config.fb_lock); list_del(&fb->head); diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4d0e897d8c854..55499e76df740 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -193,25 +193,39 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj) } /** - * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any * @obj: GEM object * - * Acquires a reference on the GEM buffer object's handle. Required - * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked() - * to release the reference. + * Acquires a reference on the GEM buffer object's handle. Required to keep + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() + * to release the reference. Does nothing if the buffer object has no handle. + * + * Returns: + * True if a handle exists, or false otherwise */ -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj) +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; mutex_lock(&dev->object_name_lock); - drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */ + /* + * First ref taken during GEM object creation, if any. Some + * drivers set up internal framebuffers with GEM objects that + * do not have a GEM handle. Hence, this counter can be zero. + */ + if (!obj->handle_count) { + mutex_unlock(&dev->object_name_lock); + return false; + } + drm_gem_object_handle_get(obj); mutex_unlock(&dev->object_name_lock); + + return true; } -EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked); + /** * 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) } /** - * drm_gem_object_handle_put_unlocked - releases reference on user-space handles + * drm_gem_object_handle_put_unlocked - releases reference on user-space handle * @obj: GEM object * * 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) struct drm_device *dev = obj->dev; bool final = false; - if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) + if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0)) return; /* - * Must bump handle count first as this may be the last - * ref, in which case the object would disappear before we - * checked for a name - */ + * Must bump handle count first as this may be the last + * ref, in which case the object would disappear before + * we checked for a name. + */ mutex_lock(&dev->object_name_lock); if (--obj->handle_count == 0) { @@ -275,7 +289,6 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) if (final) drm_gem_object_put(obj); } -EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked); /* * Called at device or object close to release the file's diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 100016c3fb7b5..7005b00b5475a 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -92,7 +92,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb) unsigned int i; for (i = 0; i < fb->format->num_planes; i++) - drm_gem_object_handle_put_unlocked(fb->obj[i]); + drm_gem_object_put(fb->obj[i]); drm_framebuffer_cleanup(fb); kfree(fb); @@ -167,10 +167,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, if (!objs[i]) { drm_dbg_kms(dev, "Failed to lookup GEM object\n"); ret = -ENOENT; - goto err_gem_object_handle_put_unlocked; + goto err_gem_object_put; } - drm_gem_object_handle_get_unlocked(objs[i]); - drm_gem_object_put(objs[i]); min_size = (height - 1) * mode_cmd->pitches[i] + drm_format_info_min_pitch(info, i, width) @@ -180,22 +178,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, drm_dbg_kms(dev, "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n", objs[i]->size, min_size, i); - drm_gem_object_handle_put_unlocked(objs[i]); + drm_gem_object_put(objs[i]); ret = -EINVAL; - goto err_gem_object_handle_put_unlocked; + goto err_gem_object_put; } } ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); if (ret) - goto err_gem_object_handle_put_unlocked; + goto err_gem_object_put; return 0; -err_gem_object_handle_put_unlocked: +err_gem_object_put: while (i > 0) { --i; - drm_gem_object_handle_put_unlocked(objs[i]); + drm_gem_object_put(objs[i]); } return ret; } diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index a8ef6f7a40aa7..f777ed3b6c455 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -158,7 +158,7 @@ void drm_sysfs_lease_event(struct drm_device *dev); /* drm_gem.c */ int drm_gem_init(struct drm_device *dev); -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj); +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj); void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj); int drm_gem_handle_create_tail(struct drm_file *file_priv, struct drm_gem_object *obj, diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index f67c5b7bcb686..013beb1a8723d 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -23,6 +23,7 @@ #ifndef __DRM_FRAMEBUFFER_H__ #define __DRM_FRAMEBUFFER_H__ +#include #include #include #include @@ -100,6 +101,8 @@ struct drm_framebuffer_funcs { unsigned num_clips); }; +#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i) BIT(0u + (_i)) + /** * struct drm_framebuffer - frame buffer object * @@ -188,6 +191,10 @@ struct drm_framebuffer { * DRM_MODE_FB_MODIFIERS. */ int flags; + /** + * @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF. + */ + unsigned int internal_flags; /** * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR From 2867a3d8c35d0a5eb6b7b6d8e625fc34c89df13a Mon Sep 17 00:00:00 2001 From: Roxana Nicolescu Date: Tue, 17 Mar 2026 11:28:03 +0100 Subject: [PATCH 12/13] github actions: Trigger kernelCI on pull request as well Since we now have a separate trigger for it, this has been renamed to match that. For the case where a PR was automatically created and there is been an update on the branch, both push and pr_request events are triggered. Only one is needed, therefore the second is automatically cancelled. Signed-off-by: Roxana Nicolescu --- ...ernel-build-and-test-multiarch-trigger.yml | 24 +++++++++++++++++++ .../kernel-build-and-test-multiarch.yml | 11 --------- 2 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/kernel-build-and-test-multiarch-trigger.yml delete mode 100644 .github/workflows/kernel-build-and-test-multiarch.yml diff --git a/.github/workflows/kernel-build-and-test-multiarch-trigger.yml b/.github/workflows/kernel-build-and-test-multiarch-trigger.yml new file mode 100644 index 0000000000000..8c817dde3b58c --- /dev/null +++ b/.github/workflows/kernel-build-and-test-multiarch-trigger.yml @@ -0,0 +1,24 @@ +name: Automated kernel build and test x86_64 and aarch64 + +on: + push: + branches: + - '*_ciqlts8_6' + pull_request: + types: [opened, synchronize, reopened] + branches: + - '**' + - '!mainline' + +concurrency: + group: kernel-ci-${{ github.event.pull_request.head.ref || github.ref_name }} + cancel-in-progress: true + +jobs: + kernelCI: + if: | + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name != github.repository || + github.event.action != 'opened' + uses: ctrliq/kernel-src-tree/.github/workflows/kernel-build-and-test-multiarch-trigger.yml@main + secrets: inherit diff --git a/.github/workflows/kernel-build-and-test-multiarch.yml b/.github/workflows/kernel-build-and-test-multiarch.yml deleted file mode 100644 index a1866feb95a36..0000000000000 --- a/.github/workflows/kernel-build-and-test-multiarch.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Automated kernel build and test x86_64 and aarch64 - -on: - push: - branches: - - '*_ciqlts8_6' - -jobs: - kernelCI: - uses: ctrliq/kernel-src-tree/.github/workflows/kernel-build-and-test-multiarch.yml@main - secrets: inherit From 299608e47e3f381ad2e4853fe54b312e2bf9550c Mon Sep 17 00:00:00 2001 From: Roxana Nicolescu Date: Thu, 26 Mar 2026 12:19:38 +0100 Subject: [PATCH 13/13] TEMPORARY: Use test branch -- round 2 Signed-off-by: Roxana Nicolescu --- .github/workflows/kernel-build-and-test-multiarch-trigger.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/kernel-build-and-test-multiarch-trigger.yml b/.github/workflows/kernel-build-and-test-multiarch-trigger.yml index 8c817dde3b58c..c5073073cb48b 100644 --- a/.github/workflows/kernel-build-and-test-multiarch-trigger.yml +++ b/.github/workflows/kernel-build-and-test-multiarch-trigger.yml @@ -20,5 +20,5 @@ jobs: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository || github.event.action != 'opened' - uses: ctrliq/kernel-src-tree/.github/workflows/kernel-build-and-test-multiarch-trigger.yml@main + uses: ctrliq/kernel-src-tree/.github/workflows/kernel-build-and-test-multiarch-trigger.yml@rnicolescu_test secrets: inherit