Devicetree
 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: 31+ 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-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-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox