In drivers/gpu/drm/vboxvideo/ (vbox_main.c, vbox_mode.c, vbva_base.c),
validate VBVA ring buffer offsets against buffer_length and check cursor
dimensions before copying cursor data into HGSMI buffers.

Fixes: 131abc56e1ba ("drm/vboxvideo: Move the vboxvideo driver out of staging")
Assisted-by: LLM
Signed-off-by: Hui Peng <[email protected]>
---
diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c 
b/drivers/gpu/drm/vboxvideo/vbox_main.c
index aa6664542b20..8cf326661b57 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -115,6 +115,10 @@ int vbox_hw_init(struct vbox_private *vbox)
 
        DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
 
+       if (vbox->full_vram_size < VBVA_ADAPTER_INFORMATION_SIZE +
+                                  vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE)
+               return -EINVAL;
+
        ret = pcim_request_region(pdev, 0, "vboxvideo");
        if (ret)
                return ret;
diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c 
b/drivers/gpu/drm/vboxvideo/vbox_mode.c
index 3c41238a8268..9a1d9e1aa92b 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_mode.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c
@@ -141,7 +141,8 @@ static bool vbox_set_up_input_mapping(struct vbox_private 
*vbox)
 
                if (!fb1) {
                        fb1 = fb;
-                       if (fb1 == vbox->ddev.fb_helper->fb)
+                       if (vbox->ddev.fb_helper &&
+                           fb1 == vbox->ddev.fb_helper->fb)
                                break;
                } else if (fb != fb1) {
                        single_framebuffer = false;
@@ -363,7 +364,8 @@ static int vbox_cursor_atomic_check(struct drm_plane *plane,
                return 0;
 
        if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
-           width == 0 || height == 0)
+           width == 0 || height == 0 ||
+           width != new_state->fb->width || height != new_state->fb->height)
                return -EINVAL;
 
        return 0;
@@ -380,6 +382,7 @@ static void copy_cursor_image(u8 *src, u8 *dst, u32 width, 
u32 height,
        size_t line_size = (width + 7) / 8;
        u32 i, j;
 
+       memset(dst, 0, mask_size);
        memcpy(dst + mask_size, src, width * height * 4);
        for (i = 0; i < height; ++i)
                for (j = 0; j < width; ++j)
diff --git a/drivers/gpu/drm/vboxvideo/vbva_base.c 
b/drivers/gpu/drm/vboxvideo/vbva_base.c
index 36bc9824ec3f..3a752be06f4e 100644
--- a/drivers/gpu/drm/vboxvideo/vbva_base.c
+++ b/drivers/gpu/drm/vboxvideo/vbva_base.c
@@ -21,18 +21,35 @@
 
 static u32 vbva_buffer_available(const struct vbva_buffer *vbva)
 {
-       s32 diff = vbva->data_offset - vbva->free_offset;
+       u32 data_len = READ_ONCE(vbva->data_len);
+       u32 data_offset = READ_ONCE(vbva->data_offset);
+       u32 free_offset = READ_ONCE(vbva->free_offset);
+       s32 diff;
 
-       return diff > 0 ? diff : vbva->data_len + diff;
+       if (!data_len || data_offset >= data_len || free_offset >= data_len)
+               return 0;
+
+       diff = data_offset - free_offset;
+
+       return diff > 0 ? diff : data_len + diff;
 }
 
 static void vbva_buffer_place_data_at(struct vbva_buf_ctx *vbva_ctx,
                                      const void *p, u32 len, u32 offset)
 {
        struct vbva_buffer *vbva = vbva_ctx->vbva;
-       u32 bytes_till_boundary = vbva->data_len - offset;
-       u8 *dst = &vbva->data[offset];
-       s32 diff = len - bytes_till_boundary;
+       u32 data_len = READ_ONCE(vbva->data_len);
+       u32 bytes_till_boundary;
+       u8 *dst;
+       s32 diff;
+
+       if (data_len > vbva_ctx->buffer_length - sizeof(*vbva) ||
+           offset >= data_len || len > data_len)
+               return;
+
+       bytes_till_boundary = data_len - offset;
+       dst = &vbva->data[offset];
+       diff = len - bytes_till_boundary;
 
        if (diff <= 0) {
                /* Chunk will not cross buffer boundary. */
@@ -93,6 +110,9 @@ bool vbva_write(struct vbva_buf_ctx *vbva_ctx, struct 
gen_pool *ctx,
                vbva_buffer_place_data_at(vbva_ctx, p, chunk,
                                          vbva->free_offset);
 
+               if (!vbva->data_len)
+                       return false;
+
                vbva->free_offset = (vbva->free_offset + chunk) %
                                    vbva->data_len;
                record->len_and_flags += chunk;
@@ -165,7 +185,7 @@ bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
                              struct gen_pool *ctx)
 {
        struct vbva_record *record;
-       u32 next;
+       u32 free_idx, next;
 
        if (!vbva_ctx->vbva ||
            !(vbva_ctx->vbva->host_flags.host_events & VBVA_F_MODE_ENABLED))
@@ -173,7 +193,11 @@ bool vbva_buffer_begin_update(struct vbva_buf_ctx 
*vbva_ctx,
 
        WARN_ON(vbva_ctx->buffer_overflow || vbva_ctx->record);
 
-       next = (vbva_ctx->vbva->record_free_index + 1) % VBVA_MAX_RECORDS;
+       free_idx = READ_ONCE(vbva_ctx->vbva->record_free_index);
+       if (free_idx >= VBVA_MAX_RECORDS)
+               return false;
+
+       next = (free_idx + 1) % VBVA_MAX_RECORDS;
 
        /* Flush if all slots in the records queue are used */
        if (next == vbva_ctx->vbva->record_first_index)
@@ -183,7 +207,7 @@ bool vbva_buffer_begin_update(struct vbva_buf_ctx *vbva_ctx,
        if (next == vbva_ctx->vbva->record_first_index)
                return false;
 
-       record = &vbva_ctx->vbva->records[vbva_ctx->vbva->record_free_index];
+       record = &vbva_ctx->vbva->records[free_idx];
        record->len_and_flags = VBVA_F_RECORD_PARTIAL;
        vbva_ctx->vbva->record_free_index = next;
        /* Remember which record we are using. */

Reply via email to