All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hui Peng <benquike@gmail.com>
To: zack.rusin@broadcom.com, airlied@redhat.com, tzimmermann@suse.de,
	simona@ffwll.ch
Cc: bcm-kernel-feedback-list@broadcom.com,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: [PATCH] drm/vmwgfx: fix surface size overflow, execbuf bounds, and cursor/msg leaks
Date: Sat, 19 Sep 2026 22:34:41 +0000	[thread overview]
Message-ID: <20260919223441.3884374-1-benquike@gmail.com> (raw)

Fix multiple integer overflows, out-of-bounds accesses, and resource
leaks across drivers/gpu/drm/vmwgfx/ (vmwgfx_surface.c,
vmwgfx_execbuf.c, vmwgfx_msg.c, vmwgfx_fence.c, vmwgfx_cursor_plane.c,
vmwgfx_cotable.c, vmwgfx_bo.c, and vmw_surface_cache.h).

Fixes: fb1d9738ca05 ("drm/vmwgfx: Add DRM driver for VMware Virtual GPU")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/drivers/gpu/drm/vmwgfx/vmw_surface_cache.h b/drivers/gpu/drm/vmwgfx/vmw_surface_cache.h
index 1ac3cb151b11..bc5f7facf728 100644
--- a/drivers/gpu/drm/vmwgfx/vmw_surface_cache.h
+++ b/drivers/gpu/drm/vmwgfx/vmw_surface_cache.h
@@ -100,7 +100,7 @@ vmw_surface_calculate_pitch(const SVGA3dSurfaceDesc *desc,
 
 	vmw_surface_get_size_in_blocks(desc, size, &blocks);
 
-	pitch = blocks.width * desc->pitchBytesPerBlock;
+	pitch = clamped_umul32(blocks.width, desc->pitchBytesPerBlock);
 
 	return pitch;
 }
@@ -159,11 +159,13 @@ vmw_surface_get_serialized_size(SVGA3dSurfaceFormat format,
 	for (mip = 0; mip < num_mip_levels; mip++) {
 		struct drm_vmw_size size =
 			vmw_surface_get_mip_size(base_level_size, mip);
-		total_size += vmw_surface_get_image_buffer_size(desc,
-								  &size, 0);
+		total_size = min_t(u64,
+			(u64)total_size +
+			vmw_surface_get_image_buffer_size(desc, &size, 0),
+			U32_MAX);
 	}
 
-	return total_size * num_layers;
+	return clamped_umul32(total_size, num_layers);
 }
 
 /**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 9c7a73c0b0dc..53b3ecfc476b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -535,7 +535,8 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp,
 
 	if (!ret) {
 		if (!(flags & drm_vmw_synccpu_allow_cs)) {
-			atomic_dec(&vmw_bo->cpu_writers);
+			if (!atomic_add_unless(&vmw_bo->cpu_writers, -1, 0))
+				ret = -EINVAL;
 		}
 		vmw_user_bo_unref(&vmw_bo);
 	}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
index 091f1039a052..4273be7ac1ac 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
@@ -481,6 +481,10 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
 		goto out_wait;
 	}
 
+	ret = dma_resv_reserve_fences(bo->base.resv, 1);
+	if (unlikely(ret))
+		goto out_wait;
+
 	vmw_resource_mob_detach(res);
 	res->guest_memory_bo = buf;
 	res->guest_memory_size = new_size;
@@ -505,10 +509,6 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
 	vmw_user_bo_unref(&old_buf);
 	res->id = vcotbl->type;
 
-	ret = dma_resv_reserve_fences(bo->base.resv, 1);
-	if (unlikely(ret))
-		goto out_wait;
-
 	/* Release the pin acquired in vmw_bo_create */
 	ttm_bo_unpin(bo);
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
index d1e7df500190..e6776ed6cfd4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
@@ -116,6 +116,12 @@ static void vmw_cursor_update_mob(struct vmw_private *vmw,
 	u32 *image = vmw_bo_map_and_cache(bo);
 	const u32 image_size = vps->base.crtc_w * vps->base.crtc_h * sizeof(*image);
 
+	if (!bo || !vps->cursor.mob)
+		return;
+	if (image_size > bo->tbo.base.size ||
+	    sizeof(*header) + image_size > vps->cursor.mob->tbo.base.size)
+		return;
+
 	header = vmw_bo_map_and_cache(vps->cursor.mob);
 	alpha_header = &header->header.alphaHeader;
 
@@ -359,7 +365,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
 	    box->x != 0    || box->y != 0    || box->z != 0    ||
 	    box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
 	    box->d != 1    || box_count != 1 ||
-	    box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) {
+	    box->w == 0    || box->h == 0    ||
+	    box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT ||
+	    cmd->dma.guest.pitch > image_pitch) {
 		/* TODO handle none page aligned offsets */
 		/* TODO handle more dst & src != 0 */
 		/* TODO handle more then one copy */
@@ -375,6 +383,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
 	kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
 	kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT;
 
+	if (bo->base.size < ((kmap_offset + kmap_num) << PAGE_SHIFT))
+		return;
+
 	ret = ttm_bo_reserve(bo, true, false, NULL);
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("reserve failed\n");
@@ -393,7 +404,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
 	} else {
 		/* Image is unsigned pointer. */
 		for (i = 0; i < box->h; i++)
-			memcpy(srf->snooper.image + i * image_pitch,
+			memcpy((u8 *)srf->snooper.image + i * image_pitch,
 			       virtual + i * cmd->dma.guest.pitch,
 			       box->w * desc->pitchBytesPerBlock);
 	}
@@ -548,7 +559,9 @@ vmw_cursor_buffer_changed(struct vmw_plane_state *new_vps,
 			old_image = vmw_bo_map_and_cache(old_bo);
 			new_image = vmw_bo_map_and_cache(new_bo);
 
-			if (old_image && new_image && old_image != new_image)
+			if (old_image && new_image && old_image != new_image &&
+			    size <= old_bo->tbo.base.size &&
+			    size <= new_bo->tbo.base.size)
 				changed = memcmp(old_image, new_image, size) !=
 					  0;
 
@@ -728,6 +741,14 @@ int vmw_cursor_plane_atomic_check(struct drm_plane *plane,
 	if (!fb)
 		return 0;
 
+	if (new_state->crtc_w <= 0 || new_state->crtc_h <= 0 ||
+	    new_state->crtc_w > vmw->fb_max_width ||
+	    new_state->crtc_h > vmw->fb_max_height) {
+		drm_warn(&vmw->drm, "Invalid cursor dimensions (%d, %d)\n",
+			 new_state->crtc_w, new_state->crtc_h);
+		return -EINVAL;
+	}
+
 	update_type = vmw_cursor_update_type(vmw, vps);
 	if (update_type == VMW_CURSOR_UPDATE_LEGACY) {
 		if (new_state->crtc_w != VMW_CURSOR_SNOOP_WIDTH ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index a9136a6523cb..92c12d6e98d6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1511,6 +1511,10 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
 
 	cmd = container_of(header, typeof(*cmd), header);
 
+	if (unlikely(header->size < sizeof(cmd->body) + sizeof(*suffix))) {
+		VMW_DEBUG_USER("Invalid DMA command size.\n");
+		return -EINVAL;
+	}
 	if (unlikely(header->size < sizeof(cmd->body) + sizeof(*suffix))) {
 		VMW_DEBUG_USER("Illegal SVGA_3D_CMD_SURFACE_DMA size.\n");
 		return -EINVAL;
@@ -1572,6 +1576,10 @@ static int vmw_cmd_draw(struct vmw_private *dev_priv,
 	VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDrawPrimitives);
 	SVGA3dVertexDecl *decl = (SVGA3dVertexDecl *)(
 		(unsigned long)header + sizeof(*cmd));
+	if (unlikely(header->size < sizeof(cmd->body))) {
+		VMW_DEBUG_USER("Draw command size too small.\n");
+		return -EINVAL;
+	}
 	SVGA3dPrimitiveRange *range;
 	uint32_t i;
 	uint32_t maxnum;
@@ -1931,6 +1939,11 @@ static int vmw_cmd_shader_define(struct vmw_private *dev_priv,
 	if (unlikely(!dev_priv->has_mob))
 		return 0;
 
+	if (unlikely(cmd->header.size < sizeof(cmd->body))) {
+		VMW_DEBUG_USER("Invalid shader define command size.\n");
+		return -EINVAL;
+	}
+
 	size = cmd->header.size - sizeof(cmd->body);
 	ret = vmw_compat_shader_add(dev_priv, vmw_context_res_man(ctx),
 				    cmd->body.shid, cmd + 1, cmd->body.type,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 384c6736cf6b..f8cabbe9868a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -703,6 +703,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
 			if (unlikely(ret != 0)) {
 				DRM_ERROR("Failed to reference a fence "
 					  "object.\n");
+				ttm_base_object_unref(&base);
 				goto out_no_ref_obj;
 			}
 			handle = base->handle;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
index fd77ab6568cb..f0f2dbb66cdc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
@@ -431,7 +431,7 @@ int vmw_host_get_guestinfo(const char *guest_info_param,
 		/* Remove reply code, which are the first 2 characters of
 		 * the reply
 		 */
-		reply_len = max(reply_len - 2, (size_t) 0);
+		reply_len = reply_len > 2 ? reply_len - 2 : 0;
 		reply_len = min(reply_len, *length);
 
 		if (reply_len > 0)
@@ -572,7 +572,8 @@ int vmw_msg_ioctl(struct drm_device *dev, void *data,
 			goto out_msg;
 		}
 		if (reply && reply_len > 0) {
-			if (copy_to_user((void __user *)((unsigned long)arg->receive),
+			if (reply_len > arg->receive_len ||
+			    copy_to_user((void __user *)((unsigned long)arg->receive),
 					 reply, reply_len)) {
 				DRM_ERROR("Failed to copy message to userspace.\n");
 				kfree(reply);
@@ -1045,7 +1046,7 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
 	hypervisor_ppn_add((PPN64)page_to_pfn(page));
 
 	dev_priv->mksstat_user_pages[slot] = page;
-	atomic_set(&dev_priv->mksstat_user_pids[slot], task_pgrp_vnr(current));
+	atomic_set(&dev_priv->mksstat_user_pids[slot], pid_nr(task_pgrp(current)));
 
 	arg->id = slot;
 
@@ -1104,7 +1105,7 @@ int vmw_mksstat_remove_ioctl(struct drm_device *dev, void *data,
 
 	DRM_DEV_INFO(dev->dev, "pid=%d arg.id=%zu\n", current->pid, slot);
 
-	pgid = task_pgrp_vnr(current);
+	pgid = pid_nr(task_pgrp(current));
 	pid = atomic_cmpxchg(&dev_priv->mksstat_user_pids[slot], pgid, MKSSTAT_PID_RESERVED);
 
 	if (!pid)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index bd0563741e89..0104e73b69de 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -785,14 +785,26 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
 
 	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
 		for (j = 0; j < metadata->mip_levels[i]; ++j) {
-			uint32_t stride = vmw_surface_calculate_pitch(
-						  desc, cur_size);
+			uint32_t stride;
 
+			if (unlikely(cur_size->width == 0 ||
+				     cur_size->height == 0 ||
+				     cur_size->depth == 0)) {
+				ret = -EINVAL;
+				goto out_no_copy;
+			}
+			stride = vmw_surface_calculate_pitch(desc, cur_size);
 			cur_offset->face = i;
 			cur_offset->mip = j;
 			cur_offset->bo_offset = cur_bo_offset;
-			cur_bo_offset += vmw_surface_get_image_buffer_size
-				(desc, cur_size, stride);
+			if (unlikely(check_add_overflow(cur_bo_offset,
+							vmw_surface_get_image_buffer_size(desc,
+											  cur_size,
+											  stride),
+							&cur_bo_offset))) {
+				ret = -EINVAL;
+				goto out_no_copy;
+			}
 			++cur_offset;
 			++cur_size;
 		}
@@ -967,12 +979,14 @@ static int vmw_buffer_prime_to_surface_base(struct vmw_private *dev_priv,
 	if (ret) {
 		drm_warn(&dev_priv->drm,
 			 "Couldn't add an object ref for the buffer (%d).\n", *handle);
+		ttm_base_object_unref(&base);
 		goto out;
 	}
 
 	*base_p = base;
 out:
 	vmw_user_bo_unref(&bo);
+	drm_gem_handle_delete(file_priv, *handle);
 
 	return ret;
 }
@@ -1440,7 +1454,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
 	    (union drm_vmw_gb_surface_reference_arg *)data;
 	struct drm_vmw_surface_arg *req = &arg->req;
 	struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep;
-	struct drm_vmw_gb_surface_ref_ext_rep rep_ext;
+	struct drm_vmw_gb_surface_ref_ext_rep rep_ext = {};
 	int ret;
 
 	ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv);
@@ -1720,6 +1734,7 @@ vmw_gb_surface_reference_internal(struct drm_device *dev,
 	srf = &user_srf->srf;
 	if (!srf->res.guest_memory_bo) {
 		DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
+		ret = -EINVAL;
 		goto out_bad_resource;
 	}
 	metadata = &srf->metadata;
@@ -1755,9 +1770,13 @@ vmw_gb_surface_reference_internal(struct drm_device *dev,
 		SVGA3D_FLAGS_UPPER_32(metadata->flags);
 	rep->creq.multisample_pattern = metadata->multisample_pattern;
 	rep->creq.quality_level = metadata->quality_level;
+	rep->creq.buffer_byte_stride = metadata->buffer_byte_stride;
 	rep->creq.must_be_zero = 0;
 
 out_bad_resource:
+	if (unlikely(ret != 0))
+		ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+					  base->handle);
 	ttm_base_object_unref(&base);
 
 	return ret;

             reply	other threads:[~2026-09-21  7:00 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-19 22:34 Hui Peng [this message]
2026-09-19 23:01 ` [PATCH] drm/vmwgfx: fix surface size overflow, execbuf bounds, and cursor/msg leaks sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260919223441.3884374-1-benquike@gmail.com \
    --to=benquike@gmail.com \
    --cc=airlied@redhat.com \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    --cc=zack.rusin@broadcom.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.