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
next prev 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