Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Lakshay Piplani" <lakshay.piplani@nxp.com>
Cc: devicetree@vger.kernel.org, conor+dt@kernel.org, robh@kernel.org
Subject: Re: [PATCH v10 7/9] i3c: hub: Add support for the I3C interface in the I3C hub
Date: Mon, 25 May 2026 09:31:46 +0000	[thread overview]
Message-ID: <20260525093146.9E6391F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260525064209.2263045-8-lakshay.piplani@nxp.com>

Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:

New issues:
- [Critical] Unconditional NULL pointer dereference in `i3c_dev_free_ibi_locked()` via recursive `i3c_hub_free_ibi()`.
- [High] Missing `up_write(&parent->bus.lock)` release on the error path in `i3c_hub_request_ibi()`.
- [High] Double free of `desc->ibi` and leaked workqueue on the error path in `i3c_hub_request_ibi()`.
- [High] `i3c_hub_master_priv_xfers()` modifies shared hub device state and parent bus topology without holding the parent controller's bus lock.
- [High] Bus address slot tracking is bypassed in `i3c_hub_master_priv_xfers()` due to identical address arguments.
- [High] Failure to restore the hub device's dynamic address (`hub_dev->info.dyn_addr`) on the reattach error path in `i3c_hub_master_priv_xfers()`.
- [High] Architectural flaw: DAA logic incorrectly delegates directly to the parent controller, permanently bypassing the virtual hub.
- [High] Missing `i3c_master_direct_detach_i3c_dev_locked()` on the error path in `i3c_hub_request_ibi()`.
- [Medium] Bitwise OR incorrectly used to combine signed error codes, resulting in corrupted errno values.

Pre-existing issues:
- [High] Leaked workqueue on the error path of IBI requests in the I3C master core.
--

commit 75489fdfdbca4c7d1708dfb61bdd09e7018b9a0b
Author: Lakshay Piplani <lakshay.piplani@nxp.com>

i3c: hub: Add support for the I3C interface in the I3C hub

Add virtual I3C bus support for the hub by creating virtual master controllers
for downstream ports and forwarding bus operations through the hub device. It
also provides an interface used by hub drivers to enable or disable downstream
ports during bus transactions.

> diff --git a/drivers/i3c/hub.c b/drivers/i3c/hub.c
> new file mode 100644
> index 0000000000000..da0e209ee5b79
> --- /dev/null
> +++ b/drivers/i3c/hub.c
[ ... ]
> @@ -54,26 +54,26 @@ static void i3c_hub_detach_i3c_dev(struct i3c_dev_desc *dev)
>   */
>  static int i3c_hub_do_daa(struct i3c_hub *hub,
>  			  struct i3c_master_controller *controller)
>  {
>  	struct i3c_master_controller *parent;
>  	int ret;
>  
>  	if (!hub || !hub->hub_dev)
>  		return -ENODEV;
>  
>  	parent = i3c_dev_get_master(hub->hub_dev->desc);
>  	if (!parent)
>  		return -ENODEV;
>  
>  	i3c_hub_enable_port(controller);
>  	ret = i3c_master_do_daa(parent);
>  	i3c_hub_disable_port(controller);

[Severity: High]
Does this discovery logic bypass the virtual hub permanently?

When calling i3c_master_do_daa(parent), newly discovered downstream devices
are attached directly to the parent controller's bus. Future transfers or
IBI requests targeting these devices will use the parent controller directly
instead of i3c_hub_master_priv_xfers().

Because of this, will i3c_hub_enable_port() never be invoked for these
devices, leaving them unreachable?

[ ... ]
> @@ -126,45 +126,45 @@ static int i3c_hub_send_ccc_cmd(struct i3c_hub *hub,
>   */
>  static int i3c_hub_master_priv_xfers(struct i3c_dev_desc *dev,
>  				     struct i3c_xfer *xfers,
>  				     int nxfers,
>  				     enum i3c_xfer_mode mode)
>  {
>  	struct i3c_master_controller *controller = i3c_dev_get_master(dev);
>  	struct i3c_hub_controller *hub_controller;
>  	struct i3c_dev_desc *hub_dev;
>  	u8 hub_addr, target_addr;
>  	struct i3c_hub *hub;
>  	int ret;
>  
>  	hub_controller = dev_get_drvdata(&controller->dev);
>  	if (!hub_controller || !hub_controller->hub)
>  		return -ENODEV;
>  
>  	hub = hub_controller->hub;
>  
>  	if (!hub->hub_dev)
>  		return -ENODEV;
>  
>  	hub_dev = hub->hub_dev->desc;
>  
>  	i3c_hub_enable_port(controller);
>  
>  	hub_addr = hub_dev->info.dyn_addr ?
>  		   hub_dev->info.dyn_addr : hub_dev->info.static_addr;
>  
>  	target_addr = dev->info.dyn_addr ?
>  		      dev->info.dyn_addr : dev->info.static_addr;
>  
>  	if (hub_addr != target_addr) {
>  		hub_dev->info.dyn_addr = target_addr;
>  		ret = i3c_master_reattach_i3c_dev_locked(hub_dev, target_addr);

[Severity: High]
Can this sequence cause a race condition when modifying shared hub state?

This code modifies hub_dev->info.dyn_addr and invokes
i3c_master_reattach_i3c_dev_locked() without holding parent->bus.lock for
writing.

If multiple virtual master controllers (hub ports) initiate transfers
concurrently, might threads race to manipulate these shared hardware address
tables and enable multiple downstream ports simultaneously without
arbitration, leading to physical bus collisions?

[Severity: High]
Will bus address slot tracking be bypassed here?

The code sets hub_dev->info.dyn_addr = target_addr and then passes
target_addr as the old_dyn_addr argument to
i3c_master_reattach_i3c_dev_locked().

Inside the core function, the condition (dev->info.dyn_addr != old_dyn_addr)
will evaluate to false, which skips updating the addr_slot_status tracking
array. Could this permanently corrupt the parent controller's view of free
and used bus addresses?

>  		if (ret)
>  			goto disable;

[Severity: High]
Should the dynamic address be restored on this error path?

If i3c_master_reattach_i3c_dev_locked() fails, the code jumps to the disable
label and returns. Since hub_dev->info.dyn_addr is not restored to hub_addr,
does this leave the software descriptor desynchronized from the actual
hardware state?

>  	}
>  
>  	ret = i3c_device_do_xfers(hub->hub_dev, xfers, nxfers, mode);
>  
>  	if (hub_addr != target_addr) {
>  		hub_dev->info.dyn_addr = hub_addr;
>  		ret |= i3c_master_reattach_i3c_dev_locked(hub_dev, hub_addr);
>  	}
>  
>  disable:

[Severity: Medium]
Is it safe to use a bitwise OR to combine these error codes?

Both i3c_device_do_xfers() and i3c_master_reattach_i3c_dev_locked() can
return negative error codes like -EAGAIN or -EBUSY. Performing a bitwise OR
combines these signed values, which can corrupt the resulting error code
and return a nonsensical status to the caller.

[ ... ]
> @@ -250,45 +250,45 @@ static bool i3c_hub_master_supports_ccc_cmd(struct i3c_master_controller *contro
>   */
>  static int i3c_hub_request_ibi(struct i3c_dev_desc *desc,
>  			       const struct i3c_ibi_setup *req)
>  {
>  	struct i3c_master_controller *controller = i3c_dev_get_master(desc);
>  	struct i3c_hub_controller *hub_controller;
>  	struct i3c_master_controller *orig_parent;
>  	struct i3c_master_controller *parent;
>  	struct i3c_hub *hub;
>  	int ret;
>  
>  	hub_controller = dev_get_drvdata(&controller->dev);
>  	if (!hub_controller || !hub_controller->hub)
>  		return -ENODEV;
>  
>  	hub = hub_controller->hub;
>  
>  	if (!hub->hub_dev)
>  		return -ENODEV;
>  
>  	parent = i3c_dev_get_master(hub->hub_dev->desc);
>  
>  	down_write(&parent->bus.lock);
>  
>  	orig_parent = i3c_hub_update_desc_parent(&desc->common, parent);
>  
>  	ret = i3c_master_direct_attach_i3c_dev_locked(parent, desc);
>  	if (ret) {
>  		i3c_hub_update_desc_parent(&desc->common, orig_parent);
>  		return ret;

[Severity: High]
Is a lock release missing on this error path?

A write lock is acquired on parent->bus.lock, but if the attachment fails,
the function returns immediately. Should up_write(&parent->bus.lock) be
called here to prevent a system deadlock on future parent bus operations?

>  	}
>  
>  	kfree(desc->ibi);
>  	desc->ibi = NULL;

[Severity: High]
Could this lead to a double free and a resource leak?

When i3c_dev_request_ibi_locked() is called, it allocates desc->ibi and a
workqueue. This code blindly calls kfree(desc->ibi), which leaves the
workqueue memory leaked.

Furthermore, if the inner call to i3c_dev_request_ibi_locked() fails, it
sets desc->ibi to NULL. The outer i3c_dev_request_ibi_locked() will then
receive the error and execute kfree(ibi) on the original pointer that was
already freed, leading to a double free.

>  	ret = i3c_dev_request_ibi_locked(desc, req);

[Severity: High]
If this recursive call fails, should the device be detached?

The downstream device is directly attached to the parent hardware controller.
If i3c_dev_request_ibi_locked() fails, the function restores the descriptor
and returns without detaching the device from the parent. Since free_ibi
will never be called to clean up a failed request, does this permanently
leak the hardware attachment resources in the parent controller?

[Severity: High]
This isn't a bug introduced by this patch, but does the core I3C code leak a
workqueue on this error path?

In drivers/i3c/master.c:i3c_dev_request_ibi_locked(), an ordered workqueue
is allocated and assigned to ibi->wq. If the controller's request_ibi
callback fails, the code frees the ibi context but does not destroy the
workqueue, leading to a memory and kernel resource leak.

>  
>  	i3c_hub_update_desc_parent(&desc->common, orig_parent);
>  
>  	up_write(&parent->bus.lock);
>  
>  	return ret;
>  }
>  
>  static void i3c_hub_free_ibi(struct i3c_dev_desc *desc)
>  {
>  	struct i3c_master_controller *controller = i3c_dev_get_master(desc);
>  	struct i3c_hub_controller *hub_controller;
>  	struct i3c_master_controller *orig_parent;
>  	struct i3c_master_controller *parent;
>  	struct i3c_hub *hub;
>  
>  	hub_controller = dev_get_drvdata(&controller->dev);
>  	if (!hub_controller || !hub_controller->hub)
>  		return;
>  
>  	hub = hub_controller->hub;
>  
>  	parent = i3c_dev_get_master(hub->hub_dev->desc);
>  
>  	i3c_hub_enable_port(controller);
>  
>  	down_write(&parent->bus.lock);
>  	orig_parent = i3c_hub_update_desc_parent(&desc->common, parent);
>  	i3c_master_direct_detach_i3c_dev_locked(desc);
>  	i3c_dev_free_ibi_locked(desc);

[Severity: Critical]
Does this recursive call result in a guaranteed NULL pointer dereference?

When the core invokes the hub's free_ibi callback, this function recursively
calls i3c_dev_free_ibi_locked() using the parent context. The inner call
frees dev->ibi and sets dev->ibi = NULL.

Upon returning to the outer i3c_dev_free_ibi_locked(), the core immediately
evaluates if (dev->ibi->wq). Since dev->ibi was just set to NULL, won't this
trigger a NULL pointer dereference on the success path?

>  	i3c_hub_update_desc_parent(&desc->common, orig_parent);
>  	up_write(&parent->bus.lock);
>  
>  	i3c_hub_disable_port(controller);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260525064209.2263045-1-lakshay.piplani@nxp.com?part=7

  reply	other threads:[~2026-05-25  9:31 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-25  6:42 [PATCH v10 0/9] Add support for NXP P3H2x4x I3C hub driver Lakshay Piplani
2026-05-25  6:42 ` [PATCH v10 1/9] i3c: master: rename i3c_master_reattach_i3c_dev() to *_locked Lakshay Piplani
2026-05-25  7:05   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 2/9] i3c: master: Expose the APIs to support I3C hub Lakshay Piplani
2026-05-25  7:39   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 3/9] i3c: master: Add APIs for I3C hub support Lakshay Piplani
2026-05-25  8:00   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 4/9] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub support Lakshay Piplani
2026-05-25  8:08   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 5/9] mfd: p3h2x4x: Add driver for NXP P3H2x4x i3c hub and on-die regulator Lakshay Piplani
2026-05-25  8:43   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 6/9] regulator: p3h2x4x: Add driver for on-die regulators in NXP P3H2x4x i3c hub Lakshay Piplani
2026-05-25  9:06   ` sashiko-bot
2026-05-26 18:16   ` Mark Brown
2026-05-25  6:42 ` [PATCH v10 7/9] i3c: hub: Add support for the I3C interface in the I3C hub Lakshay Piplani
2026-05-25  9:31   ` sashiko-bot [this message]
2026-05-25  6:42 ` [PATCH v10 8/9] i3c: hub: p3h2x4x: Add support for NXP P3H2x4x I3C hub functionality Lakshay Piplani
2026-05-25  9:56   ` sashiko-bot
2026-05-25  6:42 ` [PATCH v10 9/9] i3c: hub: p3h2x4x: Add SMBus slave mode support Lakshay Piplani
2026-05-25 10:29   ` sashiko-bot

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=20260525093146.9E6391F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lakshay.piplani@nxp.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