Skip to content

Commit 68e5254

Browse files
jwerner-chromiumSarah Sharp
authored andcommitted
xhci: fix null-pointer dereference when destroying half-built segment rings
xhci_alloc_segments_for_ring() builds a list of xhci_segments and links the tail to head at the end (forming a ring). When it bails out for OOM reasons half-way through, it tries to destroy its half-built list with xhci_free_segments_for_ring(), even though it is not a ring yet. This causes a null-pointer dereference upon hitting the last element. Furthermore, one of its callers (xhci_ring_alloc()) mistakenly believes the output parameters to be valid upon this kind of OOM failure, and calls xhci_ring_free() on them. Since the (incomplete) list/ring should already be destroyed in that case, this would lead to a use after free. This patch fixes those issues by having xhci_alloc_segments_for_ring() destroy its half-built, non-circular list manually and destroying the invalid struct xhci_ring in xhci_ring_alloc() with a plain kfree(). This patch should be backported to kernels as old as 2.6.31, that contains the commit 0ebbab3 "USB: xhci: Ring allocation and initialization." A separate patch will need to be developed for kernels older than 3.4, since the ring allocation code was refactored in that kernel. Signed-off-by: Julius Werner <[email protected]> Signed-off-by: Sarah Sharp <[email protected]> Cc: [email protected]
1 parent 4525c0a commit 68e5254

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
205205

206206
next = xhci_segment_alloc(xhci, cycle_state, flags);
207207
if (!next) {
208-
xhci_free_segments_for_ring(xhci, *first);
208+
prev = *first;
209+
while (prev) {
210+
next = prev->next;
211+
xhci_segment_free(xhci, prev);
212+
prev = next;
213+
}
209214
return -ENOMEM;
210215
}
211216
xhci_link_segments(xhci, prev, next, type);
@@ -258,7 +263,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
258263
return ring;
259264

260265
fail:
261-
xhci_ring_free(xhci, ring);
266+
kfree(ring);
262267
return NULL;
263268
}
264269

0 commit comments

Comments
 (0)