All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Joey Lu" <a0987203069@gmail.com>
Cc: olteanv@gmail.com, robh@kernel.org, devicetree@vger.kernel.org,
	neil.armstrong@linaro.org, conor+dt@kernel.org,
	linux-phy@lists.infradead.org, vkoul@kernel.org
Subject: Re: [PATCH 2/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver
Date: Thu, 04 Jun 2026 10:23:35 +0000	[thread overview]
Message-ID: <20260604102336.3F2431F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260604101220.1092822-3-a0987203069@gmail.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The driver implements a dummy USB role switch that falsely reports success without modifying hardware state.
- [High] Race condition exposing the PHY provider before initialization completes leads to a Use-After-Free.
- [High] PHY initialization fails due to polling clock stability bits while the PHY clock is disabled.
- [Medium] Ignoring the return value of `regmap_read()` results in the use of uninitialized stack memory.
--

commit 9e57cc2572b36a8f75f7ca9bc25a14c367c18b1a
Author: Joey Lu <a0987203069@gmail.com>
Subject: phy: nuvoton: Add MA35D1 USB2 OTG PHY driver

Add a PHY driver for the USB 2.0 PHYs in the Nuvoton MA35D1 SoC. It 
implements Power-On Reset sequence, optional resistor calibration trim, 
and a USB role switch.

> diff --git a/drivers/phy/nuvoton/phy-ma35d1-otg.c b/drivers/phy/nuvoton/phy-ma35d1-otg.c
> new file mode 100644
> index 0000000000000..53bc6ddf755e6
> --- /dev/null
> +++ b/drivers/phy/nuvoton/phy-ma35d1-otg.c
[ ... ]
> +static int ma35_otg_phy_init(struct phy *phy)
> +{
> +	struct ma35_otg_phy *p = phy_get_drvdata(phy);
> +	unsigned int n = p->phy_idx;
> +	u32 ready_mask = USBPMISCR_PHY_HOST_READY(n);
> +	unsigned int val;
> +	int ret;
> +
> +	regmap_read(p->sysreg, MA35_SYS_USBPMISCR, &val);
> +	if ((val & ready_mask) == ready_mask)
> +		return 0;

[Severity: Medium]
Does ignoring the return value of regmap_read() risk evaluating uninitialized
stack memory here?

If the read fails, val remains uninitialized, and using it in the bitwise
operation could cause non-deterministic behavior, such as incorrectly skipping
the PHY power-on reset sequence.

> +
> +	regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
> +			   USBPMISCR_PHY_CTL_MASK(n),
> +			   USBPMISCR_PHY_POR(n) | USBPMISCR_PHY_SUSPEND(n));
> +	msleep(20);
> +
> +	regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
> +			   USBPMISCR_PHY_CTL_MASK(n),
> +			   USBPMISCR_PHY_SUSPEND(n));
> +
> +	ret = regmap_read_poll_timeout(p->sysreg, MA35_SYS_USBPMISCR, val,
> +				       (val & ready_mask) == ready_mask,
> +				       10, 1000);

[Severity: High]
Is it possible for this polling to time out because the PHY clock isn't
enabled yet?

The polling expects the PHY clock to be stable, but the PHY clock (p->clk) is
only enabled later in ma35_otg_phy_power_on(). Because the Linux PHY framework
guarantees that phy_init() is called before phy_power_on(), the PHY reference
clock remains disabled during this stability polling.

> +	if (ret) {
> +		dev_err(p->dev, "USB PHY%u clock not stable (USBPMISCR=0x%08x)\n",
> +			n, val);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
[ ... ]
> +static enum usb_role ma35_otg_read_id(struct ma35_otg_phy *p)
> +{
> +	unsigned int val;
> +
> +	regmap_read(p->sysreg, MA35_SYS_PWRONOTP, &val);
> +	return (val & PWRONOTP_USBP0ID) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
> +}

[Severity: Medium]
Can this return an arbitrary USB role if regmap_read() fails?

If the read fails, the uninitialized stack variable val is evaluated, leading
to a potentially incorrect role being reported.

> +
> +static int ma35_otg_role_sw_set(struct usb_role_switch *sw,
> +				enum usb_role role)
> +{
> +	struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
> +
> +	p->cur_role = role;
> +
> +	return 0;
> +}

[Severity: High]
Since the hardware mux is entirely automatic based on the physical USB ID pin,
should this .set callback return an error instead of falsely reporting success?

Writing to p->cur_role doesn't configure any hardware register, and the .get
callback correctly queries the hardware directly. Returning 0 here defeats the
subsystem's -EOPNOTSUPP rejection for read-only switches, as writes from
userspace will appear to succeed but will not change the actual hardware state.

> +
> +static enum usb_role ma35_otg_role_sw_get(struct usb_role_switch *sw)
> +{
> +	struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
> +
> +	return ma35_otg_read_id(p);
> +}
> +
> +static int ma35_otg_role_switch_init(struct platform_device *pdev,
> +				     struct ma35_otg_phy *p)
> +{
> +	struct usb_role_switch_desc sw_desc = { };
> +
> +	p->cur_role = ma35_otg_read_id(p);
> +
> +	sw_desc.set = ma35_otg_role_sw_set;
> +	sw_desc.get = ma35_otg_role_sw_get;
> +	sw_desc.allow_userspace_control = true;

[Severity: High]
Is it appropriate to set allow_userspace_control to true given that the switch
strictly reflects an automatic hardware state?

> +	sw_desc.driver_data = p;
> +	sw_desc.fwnode = dev_fwnode(&pdev->dev);
[ ... ]
> +static int ma35_otg_phy_probe(struct platform_device *pdev)
> +{
[ ... ]
> +	provider = devm_of_phy_provider_register(&pdev->dev,
> +						 of_phy_simple_xlate);
> +	if (IS_ERR(provider))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(provider),
> +				     "Failed to register PHY provider\n");
> +
> +	if (p->phy_idx == 0) {
> +		ret = ma35_otg_role_switch_init(pdev, p);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}

[Severity: High]
Could registering the PHY provider before role switch initialization risk a
use-after-free?

If devm_of_phy_provider_register() exposes the PHY globally, a consumer on
another CPU could look up the PHY and call phy_init(), acquiring a reference.

If ma35_otg_role_switch_init() subsequently fails, probe returns an error,
triggering the devm cleanup which frees the struct ma35_otg_phy *p memory.
Because the consumer already holds a valid reference, subsequent calls to
PHY APIs will dereference the freed pointer.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604101220.1092822-1-a0987203069@gmail.com?part=2

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

WARNING: multiple messages have this Message-ID (diff)
From: sashiko-bot@kernel.org
To: "Joey Lu" <a0987203069@gmail.com>
Cc: olteanv@gmail.com, robh@kernel.org, devicetree@vger.kernel.org,
	neil.armstrong@linaro.org, conor+dt@kernel.org,
	linux-phy@lists.infradead.org, vkoul@kernel.org
Subject: Re: [PATCH 2/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver
Date: Thu, 04 Jun 2026 10:23:35 +0000	[thread overview]
Message-ID: <20260604102336.3F2431F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260604101220.1092822-3-a0987203069@gmail.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The driver implements a dummy USB role switch that falsely reports success without modifying hardware state.
- [High] Race condition exposing the PHY provider before initialization completes leads to a Use-After-Free.
- [High] PHY initialization fails due to polling clock stability bits while the PHY clock is disabled.
- [Medium] Ignoring the return value of `regmap_read()` results in the use of uninitialized stack memory.
--

commit 9e57cc2572b36a8f75f7ca9bc25a14c367c18b1a
Author: Joey Lu <a0987203069@gmail.com>
Subject: phy: nuvoton: Add MA35D1 USB2 OTG PHY driver

Add a PHY driver for the USB 2.0 PHYs in the Nuvoton MA35D1 SoC. It 
implements Power-On Reset sequence, optional resistor calibration trim, 
and a USB role switch.

> diff --git a/drivers/phy/nuvoton/phy-ma35d1-otg.c b/drivers/phy/nuvoton/phy-ma35d1-otg.c
> new file mode 100644
> index 0000000000000..53bc6ddf755e6
> --- /dev/null
> +++ b/drivers/phy/nuvoton/phy-ma35d1-otg.c
[ ... ]
> +static int ma35_otg_phy_init(struct phy *phy)
> +{
> +	struct ma35_otg_phy *p = phy_get_drvdata(phy);
> +	unsigned int n = p->phy_idx;
> +	u32 ready_mask = USBPMISCR_PHY_HOST_READY(n);
> +	unsigned int val;
> +	int ret;
> +
> +	regmap_read(p->sysreg, MA35_SYS_USBPMISCR, &val);
> +	if ((val & ready_mask) == ready_mask)
> +		return 0;

[Severity: Medium]
Does ignoring the return value of regmap_read() risk evaluating uninitialized
stack memory here?

If the read fails, val remains uninitialized, and using it in the bitwise
operation could cause non-deterministic behavior, such as incorrectly skipping
the PHY power-on reset sequence.

> +
> +	regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
> +			   USBPMISCR_PHY_CTL_MASK(n),
> +			   USBPMISCR_PHY_POR(n) | USBPMISCR_PHY_SUSPEND(n));
> +	msleep(20);
> +
> +	regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
> +			   USBPMISCR_PHY_CTL_MASK(n),
> +			   USBPMISCR_PHY_SUSPEND(n));
> +
> +	ret = regmap_read_poll_timeout(p->sysreg, MA35_SYS_USBPMISCR, val,
> +				       (val & ready_mask) == ready_mask,
> +				       10, 1000);

[Severity: High]
Is it possible for this polling to time out because the PHY clock isn't
enabled yet?

The polling expects the PHY clock to be stable, but the PHY clock (p->clk) is
only enabled later in ma35_otg_phy_power_on(). Because the Linux PHY framework
guarantees that phy_init() is called before phy_power_on(), the PHY reference
clock remains disabled during this stability polling.

> +	if (ret) {
> +		dev_err(p->dev, "USB PHY%u clock not stable (USBPMISCR=0x%08x)\n",
> +			n, val);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
[ ... ]
> +static enum usb_role ma35_otg_read_id(struct ma35_otg_phy *p)
> +{
> +	unsigned int val;
> +
> +	regmap_read(p->sysreg, MA35_SYS_PWRONOTP, &val);
> +	return (val & PWRONOTP_USBP0ID) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
> +}

[Severity: Medium]
Can this return an arbitrary USB role if regmap_read() fails?

If the read fails, the uninitialized stack variable val is evaluated, leading
to a potentially incorrect role being reported.

> +
> +static int ma35_otg_role_sw_set(struct usb_role_switch *sw,
> +				enum usb_role role)
> +{
> +	struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
> +
> +	p->cur_role = role;
> +
> +	return 0;
> +}

[Severity: High]
Since the hardware mux is entirely automatic based on the physical USB ID pin,
should this .set callback return an error instead of falsely reporting success?

Writing to p->cur_role doesn't configure any hardware register, and the .get
callback correctly queries the hardware directly. Returning 0 here defeats the
subsystem's -EOPNOTSUPP rejection for read-only switches, as writes from
userspace will appear to succeed but will not change the actual hardware state.

> +
> +static enum usb_role ma35_otg_role_sw_get(struct usb_role_switch *sw)
> +{
> +	struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
> +
> +	return ma35_otg_read_id(p);
> +}
> +
> +static int ma35_otg_role_switch_init(struct platform_device *pdev,
> +				     struct ma35_otg_phy *p)
> +{
> +	struct usb_role_switch_desc sw_desc = { };
> +
> +	p->cur_role = ma35_otg_read_id(p);
> +
> +	sw_desc.set = ma35_otg_role_sw_set;
> +	sw_desc.get = ma35_otg_role_sw_get;
> +	sw_desc.allow_userspace_control = true;

[Severity: High]
Is it appropriate to set allow_userspace_control to true given that the switch
strictly reflects an automatic hardware state?

> +	sw_desc.driver_data = p;
> +	sw_desc.fwnode = dev_fwnode(&pdev->dev);
[ ... ]
> +static int ma35_otg_phy_probe(struct platform_device *pdev)
> +{
[ ... ]
> +	provider = devm_of_phy_provider_register(&pdev->dev,
> +						 of_phy_simple_xlate);
> +	if (IS_ERR(provider))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(provider),
> +				     "Failed to register PHY provider\n");
> +
> +	if (p->phy_idx == 0) {
> +		ret = ma35_otg_role_switch_init(pdev, p);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}

[Severity: High]
Could registering the PHY provider before role switch initialization risk a
use-after-free?

If devm_of_phy_provider_register() exposes the PHY globally, a consumer on
another CPU could look up the PHY and call phy_init(), acquiring a reference.

If ma35_otg_role_switch_init() subsequently fails, probe returns an error,
triggering the devm cleanup which frees the struct ma35_otg_phy *p memory.
Because the consumer already holds a valid reference, subsequent calls to
PHY APIs will dereference the freed pointer.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260604101220.1092822-1-a0987203069@gmail.com?part=2

  reply	other threads:[~2026-06-04 10:23 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-04 10:12 [PATCH 0/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver Joey Lu
2026-06-04 10:12 ` Joey Lu
2026-06-04 10:12 ` [PATCH 1/2] dt-bindings: phy: nuvoton: Add MA35D1 USB2 OTG PHY binding Joey Lu
2026-06-04 10:12   ` Joey Lu
2026-06-04 10:19   ` sashiko-bot
2026-06-04 10:19     ` sashiko-bot
2026-06-08 10:45   ` Krzysztof Kozlowski
2026-06-08 10:45     ` Krzysztof Kozlowski
2026-06-09  9:15     ` Joey Lu
2026-06-09  9:15       ` Joey Lu
2026-06-04 10:12 ` [PATCH 2/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver Joey Lu
2026-06-04 10:12   ` Joey Lu
2026-06-04 10:23   ` sashiko-bot [this message]
2026-06-04 10:23     ` sashiko-bot
2026-06-11 11:04   ` Vinod Koul
2026-06-11 11:04     ` Vinod Koul

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=20260604102336.3F2431F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=a0987203069@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=neil.armstrong@linaro.org \
    --cc=olteanv@gmail.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.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.