[PATCH v14 2/8] i3c: master: Fix IBI request and free cleanup paths

From: Lakshay Piplani

Date: Tue Jul 14 2026 - 05:32:50 EST


i3c_dev_request_ibi_locked() allocates the generic IBI object and its
workqueue before calling the controller request_ibi() callback. If the
callback fails, destroy the workqueue before freeing the IBI object.

Also, a controller callback may clear dev->ibi while forwarding the request
or free operation to another controller. Avoid touching dev->ibi after the
callback if it has already been cleared.

This prevents a workqueue leak in the request failure path and avoids NULL
pointer dereference in the free path when the callback has already released
the IBI object.

Signed-off-by: Lakshay Piplani <lakshay.piplani@xxxxxxx>
Signed-off-by: Vikash Bansal <vikash.bansal@xxxxxxx>
Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@xxxxxxx>

---
Changes in v14:
- Destroy the allocated IBI workqueue when request_ibi() callback fails
- Avoid touching dev->ibi after request/free callbacks if a forwarding
controller callback has already cleared it
---
---
drivers/i3c/master.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 2cb94face156..01c6e048485c 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -3499,8 +3499,18 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,

dev->ibi = ibi;
ret = master->ops->request_ibi(dev, req);
- if (ret) {
- kfree(ibi);
+
+ /*
+ * The controller callback may have already released and cleared dev->ibi
+ * when the request is forwarded by a virtual controller. Only clean up the
+ * IBI object if the callback left dev->ibi valid.
+ */
+ if (ret && dev->ibi) {
+ /* Avoid leaking the workqueue allocated for this IBI request. */
+ if (dev->ibi->wq)
+ destroy_workqueue(dev->ibi->wq);
+
+ kfree(dev->ibi);
dev->ibi = NULL;
}

@@ -3540,6 +3550,13 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)

master->ops->free_ibi(dev);

+ /*
+ * The controller callback may have already released dev->ibi, for example
+ * when the request was forwarded by a virtual controller.
+ */
+ if (!dev->ibi)
+ return;
+
if (dev->ibi->wq) {
destroy_workqueue(dev->ibi->wq);
dev->ibi->wq = NULL;
--
2.25.1