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 <[email protected]>
> ---
> 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: signature.asc
Description: This is a digitally signed message part

Reply via email to