From: Eric Dumazet Date: Fri, 16 Jun 2023 08:57:52 +0000 (+0000) Subject: ipv6: also use netdev_hold() in ip6_route_check_nh() X-Git-Tag: v6.6.17~4555^2~71 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3515440df461359762d447b5068f148611bb4d42;p=platform%2Fkernel%2Flinux-rpi.git 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: __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 Signed-off-by: Eric Dumazet Cc: Jakub Kicinski Cc: David Ahern Reviewed-by: Jakub Kicinski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e510a41..64e873f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3360,6 +3360,7 @@ static int ip6_route_check_nh_onlink(struct net *net, static int ip6_route_check_nh(struct net *net, struct fib6_config *cfg, struct net_device **_dev, + netdevice_tracker *dev_tracker, struct inet6_dev **idev) { const struct in6_addr *gw_addr = &cfg->fc_gateway; @@ -3404,7 +3405,7 @@ static int ip6_route_check_nh(struct net *net, err = -EHOSTUNREACH; } else { *_dev = dev = res.nh->fib_nh_dev; - dev_hold(dev); + netdev_hold(dev, dev_tracker, GFP_ATOMIC); *idev = in6_dev_get(dev); } @@ -3412,7 +3413,9 @@ static int ip6_route_check_nh(struct net *net, } static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, - struct net_device **_dev, struct inet6_dev **idev, + struct net_device **_dev, + netdevice_tracker *dev_tracker, + struct inet6_dev **idev, struct netlink_ext_ack *extack) { const struct in6_addr *gw_addr = &cfg->fc_gateway; @@ -3453,7 +3456,8 @@ static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, if (cfg->fc_flags & RTNH_F_ONLINK) err = ip6_route_check_nh_onlink(net, cfg, dev, extack); else - err = ip6_route_check_nh(net, cfg, _dev, idev); + err = ip6_route_check_nh(net, cfg, _dev, dev_tracker, + idev); rcu_read_unlock(); @@ -3571,7 +3575,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, } if (cfg->fc_flags & RTF_GATEWAY) { - err = ip6_validate_gw(net, cfg, &dev, &idev, extack); + err = ip6_validate_gw(net, cfg, &dev, dev_tracker, + &idev, extack); if (err) goto out;