mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads
@ 2026-09-19 22:35 Hui Peng
  0 siblings, 0 replies; only message in thread
From: Hui Peng @ 2026-09-19 22:35 UTC (permalink / raw)
  To: rubenru09, tzimmermann, simona, airlied; +Cc: dri-devel, linux-kernel

In drivers/gpu/drm/gud/ (gud_drv.c, gud_pipe.c, gud_connector.c), ensure
gdrm->bulk_len >= max_pitch so lines = bulk_len / pitch cannot be 0 in
gud_flush_damage(), cap num_connectors to GUD_CONNECTORS_MAX, and reject
short USB control transfers in gud_usb_get().

Fixes: 40e1a70b4aed ("drm: Add GUD USB Display driver")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index 8141c3a1e30a..1bf0495bf43f 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -569,7 +569,7 @@ static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_conn
 			continue; /* not a DRM property */
 
 		property = gud_connector_property_lookup(connector, prop);
-		if (drm_WARN_ON(drm, IS_ERR(property)))
+		if (drm_WARN_ON(drm, IS_ERR_OR_NULL(property)))
 			continue;
 
 		state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index 3a1b9e2a2eaa..f69b0e6e2ee0 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -328,7 +328,7 @@ static int gud_stats_debugfs(struct seq_file *m, void *data)
 		seq_puts(m, " none");
 	seq_puts(m, "\n");
 
-	if (gdrm->compression) {
+	if (gdrm->compression && gdrm->stats_actual_length) {
 		u64 remainder;
 		u64 ratio = div64_u64_rem(gdrm->stats_length, gdrm->stats_actual_length,
 					  &remainder);
@@ -427,6 +427,8 @@ static void gud_free_buffers_and_mutex(void *data)
 {
 	struct gud_device *gdrm = data;
 
+	vfree(gdrm->shadow_buf);
+	gdrm->shadow_buf = NULL;
 	vfree(gdrm->compress_buf);
 	gdrm->compress_buf = NULL;
 	sg_free_table(&gdrm->bulk_sgt);
@@ -443,7 +445,7 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	struct usb_endpoint_descriptor *bulk_out;
 	struct gud_display_descriptor_req desc;
 	struct device *dev = &intf->dev;
-	size_t max_buffer_size = 0;
+	size_t max_buffer_size = 0, max_pitch = 0;
 	struct gud_device *gdrm;
 	struct drm_device *drm;
 	struct device *dma_dev;
@@ -495,6 +497,10 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
 		put_device(dma_dev);
 	} else {
 		dev_warn(dev, "buffer sharing not supported"); /* not an error */
+	if (!drm->mode_config.min_width || !drm->mode_config.min_height ||
+	    drm->mode_config.max_width < drm->mode_config.min_width ||
+	    drm->mode_config.max_height < drm->mode_config.min_height)
+		return -EINVAL;
 	}
 
 	/* Mode config init */
@@ -523,7 +529,7 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	num_formats_dev = ret;
 	for (i = 0; i < num_formats_dev; i++) {
 		const struct drm_format_info *info;
-		size_t fmt_buf_size;
+		size_t fmt_buf_size, fmt_pitch;
 		u32 format;
 
 		format = gud_to_fourcc(formats_dev[i]);
@@ -562,8 +568,9 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
 			break;
 		}
 
-		fmt_buf_size = drm_format_info_min_pitch(info, 0, drm->mode_config.max_width) *
-			       drm->mode_config.max_height;
+		fmt_pitch = drm_format_info_min_pitch(info, 0, drm->mode_config.max_width);
+		fmt_buf_size = fmt_pitch * drm->mode_config.max_height;
+		max_pitch = max(max_pitch, fmt_pitch);
 		max_buffer_size = max(max_buffer_size, fmt_buf_size);
 
 		if (format == GUD_DRM_FORMAT_R1 || format == GUD_DRM_FORMAT_XRGB1111)
@@ -588,9 +595,13 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 	if (desc.max_buffer_size)
 		max_buffer_size = le32_to_cpu(desc.max_buffer_size);
+	if (max_buffer_size < max_pitch)
+		max_buffer_size = max_pitch;
 	/* Prevent a misbehaving device from allocating loads of RAM. 4096x4096@XRGB8888 = 64 MB */
 	if (max_buffer_size > SZ_64M)
 		max_buffer_size = SZ_64M;
+	if (max_buffer_size < max_pitch)
+		return -EINVAL;
 
 	gdrm->bulk_pipe = usb_sndbulkpipe(interface_to_usbdev(intf), usb_endpoint_num(bulk_out));
 	gdrm->bulk_len = max_buffer_size;
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index 5ef887d8485a..1f08226b23b2 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -156,10 +156,14 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
 			  struct drm_format_conv_state *fmtcnv_state)
 {
 	u8 compression = gdrm->compression;
+	unsigned int block_width = drm_format_info_block_width(format, 0);
 	struct iosys_map dst;
 	void *vaddr, *buf;
 	size_t pitch, len;
 
+	if (block_width > 1)
+		rect->x1 = ALIGN_DOWN(rect->x1, block_width);
+
 	pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
 	len = pitch * drm_rect_height(rect);
 	if (len > gdrm->bulk_len)
@@ -327,7 +331,7 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb
 {
 	struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT;
 	const struct drm_format_info *format;
-	unsigned int i, lines;
+	unsigned int i, lines, block_width;
 	size_t pitch;
 	int ret;
 
@@ -335,12 +339,21 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb
 	if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
 		format = gdrm->xrgb8888_emulation_format;
 
+	block_width = drm_format_info_block_width(format, 0);
+	if (block_width > 1)
+		damage->x1 = ALIGN_DOWN(damage->x1, block_width);
+
 	/* Split update if it's too big */
 	pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(damage));
 	lines = drm_rect_height(damage);
 
+	if (!pitch || !lines)
+		return;
+
 	if (gdrm->bulk_len < lines * pitch)
 		lines = gdrm->bulk_len / pitch;
+	if (!lines)
+		return;
 
 	for (i = 0; i < DIV_ROUND_UP(drm_rect_height(damage), lines); i++) {
 		struct drm_rect rect = *damage;
@@ -399,6 +412,13 @@ static int gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *
 
 	mutex_lock(&gdrm->damage_lock);
 
+	if (gdrm->shadow_buf && gdrm->fb &&
+	    (fb->pitches[0] != gdrm->fb->pitches[0] || fb->height != gdrm->fb->height)) {
+		vfree(gdrm->shadow_buf);
+		gdrm->shadow_buf = NULL;
+		gud_clear_damage(gdrm);
+	}
+
 	if (!gdrm->shadow_buf) {
 		gdrm->shadow_buf = vcalloc(fb->pitches[0], fb->height);
 		if (!gdrm->shadow_buf) {
@@ -562,8 +582,8 @@ int gud_plane_atomic_check(struct drm_plane *plane,
 			goto out;
 		}
 
-		req->properties[num_properties + i].prop = cpu_to_le16(prop);
-		req->properties[num_properties + i].val = cpu_to_le64(val);
+		req->properties[num_properties].prop = cpu_to_le16(prop);
+		req->properties[num_properties].val = cpu_to_le64(val);
 		num_properties++;
 	}
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-19 22:35 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-19 22:35 [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads Hui Peng

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®