dri-devel Archive on lore.kernel.org
 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
  2026-09-19 22:57 ` sashiko-bot
  2026-10-06 13:02 ` Ruben Wauters
  0 siblings, 2 replies; 3+ messages 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 related	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads
  2026-09-19 22:35 [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads Hui Peng
@ 2026-09-19 22:57 ` sashiko-bot
  2026-10-06 13:02 ` Ruben Wauters
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-09-19 22:57 UTC (permalink / raw)
  To: Hui Peng; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] drm/gud: probe unconditionally fails on non-DMA devices due to uninitialized access
- [High] drm/gud: Use-After-Free of shadow_buf in background flush worker
- [High] drm/gud: Heap Buffer Overflow in shadow_buf during framebuffer resize
- [High] drm/gud: NULL pointer dereference in flush worker after vcalloc failure
- [Medium] drm/gud: Incomplete damage coordinate alignment yields unaligned width
--

commit 25423c5e9ff4d00f13c41b50149983a21e74d1aa
Author: Hui Peng <benquike@gmail.com>

drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads

This commit adds bounds checks during the probe process, updates shadow
buffer management in queue damage, and rounds down coordinates to block
width for damage flushes.

> diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
> --- a/drivers/gpu/drm/gud/gud_drv.c
> +++ b/drivers/gpu/drm/gud/gud_drv.c
[ ... ]
> @@ -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;

[Severity: High]
Does this unconditionally fail the probe for devices without DMA?

Inside the else branch, this newly added bounds check evaluates fields in
drm->mode_config, but drmm_mode_config_init() and the descriptor
assignments have not yet been executed. Since this memory is
zero-initialized, !drm->mode_config.min_width evaluates to true and the
function unconditionally returns -EINVAL.

>  	}
>  
[ ... ]
> diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
> --- 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);

[Severity: Medium]
Will this result in an unaligned rectangle width?

ALIGN_DOWN is applied to rect->x1, but rect->x2 is not adjusted. Because
the rectangle width is dynamically calculated as x2 - x1, this isolated
modification of x1 without a corresponding adjustment to x2 can result in
a width that is no longer a multiple of block_width.

> +
>  	pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
[ ... ]
> @@ -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);

[Severity: Medium]
Does this have the same alignment issue as in gud_prep_flush()?
Adjusting damage->x1 without adjusting damage->x2 might result in an
unaligned width when calculating x2 - x1.

> +
>  	/* Split update if it's too big */
[ ... ]
> @@ -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;

[Severity: High]
Can this lead to a use-after-free of gdrm->shadow_buf if the asynchronous
worker gud_flush_work() is currently running?

The worker clears gdrm->fb and drops the lock while performing a lengthy
USB bulk transfer. Concurrently, if a new frame with different dimensions
is queued, gdrm->fb may be set to the new fb, and a subsequent frame could
trigger this vfree() while the worker is still actively accessing the
buffer.

[Severity: High]
Additionally, does the && gdrm->fb condition bypass the reallocation block
when the background worker is active?

If gud_flush_work() has set gdrm->fb to NULL, the reallocation check fails.
This bypasses the buffer reallocation, and subsequently drm_fb_memcpy()
will copy data from a larger framebuffer into the undersized shadow_buf,
causing a heap buffer overflow.

> +		gud_clear_damage(gdrm);
> +	}
> +
>  	if (!gdrm->shadow_buf) {
>  		gdrm->shadow_buf = vcalloc(fb->pitches[0], fb->height);
>  		if (!gdrm->shadow_buf) {
>  			mutex_unlock(&gdrm->damage_lock);
>  			return -ENOMEM;

[Severity: High]
What happens if vcalloc() fails here?

If the function returns -ENOMEM without clearing gdrm->fb or canceling the
pending gud_flush_work(), the worker will eventually run, see a valid
gdrm->fb, and pass a NULL shadow map along with a cleared damage rect to
gud_flush_damage(). Because gud_clear_damage() sets y1 = INT_MAX and y2 = 0,
calculating drm_rect_height(damage) will yield a negative number, which
underflows to a massive positive iteration count and leads to repeated calls
to gud_prep_flush() dereferencing a NULL source virtual address.

>  		}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260919223510.3888975-1-benquike@gmail.com?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads
  2026-09-19 22:35 [PATCH] drm/gud: fix bulk_len divide-by-zero, connector bitmap OOB, and short USB reads Hui Peng
  2026-09-19 22:57 ` sashiko-bot
@ 2026-10-06 13:02 ` Ruben Wauters
  1 sibling, 0 replies; 3+ messages in thread
From: Ruben Wauters @ 2026-10-06 13:02 UTC (permalink / raw)
  To: Hui Peng, tzimmermann, simona, airlied; +Cc: dri-devel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 7741 bytes --]

On Sat, 2026-09-19 at 22:35 +0000, Hui Peng wrote:
> 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;
This feels like it can just be changed to a check for max_pitch >
SZ_64M || max_buffer_size > SZ_64M? Comparing max_buffer_size against
max_pitch twice seems... odd
>  
>  	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;
This also feels a bit odd, checking !lines twice, it shouldn't be
possible at this point for pitch < gdrm->bulk_len due to your changes
to max_pitch above, given that max_pitch should always be at least
min_pitch for all the formats.
>  
>  	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);
Please rebase your patch, this has already been fixed upstream

Ruben
>  		num_properties++;
>  	}
>  

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 870 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-06 13:02 UTC | newest]

Thread overview: 3+ messages (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
2026-09-19 22:57 ` sashiko-bot
2026-10-06 13:02 ` Ruben Wauters

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox