Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mayuresh Chitale" <mayuresh.chitale@oss.qualcomm.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v5 04/14] gtrace: Add functions to create/destroy a trace component path
Date: Mon, 10 Aug 2026 15:34:09 +0000	[thread overview]
Message-ID: <20260810153410.4C2CC1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260810152223.3946743-5-mayuresh.chitale@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Asymmetric trace ID lifecycle causes `put_trace_id` to be called on components that did not allocate an ID.
- [High] `gtrace_create_path` returns a path object with an empty component list when the sink is unreachable, leading to out-of-bounds pointer dereferences.
- [High] Missing NULL checks on component driver pointers (`gtdrv`) leads to NULL pointer dereferences.
- [High] Recursive graph traversal crashes on unresolved output connections where the destination component is NULL.
- [High] Unbounded recursive depth-first search (DFS) graph traversal lacks cycle detection, leading to kernel stack overflow.
- [High] Lockless pointer return in `gtrace_cpu_source` leads to a Use-After-Free.
--

--- Patch [4]: [PATCH v5 04/14] gtrace: Add functions to create/destroy a trace component path ---
commit a8e1889600bd5a16b5c7f9f06b462a376b8f943f
Author: Anup Patel <anup.patel@oss.qualcomm.com>

gtrace: Add functions to create/destroy a trace component path
    
Trace needs to be configured on a chain of trace components which are
connected to each other. These chain of components is also referred
to as trace component path. Add functions to create/destroy a trace
component path which will be later used by gtrace perf support.

> diff --git a/drivers/hwtracing/gtrace/gtrace-core.c b/drivers/hwtracing/gtrace/gtrace-core.c
> --- a/drivers/hwtracing/gtrace/gtrace-core.c
> +++ b/drivers/hwtracing/gtrace/gtrace-core.c
> @@ -210,6 +210,53 @@ int gtrace_reset_component(struct gtrace_component *comp)
>  }
>  EXPORT_SYMBOL_GPL(gtrace_reset_component);
>  
> +static int __gtrace_walk_output_components(struct gtrace_component *comp,
> +					   bool *stop, void *priv,
> +					   int (*fn)(struct gtrace_component *comp, bool *stop,
> +						     struct gtrace_connection *stop_conn,
> +						     void *priv))
> +{
> +	struct gtrace_connection *conn, *stop_conn = NULL;
> +	struct gtrace_platform_data *pdata = comp->pdata;

[Severity: High]
Does this crash if comp is NULL?

If a destination component is missing or unregistered, conn->dest_comp will be
NULL. When the recursive call is made, comp->pdata is evaluated immediately
without verifying comp, which would cause a NULL pointer dereference.

> +	int i, ret;
> +
> +	for (i = 0; i < pdata->nr_outconns; i++) {
> +		conn = pdata->outconns[i];
> +		ret = __gtrace_walk_output_components(conn->dest_comp, stop, priv, fn);

[Severity: High]
Is there any cycle detection in this graph traversal?

If a misconfigured Device Tree provides a cyclical graph layout
(e.g., A -> B -> A), wouldn't this DFS recurse indefinitely and exhaust the
kernel stack?

[ ... ]

>  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]
Is it safe to return this pointer without taking a reference?

If a caller obtains the component pointer while gtrace_unregister_component()
is invoked concurrently, the entry could be cleared and the component freed.
This would leave the caller with a dangling pointer.

Should this use gtrace_get_component() or RCU read locks before returning?

[ ... ]

> +struct gtrace_component *gtrace_path_source(struct gtrace_path *path)
> +{
> +	struct gtrace_path_node *node;
> +
> +	node = list_first_entry(&path->comp_list, struct gtrace_path_node, head);
> +	return node->comp;
> +}
> +EXPORT_SYMBOL_GPL(gtrace_path_source);

[Severity: High]
Does list_first_entry() resolve to an invalid offset if the list is empty?

If gtrace_create_path() successfully returns a path with an empty list,
calling gtrace_path_source() maps the pointer over the list head itself,
causing node->comp to read garbage memory.

[ ... ]

> +static int gtrace_assign_trace_id(struct gtrace_path *path)
> +{
> +	const struct gtrace_driver *gtdrv;
> +	struct gtrace_component *comp;
> +	struct gtrace_path_node *node;
> +	int trace_id;
> +
> +	list_for_each_entry(node, &path->comp_list, head) {
> +		comp = node->comp;
> +		gtdrv = to_gtrace_driver(comp->dev.driver);
> +
> +		if (!gtdrv->get_trace_id)

[Severity: High]
What happens if the component device lacks a bound driver?

The to_gtrace_driver() macro handles NULL inputs by returning NULL. If gtdrv
is NULL, evaluating !gtdrv->get_trace_id will dereference a NULL pointer.

> +			continue;
> +
> +		trace_id = gtdrv->get_trace_id(comp, path->mode);
> +		if (trace_id > 0) {
> +			path->trace_id = trace_id;
> +			return 0;

[Severity: High]
This function stops and returns at the first component that successfully
allocates a trace ID.

[ ... ]

> +static void gtrace_unassign_trace_id(struct gtrace_path *path)
> +{
> +	const struct gtrace_driver *gtdrv;
> +	struct gtrace_component *comp;
> +	struct gtrace_path_node *node;
> +
> +	list_for_each_entry(node, &path->comp_list, head) {
> +		comp = node->comp;
> +		gtdrv = to_gtrace_driver(comp->dev.driver);
> +
> +		if (!gtdrv->put_trace_id)
> +			continue;
> +
> +		gtdrv->put_trace_id(comp, path->mode, path->trace_id);
> +	}
> +}

[Severity: High]
Since gtrace_assign_trace_id() only allocates an ID from the first capable
component, wouldn't this loop unconditionally call put_trace_id() for every
component in the path?

This could ask components to free a trace ID they never allocated,
potentially corrupting their allocation bitmaps or driver state.

[ ... ]

> +struct gtrace_path *gtrace_create_path(struct gtrace_component *source,
> +				       struct gtrace_component *sink,
> +				       enum gtrace_component_mode mode)
> +{
> +	struct build_path_walk_priv priv;
> +	struct gtrace_path *path;
> +	int ret = 0;
> +
> +	if (!source || mode >= GTRACE_COMPONENT_MODE_MAX) {
> +		ret = -EINVAL;
> +		goto err_out;
> +	}
> +
> +	path = kzalloc(sizeof(*path), GFP_KERNEL);
> +	if (!path) {
> +		ret = -ENOMEM;
> +		goto err_out;
> +	}
> +	INIT_LIST_HEAD(&path->comp_list);
> +	path->mode = mode;
> +	path->trace_id = GTRACE_INVALID_TRACE_ID;
> +
> +	priv.path = path;
> +	priv.sink = sink;
> +	ret = gtrace_walk_output_components(source, &priv, build_path_walk_fn);
> +	if (ret < 0)
> +		goto err_release_path_nodes;

[Severity: High]
If the destination sink is unreachable, gtrace_walk_output_components()
completes without adding any nodes to path->comp_list and returns 0.

Since gtrace_path_ready() and gtrace_assign_trace_id() will vacuously pass
for an empty list, won't this return a successful path object with an empty
component list?

This leads to the invalid list head dereferences mentioned earlier in
gtrace_path_source() and gtrace_path_sink().

> +
> +	if (!gtrace_path_ready(path)) {
> +		ret = -EOPNOTSUPP;
> +		goto err_release_path_nodes;
> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260810152223.3946743-1-mayuresh.chitale@oss.qualcomm.com?part=4

  reply	other threads:[~2026-08-10 15:34 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
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 [this message]
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=20260810153410.4C2CC1F000E9@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