Re: [PATCH v2] drm/vmwgfx: Treat zero SVGA_REG_CURSOR_MAX_DIMENSION as unset

[email protected]
Newsgroups org.freedesktop.lists.dri-devel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Integer overflows in framebuffer creation and cursor command submission cause a Guest-to-Host Out-Of-Bounds Read.
- [High] Missing Error Handling / NULL Pointer Dereference in `vmw_cursor_plane_prepare_fb`.
- [High] State Confusion in `vmw_cursor_plane_atomic_check` allows bypassing legacy cursor dimension checks, leading to a massive kernel heap Out-Of-Bounds read.
--

--- Patch [1]: [PATCH v2] drm/vmwgfx: Treat zero SVGA_REG_CURSOR_MAX_DIMENSION as unset ---
commit fc08a38eba647596145d861cab4214687c5ce5ce
Author: fausten <[email protected]>

drm/vmwgfx: Treat zero SVGA_REG_CURSOR_MAX_DIMENSION as unset

This commit treats a reported SVGA_REG_CURSOR_MAX_DIMENSION of 0 as "not
implemented" and skips the cursor dimension check in that case. This restores
the pre-existing behaviour for VMware Fusion guests (SVGA version 2) where the
cursor previously did not show up.

> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
> index d1e7df5001903..fbdd23ecb2b4b 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
[ ... ]
> @@ -748,8 +750,10 @@ int vmw_cursor_plane_atomic_check(struct drm_plane *plane,
>  		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) {
> +		/* Some SVGA implementations (e.g. VMware Fusion) report 0 here. */
> +		if (cursor_max_dim &&
> +		    (new_state->crtc_w > cursor_max_dim ||
> +		    new_state->crtc_h > cursor_max_dim)) {

[Severity: High]
This isn't a bug introduced by this patch, but does the cursor plane code handle
BO mapping failures safely?

In drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c:vmw_cursor_plane_prepare_fb(),
the return value of vmw_bo_map_and_cache_size() is cast to void, ignoring
potential mapping failures:

    (void)vmw_bo_map_and_cache_size(bo, size);

If this mapping fails, bo->map.virtual remains NULL. Later, in
vmw_cursor_plane_atomic_update(), vmw_send_define_cursor_cmd() unconditionally
copies to the command buffer using the unvalidated image pointer:

    memcpy(&cmd[1], image, image_size);

Could this cause a NULL pointer dereference and kernel panic if memory
pressure causes the mapping to fail?

[Severity: High]
This is a pre-existing issue, but does skipping this dimension check expose
a state confusion bug that could lead to an out-of-bounds read?

In drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c:vmw_cursor_plane_atomic_check(),
update_type is evaluated using vmw_cursor_update_type(vmw, vps). At this point,
vps->uo contains stale state from the previous commit, as it isn't updated until
vmw_cursor_plane_prepare_fb().

If userspace commits a BO-backed cursor (GB_ONLY), and then in a subsequent
commit submits a Surface-backed cursor (LEGACY) with huge dimensions
(e.g., 512x512), atomic_check will evaluate the type as GB_ONLY.

Since this patch skips the dimension check when cursor_max_dim == 0,
the huge dimensions are accepted. When prepare_fb() runs, vps->uo is updated
and the type correctly becomes LEGACY.

Finally, in vmw_send_define_cursor_cmd(), the memcpy() reads width * height * 4
bytes from the 16KB legacy surface->snooper.image buffer:

    memcpy(&cmd[1], image, image_size);

Could this result in a massive out-of-bounds read of the kernel heap being
sent to the hypervisor?

[Severity: Critical]
This is a pre-existing issue, but does bypassing this check when
cursor_max_dim == 0 expose integer overflows that can cause a guest-to-host
out-of-bounds read?

If userspace creates a framebuffer with massive dimensions (e.g., 32768x32768),
the calculation in drivers/gpu/drm/vmwgfx/vmwgfx_kms.c:vmw_kms_new_framebuffer_bo()
overflows 32 bits:

    requested_size = mode_cmd->height * mode_cmd->pitches[0];
    if (unlikely(requested_size > bo->tbo.base.size)) {

This overflow to 0 allows creating a massive framebuffer with a 1-page BO.
Because this patch removes the dimension limit for cursor_max_dim == 0,
the large cursor dimensions are accepted.

When vmw_send_define_cursor_cmd() prepares the command:

    const u32 image_size = width * height * sizeof(*image);
    const u32 cmd_size = sizeof(*cmd) + image_size;

image_size overflows to 0, resulting in only sizeof(*cmd) bytes being allocated
in the command FIFO. The hypervisor receives the command specifying a
32768x32768 cursor but no pixel data follows in the FIFO.

Will this cause the hypervisor to read 4GB out-of-bounds from the command FIFO?

>  			drm_warn(&vmw->drm,
>  				 "Cursor dimensions (%d, %d) exceed device max %u\n",
>  				 new_state->crtc_w, new_state->crtc_h,

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.