[PATCH] i2c: core: fix slab-use-after-free in i2c_adapter_depth()

From: ThangNN99

Date: Tue Sep 01 2026 - 11:24:34 EST


i2c_adapter_depth() walks adapter->dev.parent assuming every
ancestor in the chain stays alive as long as the adapter does. That
is only true while each ancestor stays registered: device_add()
pins dev->parent, but device_del() unpins it regardless of whether
the child device's own memory is still kept alive by someone else.

This breaks for a USB-backed i2c adapter (e.g. radio-usb-si4713)
parented to its usb_device. If the host controller is unbound while
a userspace fd for the adapter is still open, the adapter's own
reference keeps the leaf usb_device alive, but that usb_device's
device_del() has already dropped its pin on its own parent (the
root hub), which then gets freed. A later i2c_transfer() walks into
that freed root hub and KASAN reports a use-after-free read.

Fix it by stopping the walk as soon as we reach a device that is no
longer registered, instead of trusting the rest of the chain.

Reported-by: syzbot+450abcfc7906fe1a1e16@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=450abcfc7906fe1a1e16
Signed-off-by: ThangNN99 <ngocthang2710.1999@xxxxxxxxx>
---
drivers/i2c/i2c-core-base.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index fb25704219c7..8c64a27eef5f 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1240,7 +1240,12 @@ unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
unsigned int depth = 0;
struct device *parent;

- for (parent = adapter->dev.parent; parent; parent = parent->parent)
+ /* An unregistered device may already be freed; stop there. */
+ if (!device_is_registered(&adapter->dev))
+ return depth;
+
+ for (parent = adapter->dev.parent; parent && device_is_registered(parent);
+ parent = parent->parent)
if (parent->type == &i2c_adapter_type)
depth++;

--
2.43.0

base-commit: 786262be6048deab760f68c8acc2c85607165894