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.

net: ipv4: guard ip_mr_output() with rcu

syzbot found at least one path leads to an ip_mr_output()
without RCU being held.

Add guard(rcu)() to fix this in a concise way.

WARNING: CPU: 0 PID: 0 at net/ipv4/ipmr.c:2302 ip_mr_output+0xbb1/0xe70 net/ipv4/ipmr.c:2302
Call Trace:
<IRQ>
igmp_send_report+0x89e/0xdb0 net/ipv4/igmp.c:799
igmp_timer_expire+0x204/0x510 net/ipv4/igmp.c:-1
call_timer_fn+0x17e/0x5f0 kernel/time/timer.c:1747
expire_timers kernel/time/timer.c:1798 [inline]
__run_timers kernel/time/timer.c:2372 [inline]
__run_timer_base+0x61a/0x860 kernel/time/timer.c:2384
run_timer_base kernel/time/timer.c:2393 [inline]
run_timer_softirq+0xb7/0x180 kernel/time/timer.c:2403
handle_softirqs+0x286/0x870 kernel/softirq.c:579
__do_softirq kernel/softirq.c:613 [inline]
invoke_softirq kernel/softirq.c:453 [inline]
__irq_exit_rcu+0xca/0x1f0 kernel/softirq.c:680
irq_exit_rcu+0x9/0x30 kernel/softirq.c:696
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1050 [inline]
sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1050

Fixes: 35bec72a24ac ("net: ipv4: Add ip_mr_output()")
Reported-by: syzbot+f02fb9e43bd85c6c66ae@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/685e841a.a00a0220.129264.0002.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Petr Machata <petrm@nvidia.com>
Cc: Roopa Prabhu <roopa@nvidia.com>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
Cc: Benjamin Poirier <bpoirier@nvidia.com>
Cc: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
beead7ee f22e6fdf

+2 -2
+2 -2
net/ipv4/ipmr.c
··· 2299 2299 struct mr_table *mrt; 2300 2300 int vif; 2301 2301 2302 - WARN_ON_ONCE(!rcu_read_lock_held()); 2302 + guard(rcu)(); 2303 + 2303 2304 dev = rt->dst.dev; 2304 2305 2305 2306 if (IPCB(skb)->flags & IPSKB_FORWARDED) ··· 2314 2313 if (IS_ERR(mrt)) 2315 2314 goto mc_output; 2316 2315 2317 - /* already under rcu_read_lock() */ 2318 2316 cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); 2319 2317 if (!cache) { 2320 2318 vif = ipmr_find_vif(mrt, dev);