All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Joshua Yeong" <joshua.yeong@starfivetech.com>
Cc: conor+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org
Subject: Re: [PATCH 2/2] pmdomain: riscv: Add RPMI device power service
Date: Sat, 29 Aug 2026 21:06:48 +0000	[thread overview]
Message-ID: <20260829210648.D7F491F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260829205520.1691-3-joshua.yeong@starfivetech.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Missing cleanup of initialized PM domains on the probe error path leads to a Use-After-Free in the global `gpd_list`.
- [High] Concurrent mailbox accesses cause stack Use-After-Free and queue corruption due to un-synchronized, non-blocking requests.
- [High] Ignoring the return value of `pm_genpd_remove()` in the driver remove path leaves dangling pointers in the global `gpd_list`.
- [Medium] Missing little-endian to CPU conversions on RPMI RX message fields causes data corruption on big-endian platforms.
- [Medium] Domains initialized in the ON state will never be powered off because the driver lacks a `sync_state` callback.
- [Medium] Uninitialized stack memory in RPMI response structures can be exposed to user-space.
--

commit 0568e3713c09ba7a392adb765c276307e1fd7322
Author: Joshua Yeong <joshua.yeong@starfivetech.com>

pmdomain: riscv: Add RPMI device power service

Add a generic power domain provider on top of the RISC-V Platform
Management Interface (RPMI) device power service group, reached through
an SBI MPXY channel.

> diff --git a/drivers/pmdomain/riscv/riscv-rpmi-device-power.c b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c
> new file mode 100644
> index 0000000000000..f34ef48dff394
> --- /dev/null
> +++ b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c
> @@ -0,0 +1,441 @@
[ ... ]
> +static int rpmi_power_state_get(struct rpmi_device_power_domain *mpxy_pm_domain,
> +				u32 domain_id, u32 *state)
> +{
> +	struct rpmi_pm_get_power_state_tx tx;
> +	struct rpmi_pm_get_power_state_rx rx;
> +	struct rpmi_mbox_message msg;
> +	int ret;
> +
> +	tx.domain_id = cpu_to_le32(domain_id);
> +
> +	rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_STATE,
> +					  &tx, sizeof(tx), &rx, sizeof(rx));
> +
> +	ret = rpmi_mbox_send_message(mpxy_pm_domain->mpxy_ctx->chan, &msg);
> +	if (ret)
> +		return ret;
> +
> +	if (rx.status)
> +		return rpmi_to_linux_error(rx.status);
> +
> +	*state = rx.power_state;

[Severity: Medium]
Will this return corrupted state data on big-endian platforms?

The driver correctly uses cpu_to_le32() for TX fields but fails to use
le32_to_cpu() when reading the raw little-endian power_state field from the
RPMI RX message.

> +
> +	return ret;
> +}
> +
> +static int rpmi_power_state_set(struct rpmi_device_power_domain *mpxy_pm_domain,
> +				u32 domain_id, u32 state)
> +{
> +	struct rpmi_pm_set_power_state_tx tx;
> +	struct rpmi_pm_set_power_state_rx rx;
> +	struct rpmi_mbox_message msg;
> +	int ret;
> +
> +	tx.domain_id = cpu_to_le32(domain_id);
> +	tx.power_state = cpu_to_le32(state);
> +
> +	rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_SET_STATE,
> +					  &tx, sizeof(tx), &rx, sizeof(rx));
> +	ret = rpmi_mbox_send_message(mpxy_pm_domain->mpxy_ctx->chan, &msg);

[Severity: High]
Can concurrent mailbox accesses cause stack Use-After-Free and queue
corruption?

Because the mailbox is configured for non-blocking execution in probe
(tx_block = false), mbox_send_message() will asynchronously queue messages if
the channel is busy. Since msg is stack-allocated, returning from
rpmi_power_state_set() destroys the message structure while it may still be
in the mailbox queue.

> +	if (ret)
> +		return ret;
[ ... ]
> +static int rpmi_device_power_get_attrs(u32 domain_id,
> +				       struct rpmi_device_power_domain *mpxy_pm_domain)
> +{
> +	struct rpmi_pm_get_domain_attrs_tx tx;
> +	struct rpmi_pm_get_domain_attrs_rx rx;
> +	struct rpmi_mbox_message msg;
> +	int ret;
> +
> +	tx.domain_id = cpu_to_le32(domain_id);
> +
> +	rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_ATTRS,
> +					  &tx, sizeof(tx), &rx, sizeof(rx));
> +	ret = rpmi_mbox_send_message(mpxy_pm_domain->mpxy_ctx->chan, &msg);
> +	if (ret)
> +		return ret;
> +
> +	if (rx.status)
> +		return rpmi_to_linux_error(rx.status);
> +
> +	mpxy_pm_domain->transition_latency = rx.transition_latency;

[Severity: Medium]
Is an endianness conversion missing here?

The transition latency field is read directly without little-endian to CPU
conversion, which could cause incorrect latency evaluations on big-endian
systems.

> +	strscpy(mpxy_pm_domain->name, rx.name, RPMI_PM_DOMAIN_NAME_LEN);

[Severity: Medium]
Does unconditionally copying rx.name here expose uninitialized stack memory
to user-space?

Because the rx struct is uninitialized on the stack, if the RPMI firmware
returns a success status but populates fewer bytes than the expected size,
uninitialized stack memory will be copied into the PM domain structure and
subsequently exposed through sysfs or debugfs.

> +
> +	return 0;
> +}
[ ... ]
> +static int rpmi_pm_domain_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct rpmi_device_power_domain *mpxy_pd;
> +	struct genpd_onecell_data *mpxy_pd_data;
> +	struct generic_pm_domain **domains;
> +	struct device *dev = &pdev->dev;
> +	struct rpmi_ctx *mpxy_ctx;
> +	u32 num_domains = 0;
> +	int ret;
> +	u32 i;
> +
> +	mpxy_ctx = devm_kzalloc(&pdev->dev, sizeof(*mpxy_ctx), GFP_KERNEL);
> +	if (!mpxy_ctx)
> +		return -ENOMEM;
> +
> +	/* Setup mailbox client */
> +	mpxy_ctx->client.dev		= dev;
> +	mpxy_ctx->client.rx_callback	= NULL;
> +	mpxy_ctx->client.tx_block	= false;
> +	mpxy_ctx->client.knows_txdone	= true;

[Severity: High]
Does configuring the mailbox client for non-blocking execution
(tx_block = false) require driver-level serialization?

Without synchronization, concurrent state change requests from different
devices will queue stack-allocated messages and cause a Use-After-Free when
the calling functions return immediately.

> +	mpxy_ctx->client.tx_tout	= 0;
[ ... ]
> +	mpxy_pd_data->domains = domains;
> +	mpxy_pd_data->num_domains = num_domains;
> +
> +	platform_set_drvdata(pdev, mpxy_pd_data);
> +
> +	return of_genpd_add_provider_onecell(np, mpxy_pd_data);
> +}

[Severity: High]
If of_genpd_add_provider_onecell() fails, does returning the error directly
leave initialized PM domains dangling in the global gpd_list?

The framework does not clean up individual initialized domains when provider
registration fails. When devres eventually frees the backing memory, the
global gpd_list will contain dangling pointers, leading to a Use-After-Free
and kernel panic.

> +
> +static void rpmi_pm_domain_remove(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct genpd_onecell_data *mpxy_pd_data;
> +	unsigned int i;
> +
> +	of_genpd_del_provider(np);
> +	mpxy_pd_data = platform_get_drvdata(pdev);
> +	for (i = 0; i < mpxy_pd_data->num_domains; i++) {
> +		if (!mpxy_pd_data->domains[i])
> +			continue;
> +		pm_genpd_remove(mpxy_pd_data->domains[i]);

[Severity: High]
Is it safe to ignore the return value of pm_genpd_remove() here?

If the driver is unbound via sysfs while consumer devices are still attached,
pm_genpd_remove() will fail and return -EBUSY. Ignoring this failure allows
the function to complete and devres to free the memory while the domains are
still actively linked in the global list, causing a Use-After-Free.

> +	}
> +}
> +
> +static const struct of_device_id rpmi_pm_domain_of_match[] = {
> +	{ .compatible = "riscv,rpmi-device-power" },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, rpmi_pm_domain_of_match);
> +
> +static struct platform_driver rpmi_pm_domain_platdrv = {
> +	.driver = {
> +		.name = "riscv-rpmi-device-power",
> +		.of_match_table = rpmi_pm_domain_of_match,
> +	},
> +	.probe = rpmi_pm_domain_probe,
> +	.remove = rpmi_pm_domain_remove,
> +};

[Severity: Medium]
Will domains initialized in the ON state remain powered on forever?

The platform driver omits a .sync_state callback. Without this callback (or
setting GENPD_FLAG_NO_STAY_ON), the genpd core sets stay_on = true for
default-ON domains and never clears it, preventing them from being powered
off.

> +
> +module_platform_driver(rpmi_pm_domain_platdrv);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260829205520.1691-1-joshua.yeong@starfivetech.com?part=2

      reply	other threads:[~2026-08-29 21:06 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-29 20:55 [PATCH 0/2] Add RISC-V RPMI device power service support Joshua Yeong
2026-08-29 20:55 ` Joshua Yeong
2026-08-29 20:55 ` [PATCH 1/2] dt-bindings: power: Add RPMI device power service bindings Joshua Yeong
2026-08-29 20:55   ` Joshua Yeong
2026-08-31 16:41   ` Conor Dooley
2026-08-31 16:41     ` Conor Dooley
2026-09-02 11:34     ` Joshua Yeong
2026-09-02 11:34       ` Joshua Yeong
2026-08-29 20:55 ` [PATCH 2/2] pmdomain: riscv: Add RPMI device power service Joshua Yeong
2026-08-29 20:55   ` Joshua Yeong
2026-08-29 21:06   ` sashiko-bot [this message]

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=20260829210648.D7F491F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=joshua.yeong@starfivetech.com \
    --cc=robh@kernel.org \
    --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.