[PATCH net v2] ipv4: prevent in_dev_get() from returning a dead in_device
From: Cen Zhang
Date: Fri Oct 09 2026 - 02:21:53 EST
in_dev_get() samples dev->ip_ptr under RCU and unconditionally
increments the in_device reference count. Device teardown can clear
the pointer and drop the last reference after the sample but before
the increment. RCU keeps the allocation accessible during the lookup,
but does not guarantee that a reference can still be acquired.
Commit 9d40c84cf5bc ("net: devinet: Reduce refcount before grace period")
moved the final put before the grace period. A zero-count increment now
warns and saturates the count, but cannot cancel the RCU free that has
already been queued. Returning that pointer lets callers access the
allocation after leaving RCU, when it can have been freed.
Use refcount_inc_not_zero() and return NULL if the reference cannot be
acquired, following the in6_dev_get() fix in commit 0e243671bc7b ("ipv6:
prevent in6_dev_get() from resurrecting inet6_dev"). A successful
increment retains the object for the caller. Under RTNL, a published
in_device still has a live reference, so reference acquisition is
unchanged. Callers already account for a NULL dev->ip_ptr result.
The RTM_GETNETCONF handler already checks for NULL and can keep
RTNL_FLAG_DOIT_UNLOCKED. This fixes reference acquisition in the helper
rather than serializing that one reader with teardown.
KASAN report as below:
BUG: KASAN: slab-use-after-free in inet_netconf_fill_devconf+0x748/0x790
Read of size 4 at addr ffff88811d70b958 by task ip_core_fixture/498
Call Trace:
[...]
inet_netconf_fill_devconf+0x748/0x790
inet_netconf_get_devconf+0x41c/0xe40
rtnetlink_rcv_msg+0x7b9/0xce0
netlink_rcv_skb+0x133/0x390
[...]
Allocated by task 496:
[...]
inetdev_init+0x60/0x550
inetdev_event+0x71e/0x1780
[...]
Freed by task 0:
[...]
kfree+0x12b/0x530
in_dev_free_rcu+0x51/0x90
rcu_core+0x661/0x1d10
[...]
Last potentially related work creation:
[...]
__call_rcu_common.constprop.0+0x76/0xbd0
in_dev_finish_destroy+0x12e/0x190
inetdev_event+0xa37/0x1780
[...]
Fixes: 9d40c84cf5bc ("net: devinet: Reduce refcount before grace period")
Reported-by: Baul Lee <baul.lee@xxxxxxxx>
Closes: https://lore.kernel.org/netdev/20260815172032.79740-1-baul.lee@xxxxxxxx/
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@xxxxxxxxx>
---
Changes in v2:
- Replace the RTNL workaround with non-zero reference acquisition.
- Keep RTM_GETNETCONF unlocked and return NULL for a retired in_device.
- Correct Fixes to 9d40c84cf5bc, as requested in the earlier review.
- Trim the traces and avoid unsupported double-destruction claims.
Link to v1: https://lore.kernel.org/r/pm-ip-core-objects-candidate-0002-v3-4af089192b0b62b40b9c@xxxxxxxxx
include/linux/inetdevice.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 6032eea2539a..a1446da64200 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -245,8 +245,8 @@ static inline struct in_device *in_dev_get(const struct net_device *dev)
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
- if (in_dev)
- refcount_inc(&in_dev->refcnt);
+ if (in_dev && !refcount_inc_not_zero(&in_dev->refcnt))
+ in_dev = NULL;
rcu_read_unlock();
return in_dev;
}
base-commit: 6d25ffca055a77787c21a36b66c253f76239411b
--
2.43.0