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
prev parent reply other threads:[~2026-08-29 21:06 UTC|newest]
Thread overview: 6+ 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 ` [PATCH 1/2] dt-bindings: power: Add RPMI device power service bindings Joshua Yeong
2026-08-31 16:41 ` Conor Dooley
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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox