mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
drm/vmwgfx: enforce cursor size limits for MOB cursors
vmw_cursor_plane_atomic_check() bounds cursor width and height only
on the legacy update path; the SVGA_CAP2_CURSOR_MOB path -- the
default on modern hosts -- accepts any size. When the requested size
exceeds SVGA_REG_CURSOR_MAX_DIMENSION or SVGA_REG_MOB_MAX_SIZE,
vmw_cursor_mob_get() returns -EINVAL and leaves vps->cursor.mob NULL.
Its return value is then discarded in vmw_cursor_plane_prepare_fb(),
so the subsequent vmw_cursor_update_mob() calls
vmw_bo_map_and_cache(NULL) and oopses inside
vmw_bo_map_and_cache_size() on the tbo.base.size load.
Reachable from any DRM master via DRM_IOCTL_MODE_CURSOR2 with a
sufficiently large width or height (e.g. cursor_max_dim + 1).
Reject oversized cursors in atomic_check for both MOB-backed cursor
update types. The MOB byte-size limit only applies to the
SVGA_CAP2_CURSOR_MOB path (vmw_cursor_mob_size() returns 0 for
GB_ONLY); compute the required MOB size in 64-bit to avoid overflow
when very large dimensions are requested.
In prepare_fb only call vmw_cursor_mob_get()/_map() for
VMW_CURSOR_UPDATE_MOB -- the GB_ONLY path uses bo->map.virtual
directly and would otherwise be silently downgraded to NONE on hosts
without SVGA_CAP2_CURSOR_MOB (where vmw_cursor_mob_get() always
returns -EINVAL). Degrade the update to NONE if vmw_cursor_mob_get()
or vmw_cursor_mob_map() fails so the update path does not run with a
NULL backing MOB.
Fixes: 965544150d ("drm/vmwgfx: Refactor cursor handling")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4.7
Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Reviewed-by: Ian Forbes <ian.forbes@broadcom.com>
Link: https://patch.msgid.link/20260505222728.519626-10-zack.rusin@broadcom.com
This commit is contained in:
parent
05eaa887e7
commit
d5ed874916
|
|
@ -432,6 +432,7 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
|
|||
u32 size = vmw_cursor_mob_size(vps->cursor.update_type,
|
||||
vps->base.crtc_w, vps->base.crtc_h);
|
||||
struct vmw_bo *vbo = vps->cursor.mob;
|
||||
void *map;
|
||||
|
||||
if (!vbo)
|
||||
return -EINVAL;
|
||||
|
|
@ -446,11 +447,15 @@ vmw_cursor_mob_map(struct vmw_plane_state *vps)
|
|||
if (unlikely(ret != 0))
|
||||
return -ENOMEM;
|
||||
|
||||
vmw_bo_map_and_cache(vbo);
|
||||
map = vmw_bo_map_and_cache(vbo);
|
||||
if (!map) {
|
||||
vmw_bo_unmap(vbo);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
ttm_bo_unreserve(&vbo->tbo);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -663,9 +668,15 @@ int vmw_cursor_plane_prepare_fb(struct drm_plane *plane,
|
|||
!vmw_cursor_buffer_changed(vps, old_vps)) {
|
||||
vps->cursor.update_type =
|
||||
VMW_CURSOR_UPDATE_NONE;
|
||||
} else {
|
||||
vmw_cursor_mob_get(vcp, vps);
|
||||
vmw_cursor_mob_map(vps);
|
||||
} else if (vps->cursor.update_type ==
|
||||
VMW_CURSOR_UPDATE_MOB &&
|
||||
(vmw_cursor_mob_get(vcp, vps) ||
|
||||
vmw_cursor_mob_map(vps))) {
|
||||
/*
|
||||
* Reset the cursor to avoid crashes later.
|
||||
*/
|
||||
vps->cursor.update_type =
|
||||
VMW_CURSOR_UPDATE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -732,6 +743,34 @@ int vmw_cursor_plane_atomic_check(struct drm_plane *plane,
|
|||
"surface not suitable for cursor\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (update_type == VMW_CURSOR_UPDATE_GB_ONLY ||
|
||||
update_type == VMW_CURSOR_UPDATE_MOB) {
|
||||
u32 cursor_max_dim =
|
||||
vmw_read(vmw, SVGA_REG_CURSOR_MAX_DIMENSION);
|
||||
|
||||
if (new_state->crtc_w > cursor_max_dim ||
|
||||
new_state->crtc_h > cursor_max_dim) {
|
||||
drm_warn(&vmw->drm,
|
||||
"Cursor dimensions (%d, %d) exceed device max %u\n",
|
||||
new_state->crtc_w, new_state->crtc_h,
|
||||
cursor_max_dim);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (update_type == VMW_CURSOR_UPDATE_MOB) {
|
||||
u32 mob_max_size =
|
||||
vmw_read(vmw, SVGA_REG_MOB_MAX_SIZE);
|
||||
u64 mob_size = (u64)new_state->crtc_w *
|
||||
new_state->crtc_h * sizeof(u32) +
|
||||
sizeof(SVGAGBCursorHeader);
|
||||
|
||||
if (mob_size > mob_max_size) {
|
||||
drm_warn(&vmw->drm,
|
||||
"Cursor MOB size %llu exceeds device max %u\n",
|
||||
mob_size, mob_max_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user