mirror of https://gitee.com/openkylin/linux.git
fib: fib_dump_info can no longer use __in_dev_get_rtnl
syzbot reported yet another regression added with DOIT_UNLOCKED.
When nexthop is marked as dead, fib_dump_info uses __in_dev_get_rtnl():
./include/linux/inetdevice.h:230 suspicious rcu_dereference_protected() usage!
rcu_scheduler_active = 2, debug_locks = 1
1 lock held by syz-executor2/23859:
#0: (rcu_read_lock){....}, at: [<ffffffff840283f0>]
inet_rtm_getroute+0xaa0/0x2d70 net/ipv4/route.c:2738
[..]
lockdep_rcu_suspicious+0x123/0x170 kernel/locking/lockdep.c:4665
__in_dev_get_rtnl include/linux/inetdevice.h:230 [inline]
fib_dump_info+0x1136/0x13d0 net/ipv4/fib_semantics.c:1377
inet_rtm_getroute+0xf97/0x2d70 net/ipv4/route.c:2785
..
This isn't safe anymore, callers either hold RTNL mutex or rcu read lock,
so these spots must use rcu_dereference_rtnl() or plain rcu_derefence()
(plus unconditional rcu read lock).
This does the latter.
Fixes: 394f51abb3
("ipv4: route: set ipv4 RTM_GETROUTE to not use rtnl")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e73b49ebd9
commit
25dd169aea
|
@ -1365,8 +1365,6 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
|||
nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
|
||||
goto nla_put_failure;
|
||||
if (fi->fib_nhs == 1) {
|
||||
struct in_device *in_dev;
|
||||
|
||||
if (fi->fib_nh->nh_gw &&
|
||||
nla_put_in_addr(skb, RTA_GATEWAY, fi->fib_nh->nh_gw))
|
||||
goto nla_put_failure;
|
||||
|
@ -1374,10 +1372,14 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
|||
nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif))
|
||||
goto nla_put_failure;
|
||||
if (fi->fib_nh->nh_flags & RTNH_F_LINKDOWN) {
|
||||
in_dev = __in_dev_get_rtnl(fi->fib_nh->nh_dev);
|
||||
struct in_device *in_dev;
|
||||
|
||||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(fi->fib_nh->nh_dev);
|
||||
if (in_dev &&
|
||||
IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
|
||||
rtm->rtm_flags |= RTNH_F_DEAD;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (fi->fib_nh->nh_flags & RTNH_F_OFFLOAD)
|
||||
rtm->rtm_flags |= RTNH_F_OFFLOAD;
|
||||
|
@ -1400,18 +1402,20 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
|||
goto nla_put_failure;
|
||||
|
||||
for_nexthops(fi) {
|
||||
struct in_device *in_dev;
|
||||
|
||||
rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
|
||||
if (!rtnh)
|
||||
goto nla_put_failure;
|
||||
|
||||
rtnh->rtnh_flags = nh->nh_flags & 0xFF;
|
||||
if (nh->nh_flags & RTNH_F_LINKDOWN) {
|
||||
in_dev = __in_dev_get_rtnl(nh->nh_dev);
|
||||
struct in_device *in_dev;
|
||||
|
||||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(nh->nh_dev);
|
||||
if (in_dev &&
|
||||
IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
|
||||
rtnh->rtnh_flags |= RTNH_F_DEAD;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
rtnh->rtnh_hops = nh->nh_weight - 1;
|
||||
rtnh->rtnh_ifindex = nh->nh_oif;
|
||||
|
|
Loading…
Reference in New Issue