Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: also use netdev_hold() in ip6_route_check_nh()

In blamed commit, we missed the fact that ip6_validate_gw()
could change dev under us from ip6_route_check_nh()

In this fix, I use GFP_ATOMIC in order to not pass too many additional
arguments to ip6_validate_gw() and ip6_route_check_nh() only
for a rarely used debug feature.

syzbot reported:

refcount_t: decrement hit 0; leaking memory.
WARNING: CPU: 0 PID: 5006 at lib/refcount.c:31 refcount_warn_saturate+0x1d7/0x1f0 lib/refcount.c:31
Modules linked in:
CPU: 0 PID: 5006 Comm: syz-executor403 Not tainted 6.4.0-rc5-syzkaller-01229-g97c5209b3d37 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023
RIP: 0010:refcount_warn_saturate+0x1d7/0x1f0 lib/refcount.c:31
Code: 05 fb 8e 51 0a 01 e8 98 95 38 fd 0f 0b e9 d3 fe ff ff e8 ac d9 70 fd 48 c7 c7 00 d3 a6 8a c6 05 d8 8e 51 0a 01 e8 79 95 38 fd <0f> 0b e9 b4 fe ff ff 48 89 ef e8 1a d7 c3 fd e9 5c fe ff ff 0f 1f
RSP: 0018:ffffc900039df6b8 EFLAGS: 00010282
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: ffff888026d71dc0 RSI: ffffffff814c03b7 RDI: 0000000000000001
RBP: ffff888146a505fc R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000001 R11: 0000000000000001 R12: 1ffff9200073bedc
R13: 00000000ffffffef R14: ffff888146a505fc R15: ffff8880284eb5a8
FS: 0000555556c88300(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000004585c0 CR3: 000000002b1b1000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
__refcount_dec include/linux/refcount.h:344 [inline]
refcount_dec include/linux/refcount.h:359 [inline]
ref_tracker_free+0x539/0x820 lib/ref_tracker.c:236
netdev_tracker_free include/linux/netdevice.h:4097 [inline]
netdev_put include/linux/netdevice.h:4114 [inline]
netdev_put include/linux/netdevice.h:4110 [inline]
fib6_nh_init+0xb96/0x1bd0 net/ipv6/route.c:3624
ip6_route_info_create+0x10f3/0x1980 net/ipv6/route.c:3791
ip6_route_add+0x28/0x150 net/ipv6/route.c:3835
ipv6_route_ioctl+0x3fc/0x570 net/ipv6/route.c:4459
inet6_ioctl+0x246/0x290 net/ipv6/af_inet6.c:569
sock_do_ioctl+0xcc/0x230 net/socket.c:1189
sock_ioctl+0x1f8/0x680 net/socket.c:1306
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:870 [inline]
__se_sys_ioctl fs/ioctl.c:856 [inline]
__x64_sys_ioctl+0x197/0x210 fs/ioctl.c:856
do_syscall_x64 arch/x86/entry/common.c:50 [inline]

Fixes: 70f7457ad6d6 ("net: create device lookup API with reference tracking")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
3515440d 43804992

+9 -4
+9 -4
net/ipv6/route.c
··· 3360 3360 static int ip6_route_check_nh(struct net *net, 3361 3361 struct fib6_config *cfg, 3362 3362 struct net_device **_dev, 3363 + netdevice_tracker *dev_tracker, 3363 3364 struct inet6_dev **idev) 3364 3365 { 3365 3366 const struct in6_addr *gw_addr = &cfg->fc_gateway; ··· 3405 3404 err = -EHOSTUNREACH; 3406 3405 } else { 3407 3406 *_dev = dev = res.nh->fib_nh_dev; 3408 - dev_hold(dev); 3407 + netdev_hold(dev, dev_tracker, GFP_ATOMIC); 3409 3408 *idev = in6_dev_get(dev); 3410 3409 } 3411 3410 ··· 3413 3412 } 3414 3413 3415 3414 static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, 3416 - struct net_device **_dev, struct inet6_dev **idev, 3415 + struct net_device **_dev, 3416 + netdevice_tracker *dev_tracker, 3417 + struct inet6_dev **idev, 3417 3418 struct netlink_ext_ack *extack) 3418 3419 { 3419 3420 const struct in6_addr *gw_addr = &cfg->fc_gateway; ··· 3456 3453 if (cfg->fc_flags & RTNH_F_ONLINK) 3457 3454 err = ip6_route_check_nh_onlink(net, cfg, dev, extack); 3458 3455 else 3459 - err = ip6_route_check_nh(net, cfg, _dev, idev); 3456 + err = ip6_route_check_nh(net, cfg, _dev, dev_tracker, 3457 + idev); 3460 3458 3461 3459 rcu_read_unlock(); 3462 3460 ··· 3575 3571 } 3576 3572 3577 3573 if (cfg->fc_flags & RTF_GATEWAY) { 3578 - err = ip6_validate_gw(net, cfg, &dev, &idev, extack); 3574 + err = ip6_validate_gw(net, cfg, &dev, dev_tracker, 3575 + &idev, extack); 3579 3576 if (err) 3580 3577 goto out; 3581 3578