All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mathias Nyman" <mathias.nyman@linux.intel.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH 01/14] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability
Date: Fri, 09 Oct 2026 10:11:03 +0000	[thread overview]
Message-ID: <sashiko-outbox-165202@kernel.org> (raw)
In-Reply-To: <20261009095834.561578-2-mathias.nyman@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] usb: xhci-dbc: OOB MMIO read during capability traversal via truncated early_ioremap
- [High] usb: xhci-dbc: strictly requiring optional LEGACY capability breaks valid hardware
- [High] usb: xhci-dbc: missing bounds check allows OOB access to LEGACY capability registers
- [High] usb: xhci-dbc: lockless unmap on ioremap failure causes UAF with active console
- [Medium] usb: xhci-dbc: off-by-one check incorrectly rejects capabilities ending at fixmap boundary
- [Medium] usb: xhci-dbc: missing offset=0 check processes base registers as capability
--

commit c5569785c857fd1c3eacf9d2844609e296560040
Author: Umang Jain <uajain@igalia.com>

early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability

This commit handles the case where the PCIe memory IO size exceeds the
fixed boot time mappings dictated by NR_FIX_BTMAPS. It ensures that the
xHCI debug capability can still be queried by mapping the base address
up to the fixmap size and querying capabilities within that range. It also
introduces xhci_base_length to track the early_ioremap() mapped size.

> diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
> index 41118bba91978..f2ed8e52cc56c 100644
> --- a/drivers/usb/early/xhci-dbc.c
> +++ b/drivers/usb/early/xhci-dbc.c

[ ... ]

> @@ -85,7 +98,59 @@ static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
>  
>  	xdbc.xhci_start = val64;
>  	xdbc.xhci_length = sz64;
> -	base = early_ioremap(val64, sz64);
> +
> +	fixmap_size = NR_FIX_BTMAPS << PAGE_SHIFT;
> +	if (sz64 < fixmap_size) {
> +		xdbc.xhci_base_length = sz64;
> +		return early_ioremap(val64, sz64);
> +	}
> +
> +	/*
> +	 * Base address size is greater than fixed size boot time mappings
> +	 * hence, map maximum allowed fixmap size from base address and
> +	 * determine if the required extended capabilities lies within the
> +	 * fixmap.
> +	 */
> +	base = early_ioremap(val64, fixmap_size);
> +	if (!base)
> +		return NULL;
> +
> +	offset = xhci_find_next_ext_cap(base, 0, 0);
> +
> +	while (offset < fixmap_size) {
> +		val = readl(base + offset);

[Severity: Medium]
If xhci_find_next_ext_cap() returns 0 (indicating no capabilities found),
doesn't this loop unconditionally enter because 0 < fixmap_size?

Inside the loop, readl(base + 0) would read the base xHCI Capability
Registers rather than an extended capability header. XHCI_EXT_CAPS_ID(val)
could then mistakenly extract the CAPLENGTH byte, potentially misinterpreting
it as an extended capability ID like XDBC_CAP_FLAG_LEGACY.

Should there be an explicit check for offset == 0 before entering the loop?

> +		switch (XHCI_EXT_CAPS_ID(val)) {
> +		case XHCI_EXT_CAPS_DEBUG:
> +			if (offset + XDBC_MAPPING_SIZE < fixmap_size)

[Severity: Medium]
If the 64-byte DEBUG capability struct ends exactly at the fixmap_size
boundary (offset + XDBC_MAPPING_SIZE == fixmap_size), it is fully mapped
and safe to access.

Does the strict less-than operator here incorrectly reject a perfectly valid
capability that ends exactly at the boundary?

> +				cap_flags |= XDBC_CAP_FLAG_DEBUG;
> +			break;
> +		case XHCI_EXT_CAPS_PROTOCOL:
> +			cap_flags |= XDBC_CAP_FLAG_PROTOCOL;
> +			break;
> +		case XHCI_EXT_CAPS_LEGACY:
> +			cap_flags |= XDBC_CAP_FLAG_LEGACY;
> +			break;

[Severity: High]
This accepts the LEGACY capability without ensuring its extended registers
fit within the mapped fixmap region.

If the LEGACY capability header is located at fixmap_size - 4, the while
condition (offset < fixmap_size) is satisfied, and the header is read.
However, later in xdbc_bios_handoff(), the code accesses the control register
at offset + XHCI_LEGACY_CONTROL_OFFSET (offset + 4).

Will this result in an out-of-bounds MMIO read when offset + 4 equals
fixmap_size?

> +		}
> +
> +		if ((cap_flags & XDBC_CAP_FLAG_DEBUG) &&
> +		    (cap_flags & XDBC_CAP_FLAG_PROTOCOL) &&
> +		    (cap_flags & XDBC_CAP_FLAG_LEGACY)) {
> +			found_all_caps = true;
> +			break;
> +		}

[Severity: High]
According to Section 7.1 of the xHCI specification, the "USB Legacy Support
Capability" is strictly optional.

By requiring XDBC_CAP_FLAG_LEGACY to be present here, does this patch
introduce a regression that breaks DbC initialization on valid, compliant
hardware that safely omits it?

> +
> +		offset = xhci_find_next_ext_cap(base, offset, 0);

[Severity: High]
Does this blindly request the next offset without verifying bounds beforehand?

Inside xhci_find_next_ext_cap(), the helper computes the offset to the next
capability and immediately dereferences it:

xhci_find_next_ext_cap():
    do {
        ...
        next = XHCI_EXT_CAPS_NEXT(val);
        offset += next << 2;
    } while (next);  // loops back to readl(base + offset)

If the computed offset exceeds fixmap_size, readl() will access unmapped
MMIO memory and cause a kernel page fault BEFORE xhci_find_next_ext_cap()
returns.

The offset < fixmap_size check at the top of the loop is too late to prevent
this out-of-bounds access.

> +		if (!offset)
> +			break;
> +	}

[ ... ]

> @@ -1004,7 +1069,7 @@ static int __init xdbc_init(void)
>  	memblock_phys_free(xdbc.table_dma, PAGE_SIZE);
>  	memblock_phys_free(xdbc.out_dma, PAGE_SIZE);
>  	writel(0, &xdbc.xdbc_reg->control);
> -	early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
> +	early_iounmap(xdbc.xhci_base, xdbc.xhci_base_length);

[Severity: High]
If keep_bootcon is used, the console remains active. If the permanent
ioremap() fails in xdbc_init(), execution jumps to the free_and_quit error
path.

This error path locklessly unmaps the underlying MMIO regions by calling
early_iounmap() and writel() without acquiring xdbc.lock and without
unregistering the console.

Concurrently, if another CPU calls printk(), it could invoke
early_xdbc_write(), which acquires xdbc.lock and attempts to write to the
now-unmapped xdbc.xhci_base. Can this cause an MMIO use-after-free or page
fault?

>  
>  	return ret;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261009095834.561578-1-mathias.nyman@linux.intel.com?part=1

  reply	other threads:[~2026-10-09 10:11 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-09  9:58 [PATCH 00/14] xhci features and fixes for usb-next Mathias Nyman
2026-10-09  9:58 ` [PATCH 01/14] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability Mathias Nyman
2026-10-09 10:11   ` sashiko-bot [this message]
2026-10-09 14:52     ` Mathias Nyman
2026-10-09  9:58 ` [PATCH 02/14] usb: xhci: return an error if the host is not halted Mathias Nyman
2026-10-09 10:13   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 03/14] usb: xhci: Unlock for command abort polling Mathias Nyman
2026-10-09 10:10   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 04/14] usb: xhci: fix typos in comments Mathias Nyman
2026-10-09 10:02   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 05/14] xhci: check device notification type before forwarding wake event Mathias Nyman
2026-10-09 10:10   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 06/14] xhci: dbc: lock the minor IDR on registration failure Mathias Nyman
2026-10-09 10:13   ` sashiko-bot
2026-10-09 10:51     ` Greg KH
2026-10-09 10:52       ` Greg KH
2026-10-09 11:16         ` Mathias Nyman
2026-10-09 11:23           ` Greg KH
2026-10-09  9:58 ` [PATCH 07/14] usb: xhci: sideband: fix ring sg table for sub-page TRB segments Mathias Nyman
2026-10-09 10:15   ` sashiko-bot
2026-10-09 13:35     ` Mathias Nyman
2026-10-09  9:58 ` [PATCH 08/14] usb: xhci-pci: Add TUSB73x0 definitions Mathias Nyman
2026-10-09 10:07   ` sashiko-bot
2026-10-09 12:15     ` Mathias Nyman
2026-10-09  9:58 ` [PATCH 09/14] usb: xhci: Guarantee URB giveback on Ring Underrun/Overrun Mathias Nyman
2026-10-09 10:11   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 10/14] usb: xhci: Don't set the skip flag on non-isoc endpoints Mathias Nyman
2026-10-09 10:16   ` sashiko-bot
2026-10-09 12:06     ` Mathias Nyman
2026-10-09  9:58 ` [PATCH 11/14] usb: xhci: Shorten the TD skipping loop Mathias Nyman
2026-10-09 10:06   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 12/14] usb: xhci: Rework and improve the TD matching and skipping logic Mathias Nyman
2026-10-09 10:15   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 13/14] usb: xhci: Fix bounce buffer overflow Mathias Nyman
2026-10-09 10:15   ` sashiko-bot
2026-10-09  9:58 ` [PATCH 14/14] xhci: Prevent invalid vdev dereference during sideband unregister Mathias Nyman
2026-10-09 10:12   ` sashiko-bot
2026-10-09 10:50 ` [PATCH 00/14] xhci features and fixes for usb-next Greg KH
2026-10-09 11:00   ` Mathias Nyman
2026-10-09 12:23     ` Michal Pecio

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-165202@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@linux.intel.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.