Hello,

This is a follow-up to my previous disclosure email regarding the integer 
overflow vulnerability in vmw_surface_define_ioctl() (vmwgfx_surface.c:794), 
sent earlier today.

I am writing to address two points:

1. ADDITIONAL TECHNICAL DETAILS

1.1 — Root Cause (deeper analysis)

The vulnerability resides in the two nested loops inside 
vmw_surface_define_ioctl():

    cur_bo_offset = 0;  /* uint32_t */
    for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; i++) {
        for (j = 0; j < metadata->mip_levels[i]; j++) {
            cur_offset->bo_offset = cur_bo_offset;
            cur_bo_offset += vmw_surface_get_image_buffer_size(  /* line 794 */
                    desc, cur_size, stride);  /* NO overflow check on 
accumulation */
        }
    }
    res->guest_memory_size = cur_bo_offset;  /* wrapped value stored here */

While vmw_surface_get_image_buffer_size() internally uses clamped_umul32 to
protect individual per-mip-level calculations, the outer accumulation
across up to 144 iterations (6 faces × 24 mip levels) performs a plain
uint32_t += without any call to check_add_overflow(). This is the exact
pattern that CWE-190 describes.

The wrapped value is then passed directly to:
    vmw_bo_create_and_populate(dev_priv, res->guest_memory_size, ...)

which allocates the backing buffer object (BO) with the undersized value.
The surface metadata (srf->offsets[].bo_offset), however, retains the
correct large values calculated before the wrap — creating the mismatch.


1.2 — Trigger Parameters

Minimal reproducer:
    Format:      40 (SVGA3D_A16B16G16R16, 8 bytes/pixel)
    Width:       8192
    Faces:       DRM_VMW_MAX_SURFACE_FACES (6)
    Mip levels:  DRM_VMW_MAX_MIP_LEVELS (24) per face

Arithmetic:
    Per-face sum    = 715,827,960 bytes
     6faces total   = 4,294,967,760 bytes (u64)
    Wrapped (u32)   = 464 bytes  <-- guest_memory_size
    BO allocated    = 464 bytes
    TTM page alloc  = 4,096 bytes (PAGE_SIZE minimum)

The kernel accepts the ioctl without returning an error and issues a
valid surface SID (confirmed: SID=53036 in testing).


1.3 — Crash Path (VMware Workstation)

When EXECBUF SURFACE_DMA is issued referencing this surface:

1. vmw_cmd_dma() calls vmw_cmd_res_check() to validate the surface
2. vmw_resource_validate() triggers the surface bind
3. The host (VMware) computes the MOB (Memory Object Buffer) size
    from the surface dimensions: 4.29 GB => 1,048,576 pages
4. vmw_mob_pt_setup() attempts to build a 3-level page table
    for 1,048,576 pages
5. BUG_ON(mob->pt_level > 2) fires in vmwgfx_mob.c:518
6. Kernel panic — full system crash from unprivileged userspace

Kernel log (observed):
kernel BUG at drivers/gpu/drm/vmwgfx/vmwgfx_mob.c:518!
Oops: invalid opcode: 0000 [#1] SMP NOPTI
RIP: vmw_mob_pt_setup+0x2b5/0x3b0 [vmwgfx]
Call Trace:
    vmw_execbuf_ioctl
    drm_ioctl
     __x64_sys_ioctl


1.4 — Distinction from CVE-2017-7294

CVE-2017-7294 addressed a different integer overflow in the same function
(vmw_surface_define_ioctl), triggered by the levels data. That fix added
validation on the mip_levels values themselves. The current vulnerability
is in the accumulation of cur_bo_offset across mip iterations — a distinct
code path that was not covered by the 2017 patch, allowing the bug to
survive all subsequent kernel versions up to 7.0.12.

1.5 — Proposed Fix

Replace the unchecked accumulation at line 794:

/* BEFORE (vulnerable): */
cur_bo_offset += vmw_surface_get_image_buffer_size(desc, cur_size, stride);

/* AFTER (fixed): */
u32 img_size = vmw_surface_get_image_buffer_size(desc, cur_size, stride);
if (check_add_overflow(cur_bo_offset, img_size, &cur_bo_offset)) {
    ret = -EINVAL;
    goto out_invalid_size;
}

This is consistent with the existing use of check_add_overflow() throughout
the rest of the vmwgfx driver (e.g., vmwgfx_execbuf.c, vmwgfx_bo.c).


1.6 — CVSS 3.1 Breakdown

Attack Vector (AV):      Local (L)
    -> Requires local account + membership in 'video' group
Attack Complexity (AC):  Low (L)
    -> No race condition; single ioctl call is sufficient
Privileges Required (PR): Low (L)
    -> 'video' group membership, not root
User Interaction (UI):   None (N)
Scope (S):               Unchanged (U)
Confidentiality (C):     None (N)  — DoS only in tested environment
Integrity (I):           None (N)
Availability (A):        High (H)  — kernel panic confirmed

Base Score: 5.5 (Medium)

Note: If OOB write is achieved in environments without the
BUG_ON(pt_level > 2) guard (e.g., older vmwgfx or ESXi without
the 2-level PT limit), the Integrity and Confidentiality scores
would increase, pushing the score toward High (7.8+).

The attached PoC (poc_vmwgfx_bug6_final.c) from the original email
remains valid and unchanged.

We remain available for any additional questions or testing.

Best regards,

Fernando Maia
Security Researcher

Renan Malafatti
Security Researcher

________________________________
De: Fernando Gomes
Enviado: quinta-feira, 9 de julho de 2026 17:28
Para: [email protected] <[email protected]>; 
[email protected] <[email protected]>
Assunto: [SECURITY] drm/vmwgfx: Integer overflow in cur_bo_offset accumulation 
in vmw_surface_define_ioctl()

Hello,
I am reporting a security vulnerability discovered during a kernel security 
audit of Linux 7.0.12+kali-rt-amd64. This report is submitted under coordinated 
disclosure.
Vulnerability Summary
An integer overflow exists in the cur_bo_offset accumulation loop inside 
vmw_surface_define_ioctl() in drivers/gpu/drm/vmwgfx/vmwgfx_surface.c, line 
794. The loop iterates up to 144 times (DRM_VMW_MAX_SURFACE_FACES × 
DRM_VMW_MAX_MIP_LEVELS) accumulating per-mip-level buffer sizes into a uint32_t 
variable without any overflow check. The resulting wrapped value is then used 
as guest_memory_size to allocate the backing buffer object (BO), creating a 
severe size discrepancy between the allocated BO and the surface the GPU 
expects to access.
Affected Component

  *   File: drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
  *   Function: vmw_surface_define_ioctl()
  *   Line: 794
  *   Kernel tested: Linux 7.0.12+kali-rt-amd64

Vulnerable Code
c

cur_bo_offset = 0;   /* uint32_t — no overflow protection */
for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
    for (j = 0; j < metadata->mip_levels[i]; ++j) {
        cur_offset->bo_offset = cur_bo_offset;
        cur_bo_offset += vmw_surface_get_image_buffer_size(   /* line 794 */
                desc, cur_size, stride);   /* NO check_add_overflow() */
    }
}
res->guest_memory_size = cur_bo_offset;   /* stored wrapped value */

Proof of Concept
Using format 40 (SVGA3D_A16_B16_G16_R16, 8 bytes/pixel), width=8192, 6 faces 
and 24 mip levels:

  *   Real surface size (u64): 4,294,967,760 bytes (~4.29 GB)
  *   Wrapped guest_memory_size (u32): 464 bytes
  *   BO allocated: 464 bytes
  *   Surface SID returned by kernel: 53036 (no error returned)

When EXECBUF SURFACE_DMA is subsequently issued, the host attempts to construct 
a 3-level MOB page table for the 4.29 GB surface. This exceeds vmwgfx's 2-level 
limit, triggering BUG_ON(mob->pt_level > 2) in vmwgfx_mob.c:518 and causing an 
immediate kernel panic from an unprivileged process in the video group.
Impact

  *   Denial of Service (kernel panic) — confirmed on VMware Workstation Pro
  *   Potential out-of-bounds write in environments without the pt_level guard 
(e.g., ESXi/vSphere)
  *   Access vector: local user in the video group, no root privileges required

Suggested Fix
c

u32 img_size = vmw_surface_get_image_buffer_size(desc, cur_size, stride);
if (check_add_overflow(cur_bo_offset, img_size, &cur_bo_offset)) {
    ret = -EINVAL;
    goto out_invalid_size;
}

Related CVEs

  *   CVE-2017-7294 — Prior integer overflow in the same function 
(vmw_surface_define_ioctl), fixed in kernel 4.10.6. The current bug is a 
distinct variant in the accumulation path that was not addressed by that fix.
  *   CVE-2025-40277 — Recent integer overflow in vmw_cmd_check (vmwgfx).

Attachments

  *   poc_vmwgfx_bug6_final.c — self-contained PoC; compile with gcc -O0 -o poc 
poc_vmwgfx_bug6_final.c and run as a user in the video group.

I am available to provide additional technical details, logs, or testing 
assistance. I request coordinated disclosure with a standard 90-day embargo.
Regards,
Fernando Maia and Renan Malafati
Security Researcher's

Reply via email to