mirror of https://lore.kernel.org/lkml/
 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-19 22:34 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®