All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Chen-Yu Tsai" <wenst@chromium.org>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v4 09/14] usb: hub: Power on connected M.2 E-key connectors with power sequencing API
Date: Thu, 09 Jul 2026 11:45:13 +0000	[thread overview]
Message-ID: <20260709114513.D1F091F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260709095726.704448-10-wenst@chromium.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Incomplete and race-prone clearing of `hub->ports[]` causing Use-After-Free during teardown.
- [High] Missing NULL pointer checks cause deterministic crashes if the UAF mitigation is triggered.
- [Medium] Port device sysfs exposure before power sequencer initialization causes data races and potential Use-After-Free.
--

--- Patch [9]: [PATCH v4 09/14] usb: hub: Power on connected M.2 E-key connectors with power sequencing API ---
commit db3c17ab30961cf683de3a4643e34e109f716eac
Author: Chen-Yu Tsai <wenst@chromium.org>

usb: hub: Power on connected M.2 E-key connectors with power sequencing API

This commit adds power sequencing API support for M.2 E-key USB connectors
so their power can be enabled and W_DISABLE2# signal deasserted. It uses
the usb_port device to acquire the power sequencing descriptor and manages
it during port creation and removal.

> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index db867dc1cd14f..e1908a4e1f54a 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c

[ ... ]

> @@ -886,20 +897,24 @@ static void hub_tt_work(struct work_struct *work)
>  int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
>  			   int port1, bool set)
>  {
> +	struct usb_port *pwrseq_port = hub->ports[port1 - 1];
>  	int ret;
>  
> +	ret = usb_hub_set_port_pwrseq(pwrseq_port, set);

[Severity: High]
Does this code dereference a NULL pointer if the port creation previously
failed?

If usb_hub_create_port_device() hits an error, it sets this array entry
to NULL. A concurrent PM or sysfs call to usb_hub_set_port_power() might
pass this NULL pointer directly into usb_hub_set_port_pwrseq(), which
then accesses port->pwrseq.

> diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
> index de524c6da9fc4..7277c38c9e62c 100644
> --- a/drivers/usb/core/hub.h
> +++ b/drivers/usb/core/hub.h

[ ... ]

> @@ -103,7 +103,13 @@ static inline bool hub_is_port_power_switchable(struct usb_hub *hub)
>  	if (!hub)
>  		return false;
>  	hcs = hub->descriptor->wHubCharacteristics;
> -	return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM;
> +	if ((le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM)
> +		return true;
> +	/* check for controllable external power sequencers */
> +	for (unsigned int i = 0; i < hub->hdev->maxchild; i++)
> +		if (hub->ports[i] && hub->ports[i]->pwrseq)

[Severity: High]
Is it possible for hub->ports[i] to be set to NULL between the two reads?

Since the array entry can be cleared by another thread without a lock or
READ_ONCE(), evaluating hub->ports[i] twice might result in a NULL pointer
dereference on the second read.

> diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
> index f3e4d6a31798a..dfb9f4bcd6124 100644
> --- a/drivers/usb/core/port.c
> +++ b/drivers/usb/core/port.c

[ ... ]

> @@ -813,6 +859,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
>  	if (!is_acpi_node(dev_fwnode(&hdev->dev)))
>  		device_set_node(&port_dev->dev,
>  				fwnode_graph_get_port_by_id(dev_fwnode(&hdev->dev), port1));
>  	mutex_init(&port_dev->status_lock);
>  	retval = device_register(&port_dev->dev);

[Severity: Medium]
Does registering the device here expose sysfs attributes before the power
sequencer is fully initialized?

device_register() exposes the device to userspace. A concurrent write to
the sysfs disable attribute can invoke disable_store(), which calls
usb_hub_set_port_power() and accesses port_dev->pwrseq without locking,
before it is assigned below.

>  	if (retval) {
>  		put_device(&port_dev->dev);
> +		hub->ports[port1 - 1] = NULL;
>  		return retval;
>  	}

[ ... ]

> @@ -871,10 +925,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
>  	}
>  	return 0;
>  
> +err_put_pwrseq:
> +	pwrseq_put(port_dev->pwrseq);

[Severity: Medium]
Could this result in a use-after-free if a concurrent sysfs write is in
progress?

If device_register() succeeded earlier, a racing sysfs operation might be
using the pwrseq descriptor when we free it here on the error path.

>  err_put_kn:
>  	sysfs_put(port_dev->state_kn);
>  err_unregister:
>  	device_unregister(&port_dev->dev);
> +	hub->ports[port1 - 1] = NULL;

[Severity: High]
Does clearing the array entry after device_unregister() leave a race window?

Since device_unregister() blocks to drain active sysfs and PM operations,
the array still contains a dangling pointer to this soon-to-be-freed memory
during that window. Should hub->ports[port1 - 1] be cleared before
unregistering?

>  
>  	return retval;
>  }
> @@ -888,6 +945,7 @@ void usb_hub_remove_port_device(struct usb_hub *hub, int port1)
>  {
>  	struct usb_device *hdev = hub->hdev;
>  	struct usb_port *port_dev = hub->ports[port1 - 1];
>  	struct usb_port *peer;
>  
>  	peer = port_dev->peer;

[Severity: High]
Does this code need to check if port_dev is NULL? 

If usb_hub_create_port_device() failed previously, it sets this array entry
to NULL. During hub disconnect, iterating over all ports and calling this
function would blindly dereference port_dev here.

>  	if (peer)
>  		unlink_peers(port_dev, peer);
> +	pwrseq_put(port_dev->pwrseq);

[Severity: High]
Could freeing the power sequencer here cause a use-after-free?

By calling pwrseq_put() before device_unregister(), the descriptor is freed
while PM runtime and sysfs attributes are still fully active. A racing PM
autosuspend timer calling usb_hub_set_port_power() could dereference the
freed port->pwrseq.

Additionally, should hub->ports[port1 - 1] be set to NULL here to prevent
dangling pointers?

>  	component_del(&port_dev->dev, &connector_ops);
>  	sysfs_put(port_dev->state_kn);
>  	device_unregister(&port_dev->dev);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260709095726.704448-1-wenst@chromium.org?part=9

  parent reply	other threads:[~2026-07-09 11:45 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-09  9:57 [PATCH v4 00/14] arm64: mediatek: Add M.2 E-key slot on Chromebooks Chen-Yu Tsai
2026-07-09  9:57 ` [PATCH v4 01/14] device property: Add fwnode_graph_get_port_by_id() Chen-Yu Tsai
2026-07-09 10:13   ` sashiko-bot
2026-07-09  9:57 ` [PATCH v4 02/14] device property: Add fwnode_graph_get_next_port_endpoint() Chen-Yu Tsai
2026-07-09 10:26   ` sashiko-bot
2026-07-09  9:57 ` [PATCH v4 03/14] power: sequencing: Add pwrseq_power_is_on() Chen-Yu Tsai
2026-07-09 10:33   ` Andy Shevchenko
2026-07-09 10:35   ` sashiko-bot
2026-07-09  9:57 ` [PATCH v4 04/14] usb: hub: Return actual error from hub_configure() in hub_probe() Chen-Yu Tsai
2026-07-09  9:57 ` [PATCH v4 05/14] usb: hub: Associate port@ fwnode with USB port device Chen-Yu Tsai
2026-07-09 11:04   ` sashiko-bot
2026-07-10 12:08   ` Greg Kroah-Hartman
2026-07-13  6:40     ` Chen-Yu Tsai
2026-07-09  9:57 ` [PATCH v4 06/14] usb: core: Move struct usb_port and related APIs to port.h Chen-Yu Tsai
2026-07-09 10:36   ` Andy Shevchenko
2026-07-09 14:30   ` Bartosz Golaszewski
2026-07-09  9:57 ` [PATCH v4 07/14] usb: hub: Pass |struct usb_port*| to usb_port_is_power_on() Chen-Yu Tsai
2026-07-09 10:38   ` Andy Shevchenko
2026-07-09  9:57 ` [PATCH v4 08/14] usb: hub: Use usb_hub_set_port_power() to control port power everywhere Chen-Yu Tsai
2026-07-09 10:39   ` Andy Shevchenko
2026-07-09  9:57 ` [PATCH v4 09/14] usb: hub: Power on connected M.2 E-key connectors with power sequencing API Chen-Yu Tsai
2026-07-09 10:53   ` Andy Shevchenko
2026-07-09 11:45   ` sashiko-bot [this message]
2026-07-09  9:57 ` [PATCH v4 10/14] dt-bindings: usb: mediatek,mtk-xhci: Switch to ports for USB connections Chen-Yu Tsai
2026-07-09 11:58   ` sashiko-bot
2026-07-09 14:31   ` Bartosz Golaszewski
2026-07-09  9:57 ` [PATCH v4 11/14] power: sequencing: pcie-m2: support matching on remote "port" node Chen-Yu Tsai
2026-07-09 10:55   ` Andy Shevchenko
2026-07-09  9:57 ` [PATCH v4 12/14] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector Chen-Yu Tsai
2026-07-13  9:43   ` Wei Deng
2026-07-13  9:57     ` Chen-Yu Tsai
2026-07-13 10:42       ` Chen-Yu Tsai
2026-07-09  9:57 ` [PATCH v4 13/14] arm64: dts: mediatek: mt8195-cherry: Add M.2 E-key slot Chen-Yu Tsai
2026-07-09 12:35   ` sashiko-bot
2026-07-09  9:57 ` [PATCH v4 14/14] arm64: dts: mediatek: mt8188-geralt: Add WiFi/BT as " Chen-Yu Tsai

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=20260709114513.D1F091F00A3A@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=wenst@chromium.org \
    /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.