From: sashiko-bot@kernel.org
To: "Mayuresh Chitale" <mayuresh.chitale@oss.qualcomm.com>
Cc: robh@kernel.org, devicetree@vger.kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v5 02/14] hwtracing: gtrace: Initial implementation of gtrace framework
Date: Mon, 10 Aug 2026 15:36:35 +0000 [thread overview]
Message-ID: <20260810153635.D61331F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260810152223.3946743-3-mayuresh.chitale@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Use-After-Free due to missing cleanup of upstream connections upon component unregistration.
- [High] Topology validation failure and missing `dest_comp` assignment lead to registration rejection and NULL pointer dereferences.
- [High] Exported lookup APIs return unreferenced device pointers, causing Use-After-Free risks.
- [High] Unbalanced refcounts and memory leak when multiple components bind to the same CPU.
- [High] Strict probe order dependency silently breaks topology building.
- [High] Infinite recursion during graph traversal leads to kernel stack overflow.
- [High] ID matching logic ignores version comparisons and terminates prematurely.
- [High] Unconditional NULL pointer dereference if driver lacks `id_table`.
- [Medium] Deadlock risk by holding subsystem mutex during device_register.
--
--- Patch [2]: [PATCH v5 02/14] hwtracing: gtrace: Initial implementation of gtrace framework ---
commit 9dea7b9c99e06842582e974d2b7070319605798a
Author: Anup Patel <anup.patel@oss.qualcomm.com>
hwtracing: gtrace: Initial implementation of gtrace framework
This patch introduces a generic hardware trace framework (gtrace). It provides
a bus and topology management helpers for trace components to interact across
different architectures.
> --- /dev/null
> +++ b/drivers/hwtracing/gtrace/gtrace-core.c
[ ... ]
> +const struct gtrace_component_id *gtrace_match_id(struct gtrace_component *comp,
> + const struct gtrace_component_id *ids)
> +{
> + const struct gtrace_component_id *id;
> +
> + for (id = ids; id->version; id++) {
> + if (comp->id.type != id->type)
> + continue;
> +
> + return id;
> + }
> +
> + return NULL;
> +}
[Severity: High]
Does this loop use the version field as a termination sentinel instead of
evaluating it? If a driver defines a component with version 0, it appears
the loop will terminate prematurely.
Also, it looks like a version comparison against comp->id.version is missing
entirely, which might cause it to match any version of a given type.
[ ... ]
> +static int gtrace_match_device(struct device *dev, const struct device_driver *drv)
> +{
> + const struct gtrace_driver *gtdrv = to_gtrace_driver(drv);
> + struct gtrace_component *comp = to_gtrace_component(dev);
> +
> + return gtrace_match_id(comp, gtdrv->id_table) ? 1 : 0;
> +}
[Severity: High]
If a driver is registered on this bus without an id_table (for example, matching
solely by ACPI or OF tables), will passing a NULL id_table here lead to a
NULL pointer dereference when gtrace_match_id() evaluates its loop condition?
[ ... ]
> +struct gtrace_component *gtrace_find_by_fwnode(struct fwnode_handle *fwnode)
> +{
> + struct gtrace_fwnode_match_data d = { .fwnode = fwnode, .match = NULL };
> + int ret;
> +
> + ret = bus_for_each_dev(>race_bustype, NULL, &d, gtrace_match_fwnode);
> + if (ret < 0)
> + return ERR_PTR(ret);
> +
> + return d.match;
> +}
[Severity: High]
Since bus_for_each_dev() drops its temporary reference upon returning, does
returning d.match directly leave the caller with an unreferenced raw pointer?
Could this lead to a use-after-free if the component is unregistered
concurrently?
[ ... ]
> +struct gtrace_component *gtrace_cpu_source(unsigned int cpu)
> +{
> + if (!cpu_present(cpu))
> + return NULL;
> +
> + return per_cpu(gtrace_cpu_source_comp, cpu);
> +}
[Severity: High]
Similar to the fwnode lookup above, should this function return a referenced
device pointer? Exposing the unreferenced component might cause a
use-after-free if the component is suddenly unregistered by another thread.
[ ... ]
> +static int gtrace_setup_inconn(struct device *dev, void *data)
> +{
> + struct gtrace_component *comp = to_gtrace_component(dev);
> + struct gtrace_platform_data *pdata = comp->pdata;
> + struct gtrace_connection *conn = data;
> + int i;
> +
> + if (device_match_fwnode(&comp->dev, conn->dest_fwnode)) {
> + for (i = 0; i < pdata->nr_inconns; i++) {
> + if (pdata->inconns[i])
> + continue;
> + pdata->inconns[i] = conn;
> + return 1;
> + }
> + }
[Severity: High]
While this properly links the connection into the destination's inconns array,
should it also assign conn->dest_comp = comp? If conn->dest_comp remains
unassigned (NULL), won't later graph traversals encounter a NULL pointer
dereference?
[ ... ]
> +static int gtrace_setup_inconns_from_outconns(struct gtrace_component *comp)
> +{
> + struct gtrace_platform_data *pdata = comp->pdata;
> + struct gtrace_connection *conn;
> + int i, ret;
> +
> + lockdep_assert_held(>race_mutex);
> +
> + for (i = 0; i < pdata->nr_outconns; i++) {
> + conn = pdata->outconns[i];
> + ret = bus_for_each_dev(>race_bustype, NULL, conn, gtrace_setup_inconn);
> + if (ret < 0) {
> + gtrace_cleanup_inconns_from_outconns(comp);
> + return ret;
> + }
> + }
[Severity: High]
If a destination component has not probed yet, bus_for_each_dev() will return 0.
Will treating 0 as a success leave this connection permanently incomplete,
since the framework does not appear to re-evaluate bidirectional matches or
request probe deferrals?
[ ... ]
> +struct gtrace_component *gtrace_register_component(struct gtrace_component_id *id,
> + const char *name,
> + struct gtrace_platform_data *pdata)
> +{
> + struct gtrace_connection *conn;
> + struct gtrace_component *comp;
> + int i, ret = 0;
> +
> + if (!id || id->type >= GTRACE_COMPONENT_TYPE_MAX) {
> + ret = -EINVAL;
> + goto err_out;
> + }
> +
> + if (!pdata || !pdata->dev) {
> + ret = -EINVAL;
> + goto err_out;
> + }
> +
> + for (i = 0; i < pdata->nr_inconns; i++) {
> + if (pdata->inconns[i]) {
> + ret = -EINVAL;
> + goto err_out;
> + }
> + }
> +
> + for (i = 0; i < pdata->nr_outconns; i++) {
> + conn = pdata->outconns[i];
> + if (!conn || conn->src_port < 0 || conn->src_comp ||
> + !device_match_fwnode(pdata->dev, conn->src_fwnode) ||
> + conn->dest_port < 0 || !conn->dest_fwnode || !conn->dest_comp) {
> + ret = -EINVAL;
> + goto err_out;
> + }
> + }
[Severity: High]
During component registration, won't the !conn->dest_comp check always fail
here since the dynamic discovery hasn't had a chance to run yet? This appears
to reject registration for any component that has output connections.
[ ... ]
> + mutex_lock(>race_mutex);
> +
> + ret = device_register(&comp->dev);
[Severity: Medium]
Calling device_register() triggers a synchronous driver probe. If the driver's
probe routine calls back into an exported framework API that also attempts to
acquire gtrace_mutex, could this result in a deadlock?
[ ... ]
> + if (comp->pdata->bound_cpu >= 0) {
> + gtrace_get_component(comp);
> + per_cpu(gtrace_cpu_source_comp, comp->pdata->bound_cpu) = comp;
> + }
[Severity: High]
If multiple components bind to the same CPU, does blindly overwriting this
per-CPU pointer without releasing the previously bound component lead to a
memory leak?
[ ... ]
> +void gtrace_unregister_component(struct gtrace_component *comp)
> +{
> + struct gtrace_component *c;
> +
> + mutex_lock(>race_mutex);
> +
> + if (comp->pdata->bound_cpu >= 0) {
> + c = per_cpu(gtrace_cpu_source_comp, comp->pdata->bound_cpu);
> + per_cpu(gtrace_cpu_source_comp, comp->pdata->bound_cpu) = NULL;
> + gtrace_put_component(c);
> + }
[Severity: High]
If an old component's CPU slot was overwritten by a newer component (leaking
the original reference as mentioned above), could putting the current occupant
here cause us to prematurely free the newer component?
> +
> + gtrace_cleanup_inconns_from_outconns(comp);
> + device_unregister(&comp->dev);
[Severity: High]
This cleans up downstream outconns, but what about upstream components that
connect to this component? If upstream nodes retain dangling pointers to this
freed component, could it cause a use-after-free during graph traversal?
One additional question regarding graph traversals: when recursively walking the
graph topology across connections, it doesn't appear that visited nodes are
tracked. If hardware topology tables are misconfigured with a cycle
(e.g., A -> B -> A), could this trigger infinite recursion and overflow the
kernel stack?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810152223.3946743-1-mayuresh.chitale@oss.qualcomm.com?part=2
next prev parent reply other threads:[~2026-08-10 15:36 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 15:22 [PATCH v5 00/14] Linux RISC-V trace framework and drivers Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:22 ` [PATCH v5 01/14] dt-bindings: Add RISC-V trace component bindings Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:33 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 02/14] hwtracing: gtrace: Initial implementation of gtrace framework Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:36 ` sashiko-bot [this message]
2026-08-10 15:22 ` [PATCH v5 03/14] gtrace: Add RISC-V platform driver for the " Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:38 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 04/14] gtrace: Add functions to create/destroy a trace component path Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:34 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 05/14] gtrace: Add functions to start/stop tracing on a " Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:33 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 06/14] gtrace: Add RISC-V Trace encoder driver Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:40 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 07/14] gtrace: Add function to copy into perf AUX buffer Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:42 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 08/14] perf: Add gtrace AUX buffer trace format type Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:37 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 09/14] gtrace: Add RISC-V Trace ramsink driver Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:47 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 10/14] riscv: Enable DMA_RESTRICTED_POOL in defconfig Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:22 ` [PATCH v5 11/14] gtrace: Add perf driver for tracing using perf tool Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:48 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 12/14] perf tools: Add RISC-V trace PMU record capabilities Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:55 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 13/14] perf tools: Initial support for gtrace decoder Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
2026-08-10 15:51 ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 14/14] MAINTAINERS: Add entry for RISC-V trace framework Mayuresh Chitale
2026-08-10 15:22 ` Mayuresh Chitale
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=20260810153635.D61331F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=mayuresh.chitale@oss.qualcomm.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.