MAX3420 USB Device Controller: Endpoint Index Out-of-Bounds via wIndex

Out-of-bounds read/write in MAX3420 UDC caused by unvalidated USB wIndex used as endpoint array index.


Overview

The MAX3420 USB Device Controller driver uses the USB SETUP packet field wIndex as an index into a fixed-size endpoint array without validating it against the array bounds.

The derived index is computed as:

id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;

where USB_ENDPOINT_NUMBER_MASK = 0x0f, producing values in the range 0–15, while the actual endpoint array size is only 4.

Attack Surface

USB SETUP packets originate from a fully untrusted USB host and are ingested directly from hardware:

spi_rd_buf(udc, MAX3420_REG_SUDFIFO, &setup, 8);

udc->setup = setup;
udc->setup.wIndex = cpu_to_le16(setup.wIndex);

No validation is performed on wIndex before it is used in control flow or memory access.

Vulnerability

Endpoint access occurs directly via:

ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];

With:

struct max3420_ep ep[4];

Any value ≥ 4 results in out-of-bounds access.

Vulnerability 1: max3420_getstatus() OOB Read

The function dereferences an endpoint pointer derived from unvalidated input:

ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];

If the index is out of bounds, subsequent field reads operate on unrelated kernel memory, resulting in a heap out-of-bounds read.

Vulnerability 2: max3420_set_clear_feature() OOB Write

The same index is used for write operations:

id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[id];

When id ≥ 4, writes target memory beyond the endpoint array, corrupting adjacent kernel heap or struct fields.

Trigger

bmRequestType = 0x02
bRequest      = SET_FEATURE
wValue        = ENDPOINT_HALT
wIndex        = 0x0007
wLength       = 0x0000

This produces id = 7, which is outside the valid range [0–3].

Execution Flow

max3420_handle_irqs()
  → SUDAVIRQ
    → max3420_handle_setup()
      → spi_rd_buf(SUDFIFO)
      → max3420_getstatus() / max3420_set_clear_feature()
        → udc->ep[index] (no bounds check)

No validation occurs between packet ingestion and array indexing.

Crash Evidence

AddressSanitizer confirms out-of-bounds access in a userspace harness:

runtime error: index 7 out of bounds for type 'max3420_ep [4]'
ERROR: AddressSanitizer: heap-buffer-overflow

WRITE of size 1 at 0x... (168 bytes past region)

#0 max3420_set_clear_feature
#1 run_test
#2 main

The access occurs 168 bytes past the allocated region, confirming struct adjacency corruption before heap boundary.

Root Cause

The driver assumes the masked USB field is safe to use as an array index:

wIndex & USB_ENDPOINT_NUMBER_MASK

However, masking does not enforce the actual array bounds (MAX3420_MAX_EPS = 4), leading to a mismatch between protocol encoding and memory safety constraints.

Fix

id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;

if (id >= MAX3420_MAX_EPS)
    goto stall;

ep = &udc->ep[id];

The check must be applied consistently across all endpoint-accessing paths.

Affected Scope

All kernels containing the MAX3420 USB Device Controller driver are affected.