* [PATCH] ipv4: Serialize netconf GET requests with RTNL
@ 2026-10-08 6:32 Cen Zhang
2026-10-08 7:30 ` Ido Schimmel
0 siblings, 1 reply; 3+ messages in thread
From: Cen Zhang @ 2026-10-08 6:32 UTC (permalink / raw)
To: dsahern, idosch, davem, edumazet, kuba, pabeni, horms, jiri
Cc: netdev, linux-kernel, baijiaju1990, jjzuming, zzzccc427
An in_device returned by in_dev_get() must stay alive until
inet_netconf_get_devconf() finishes reading its cnf. However, the helper
samples dev->ip_ptr under RCU and unconditionally increments refcnt,
then returns the pointer outside RCU without checking whether the count
was already zero. The net_device reference held by the request does not
retain the separately allocated in_device.
A down interface without IPv4 addresses or multicast owners can have
only the ip_ptr publication reference. Lowering its MTU below
IPV4_MIN_MTU invokes inetdev_destroy() through the RTNL-held
NETDEV_CHANGEMTU notifier. RTM_GETNETCONF runs without RTNL, allowing
the final put to follow its pointer sample but precede its increment:
RTM_GETNETCONF MTU change (RTNL held)
in_dev_get():
rcu_read_lock()
sample dev->ip_ptr
inetdev_destroy():
clear dev->ip_ptr
in_dev_put(): refcnt -> 0
call_rcu(in_dev_free_rcu)
refcount_inc() from zero
rcu_read_unlock()
in_dev_free_rcu(): kfree()
inet_netconf_fill_devconf():
read in_dev->cnf
The zero-count increment warns and saturates the refcount, but cannot
cancel the queued free. Once the request leaves RCU, the callback can
free the attachment before the configuration read, causing a
use-after-free. Restoring a valid MTU can publish a new attachment on
the same device while the request still holds the old pointer.
Drop RTNL_FLAG_DOIT_UNLOCKED so rtnetlink holds RTNL from lookup through
reply construction and reference release. This serializes the request
with inetdev_destroy(), preventing the publication reference from being
dropped during acquisition or use. The dump handler already holds RCU
through its configuration reads and keeps RTNL_FLAG_DUMP_UNLOCKED.
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
CPU: 1 UID: 0 PID: 498 Comm: ip_core_fixture Tainted: G W 7.2.0-rc5-pmb-bt-functional-v1+ #1 PREEMPT(lazy)
Tainted: [W]=WARN
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? inet_netconf_fill_devconf+0x748/0x790
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? inet_netconf_fill_devconf+0x748/0x790
kasan_report+0xe0/0x110
? inet_netconf_fill_devconf+0x748/0x790
inet_netconf_fill_devconf+0x748/0x790
? __pfx_inet_netconf_fill_devconf+0x10/0x10
? inet_netconf_get_devconf+0xaef/0xe40
inet_netconf_get_devconf+0x41c/0xe40
? __pfx_inet_netconf_get_devconf+0x10/0x10
? __pfx_inet_netconf_get_devconf+0x10/0x10
? rtnetlink_rcv_msg+0x795/0xce0
? srso_alias_return_thunk+0x5/0xfbef5
? lock_release+0xc8/0x280
? __pfx_inet_netconf_get_devconf+0x10/0x10
rtnetlink_rcv_msg+0x7b9/0xce0
? __pfx_rtnetlink_rcv_msg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __lock_acquire+0x466/0x2260
? lock_acquire+0x17b/0x2f0
netlink_rcv_skb+0x133/0x390
? __pfx_rtnetlink_rcv_msg+0x10/0x10
? __pfx_netlink_rcv_skb+0x10/0x10
? netlink_deliver_tap+0xdf/0xbd0
? srso_alias_return_thunk+0x5/0xfbef5
? netlink_deliver_tap+0x173/0xbd0
netlink_unicast+0x504/0x840
? __pfx_netlink_unicast+0x10/0x10
netlink_sendmsg+0x7f7/0xcf0
? __pfx_netlink_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? selinux_socket_sendmsg+0x160/0x280
? __pfx_netlink_sendmsg+0x10/0x10
____sys_sendmsg+0x88b/0x9d0
? __pfx_____sys_sendmsg+0x10/0x10
___sys_sendmsg+0x125/0x1d0
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx____sys_sendmsg+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? lock_release+0xc8/0x280
? srso_alias_return_thunk+0x5/0xfbef5
? netlink_bind+0x518/0x900
? srso_alias_return_thunk+0x5/0xfbef5
__sys_sendmsg+0x13e/0x1e0
? __pfx___sys_sendmsg+0x10/0x10
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f8ea8b31687
Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
RSP: 002b:00007fff83200d90 EFLAGS: 00000202 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f8ea8a9f780 RCX: 00007f8ea8b31687
RDX: 0000000000000000 RSI: 00007fff83200e50 RDI: 0000000000000003
RBP: 00007fff83202ed0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000000
R13: 00007fff83203070 R14: 00007f8ea8cdd000 R15: 0000559d62722c80
</TASK>
Allocated by task 496:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x630
inetdev_init+0x60/0x550
inetdev_event+0x71e/0x1780
notifier_call_chain+0xbb/0x330
call_netdevice_notifiers_info+0xa2/0xf0
register_netdevice+0x17b0/0x2090
rtnl_newlink+0x1a30/0x1f40
rtnetlink_rcv_msg+0x7b9/0xce0
netlink_rcv_skb+0x133/0x390
netlink_unicast+0x504/0x840
netlink_sendmsg+0x7f7/0xcf0
____sys_sendmsg+0x88b/0x9d0
___sys_sendmsg+0x125/0x1d0
__sys_sendmsg+0x13e/0x1e0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 0:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x12b/0x530
in_dev_free_rcu+0x51/0x90
rcu_core+0x661/0x1d10
handle_softirqs+0x201/0x930
__irq_exit_rcu+0x110/0x1e0
irq_exit_rcu+0xe/0x20
sysvec_apic_timer_interrupt+0x6c/0x80
asm_sysvec_apic_timer_interrupt+0x1a/0x20
Last potentially related work creation:
kasan_save_stack+0x33/0x60
kasan_record_aux_stack+0xa7/0xc0
__call_rcu_common.constprop.0+0x76/0xbd0
in_dev_finish_destroy+0x12e/0x190
inetdev_event+0xa37/0x1780
notifier_call_chain+0xbb/0x330
call_netdevice_notifiers_info+0xa2/0xf0
netif_set_mtu_ext+0x47d/0x6a0
netif_set_mtu+0x8b/0x120
dev_set_mtu+0xb9/0x180
dev_ifsioc+0x3b8/0x1820
dev_ioctl+0x301/0xf80
sock_do_ioctl+0x1dc/0x2b0
sock_ioctl+0x41b/0x670
__x64_sys_ioctl+0x163/0x1d0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff88811d70b800
which belongs to the cache kmalloc-512 of size 512
The buggy address is located 344 bytes inside of
freed 512-byte region [ffff88811d70b800, ffff88811d70ba00)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x11d70b
flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff888100042780 dead000000000122 0000000000000000
raw: 0000000000000000 0000000000040004 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88811d70b800: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88811d70b880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88811d70b900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88811d70b980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88811d70ba00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================
Fixes: bbcf91053bb6 ("inet: do not use RTNL in inet_netconf_get_devconf()")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 5b6b11c943e453742b4893f1c9bd9e70d3d37a6f..4e9de0c6b2c1426c4b4c8638a0a6da4be9c2034d 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2958,7 +2958,7 @@ static const struct rtnl_msg_handler devinet_rtnl_msg_handlers[] __initconst = {
.flags = RTNL_FLAG_DUMP_UNLOCKED | RTNL_FLAG_DUMP_SPLIT_NLM_DONE},
{.protocol = PF_INET, .msgtype = RTM_GETNETCONF,
.doit = inet_netconf_get_devconf, .dumpit = inet_netconf_dump_devconf,
- .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
+ .flags = RTNL_FLAG_DUMP_UNLOCKED},
{.owner = THIS_MODULE, .protocol = PF_INET, .msgtype = RTM_GETMULTICAST,
.dumpit = inet_dump_ifmcaddr, .flags = RTNL_FLAG_DUMP_UNLOCKED},
};
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ipv4: Serialize netconf GET requests with RTNL
2026-10-08 6:32 [PATCH] ipv4: Serialize netconf GET requests with RTNL Cen Zhang
@ 2026-10-08 7:30 ` Ido Schimmel
2026-10-08 8:33 ` Cen Zhang
0 siblings, 1 reply; 3+ messages in thread
From: Ido Schimmel @ 2026-10-08 7:30 UTC (permalink / raw)
To: Cen Zhang
Cc: dsahern, davem, edumazet, kuba, pabeni, horms, jiri, netdev,
linux-kernel, baijiaju1990, jjzuming
On Thu, Oct 08, 2026 at 02:32:18PM +0800, Cen Zhang wrote:
> An in_device returned by in_dev_get() must stay alive until
> inet_netconf_get_devconf() finishes reading its cnf. However, the helper
> samples dev->ip_ptr under RCU and unconditionally increments refcnt,
> then returns the pointer outside RCU without checking whether the count
> was already zero. The net_device reference held by the request does not
> retain the separately allocated in_device.
>
> A down interface without IPv4 addresses or multicast owners can have
> only the ip_ptr publication reference. Lowering its MTU below
> IPV4_MIN_MTU invokes inetdev_destroy() through the RTNL-held
> NETDEV_CHANGEMTU notifier. RTM_GETNETCONF runs without RTNL, allowing
> the final put to follow its pointer sample but precede its increment:
>
> RTM_GETNETCONF MTU change (RTNL held)
> in_dev_get():
> rcu_read_lock()
> sample dev->ip_ptr
> inetdev_destroy():
> clear dev->ip_ptr
> in_dev_put(): refcnt -> 0
> call_rcu(in_dev_free_rcu)
> refcount_inc() from zero
> rcu_read_unlock()
> in_dev_free_rcu(): kfree()
> inet_netconf_fill_devconf():
> read in_dev->cnf
>
> The zero-count increment warns and saturates the refcount, but cannot
> cancel the queued free. Once the request leaves RCU, the callback can
> free the attachment before the configuration read, causing a
> use-after-free. Restoring a valid MTU can publish a new attachment on
> the same device while the request still holds the old pointer.
>
> Drop RTNL_FLAG_DOIT_UNLOCKED so rtnetlink holds RTNL from lookup through
> reply construction and reference release. This serializes the request
> with inetdev_destroy(), preventing the publication reference from being
> dropped during acquisition or use. The dump handler already holds RCU
> through its configuration reads and keeps RTNL_FLAG_DUMP_UNLOCKED.
>
> KASAN report as below:
[...]
>
> Fixes: bbcf91053bb6 ("inet: do not use RTNL in inet_netconf_get_devconf()")
> Assisted-by: LLM
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
The correct fix is to use refcount_inc_not_zero() in in_dev_get(), in a
similar fashion to commit 0e243671bc7b ("ipv6: prevent in6_dev_get()
from resurrecting inet6_dev"). Please base your v2 on the following
submission and the feedback I provided:
https://lore.kernel.org/netdev/20260815172032.79740-1-baul.lee@xbow.com/
And please read:
https://docs.kernel.org/next/process/maintainer-netdev.html
Notably:
1. "designate your patch to a tree - [PATCH net] or [PATCH net-next]"
2. "don’t repost your patches within one 24h period"
Also, trim the traces (preferably decoded) to what is actually useful:
https://docs.kernel.org/next/process/submitting-patches.html#backtraces-in-commit-messages
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ipv4: Serialize netconf GET requests with RTNL
2026-10-08 7:30 ` Ido Schimmel
@ 2026-10-08 8:33 ` Cen Zhang
0 siblings, 0 replies; 3+ messages in thread
From: Cen Zhang @ 2026-10-08 8:33 UTC (permalink / raw)
To: Ido Schimmel
Cc: dsahern, davem, edumazet, kuba, pabeni, horms, jiri, netdev,
linux-kernel, baijiaju1990, jjzuming
Hi Ido,
> The correct fix is to use refcount_inc_not_zero() in in_dev_get(), in a
> similar fashion to commit 0e243671bc7b ("ipv6: prevent in6_dev_get()
> from resurrecting inet6_dev"). Please base your v2 on the following
> submission and the feedback I provided:
>
> https://lore.kernel.org/netdev/20260815172032.79740-1-baul.lee@xbow.com/
>
> And please read:
>
> https://docs.kernel.org/next/process/maintainer-netdev.html
>
> Notably:
>
> 1. "designate your patch to a tree - [PATCH net] or [PATCH net-next]"
> 2. "don’t repost your patches within one 24h period"
>
> Also, trim the traces (preferably decoded) to what is actually useful:
>
> https://docs.kernel.org/next/process/submitting-patches.html#backtraces-in-commit-messages
Thanks for the review. I'll fix the reference acquisition in
in_dev_get(), returning NULL if refcount_inc_not_zero() fails, and
keep RTM_GETNETCONF unlocked.
I'll review the linked submission and your feedback before preparing
v2. I'll base it on net, use the appropriate subject prefix, trim the
traces to the relevant paths, and allow at least 24 hours between
patch postings.
Best regards,
Cen Zhang
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-08 8:33 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 6:32 [PATCH] ipv4: Serialize netconf GET requests with RTNL Cen Zhang
2026-10-08 7:30 ` Ido Schimmel
2026-10-08 8:33 ` Cen Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®