Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d9b70f7 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

xhci: Don't add a virt_dev to the devs array before it's fully allocated



Avoid null pointer dereference if some function is walking through the
devs array accessing members of a new virt_dev that is mid allocation.

Add the virt_dev to xhci->devs[i] _after_ the virt_device and all its
members are properly allocated.

issue found by KASAN: null-ptr-deref in xhci_find_slot_id_by_port

"Quick analysis suggests that xhci_alloc_virt_device() is not mutex
protected. If so, there is a time frame where xhci->devs[slot_id] is set
but not fully initialized. Specifically, xhci->devs[i]->udev can be NULL."

Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent be6123df
Loading
Loading
Loading
Loading
+11 −4
Original line number Original line Diff line number Diff line
@@ -971,10 +971,9 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
		return 0;
		return 0;
	}
	}


	xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
	dev = kzalloc(sizeof(*dev), flags);
	if (!xhci->devs[slot_id])
	if (!dev)
		return 0;
		return 0;
	dev = xhci->devs[slot_id];


	/* Allocate the (output) device context that will be used in the HC. */
	/* Allocate the (output) device context that will be used in the HC. */
	dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
	dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
@@ -1015,9 +1014,17 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,


	trace_xhci_alloc_virt_device(dev);
	trace_xhci_alloc_virt_device(dev);


	xhci->devs[slot_id] = dev;

	return 1;
	return 1;
fail:
fail:
	xhci_free_virt_device(xhci, slot_id);

	if (dev->in_ctx)
		xhci_free_container_ctx(xhci, dev->in_ctx);
	if (dev->out_ctx)
		xhci_free_container_ctx(xhci, dev->out_ctx);
	kfree(dev);

	return 0;
	return 0;
}
}