Fix xHCI heap corruption: allocate the Output Device Context full size at Address Device, never swap it (found at O-C)

xhci_cmd_address_device() sized the Output Device Context for Slot + EP0
(64 bytes); xhci_cmd_configure_endpoint() then allocated a bigger copy and
repointed DCBAA[slot_id]. The controller keeps the address it was given at
Address Device (QEMU caches it), so every bulk Endpoint Context was written
past the 64-byte block into the next kmalloc header -- on every USB
mass-storage attach, every ISA. After O-C's smoke campaign reshuffled the
heap, a kfree at thumbdrive unplug walked into it: #GP in coalesce_neighbors().

Found with temporary instrumentation (load base, code bytes at RIP, event
crumbs, a heap-list checker): the corrupt word was an EP Context (Bulk IN,
Running, MPS 1024) exactly DCI 3 x 32 bytes into the 64-byte context.

Now: XHCI_DEVICE_CTX_BYTES (32 contexts x 32 bytes) allocated once per
slot at Address Device, zeroed whole, never reallocated; Configure
Endpoint just fills it. Also ends the per-attach leak of the old context.

Verified: heap checker clean from boot; campaign -> O-A -> MINT -> unplug
-> re-attach passes with 0 exceptions; 3-ISA acceptance passes, parity and
dict_hash set unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-25 10:57:43 -04:00
co-authored by Claude Opus 5.5
parent ee4c401d1c
commit df150e8626
28 changed files with 110993 additions and 24 deletions
+7
View File
@@ -443,6 +443,13 @@ typedef struct {
volatile uint32_t reserved[3];
} xhci_ep_ctx32_t;
/* The whole Output Device Context (xHCI 1.2 spec section 6.2.1): the Slot
* Context plus 31 Endpoint Contexts, 32-byte each (CSZ=0, the only mode
* this driver implements). Allocated at this size once, at Address Device
* -- the controller keeps the address it was given there. */
#define XHCI_DEVICE_CTX_ENTRIES 32u
#define XHCI_DEVICE_CTX_BYTES (XHCI_DEVICE_CTX_ENTRIES * sizeof(xhci_ep_ctx32_t))
#define XHCI_EP_CTX_TYPE_SHIFT 3
#define XHCI_EP_CTX_TYPE_CONTROL_BIDI 4u /* EP0 */
#define XHCI_EP_CTX_TYPE_BULK_OUT 2u /* xHCI 1.2 spec table 6-9 */
+2 -1
View File
@@ -98,7 +98,8 @@ typedef struct {
* device_ctx/ep0_ring* before this fix; single-drive-at-a-time scope
* removed, each attached device now gets its own. */
void *input_ctx; /* Input Control Ctx + Slot Ctx + EP0 Ctx (96 bytes, 32-byte contexts) */
void *device_ctx; /* Slot Ctx + EP0 Ctx (64 bytes) -- DCBAA[slot_id] points here */
void *device_ctx; /* full Output Device Context (XHCI_DEVICE_CTX_BYTES, all 32
* contexts) -- DCBAA[slot_id] points here, never swapped */
xhci_trb_t *ep0_ring; /* EP0 Transfer Ring, XHCI_RING_TRB_COUNT TRBs */
uint32_t ep0_ring_cycle;
uint32_t ep0_ring_enq;