Devicetree
 help / color / mirror / Atom feed
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(&gtrace_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(&gtrace_mutex);
> +
> +     for (i = 0; i < pdata->nr_outconns; i++) {
> +             conn = pdata->outconns[i];
> +             ret = bus_for_each_dev(&gtrace_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(&gtrace_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(&gtrace_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

  reply	other threads:[~2026-08-10 15:36 UTC|newest]

Thread overview: 27+ 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 ` [PATCH v5 01/14] dt-bindings: Add RISC-V trace component bindings 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: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: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: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: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: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: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: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: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 ` [PATCH v5 11/14] gtrace: Add perf driver for tracing using perf tool 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: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:51   ` sashiko-bot
2026-08-10 15:22 ` [PATCH v5 14/14] MAINTAINERS: Add entry for RISC-V trace framework 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox