Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit dcdfdf5

Browse files
Alexei Starovoitovdavem330
Alexei Starovoitov
authored andcommitted
ipv4: fix race in concurrent ip_route_input_slow()
CPUs can ask for local route via ip_route_input_noref() concurrently. if nh_rth_input is not cached yet, CPUs will proceed to allocate equivalent DSTs on 'lo' and then will try to cache them in nh_rth_input via rt_cache_route() Most of the time they succeed, but on occasion the following two lines: orig = *p; prev = cmpxchg(p, orig, rt); in rt_cache_route() do race and one of the cpus fails to complete cmpxchg. But ip_route_input_slow() doesn't check the return code of rt_cache_route(), so dst is leaking. dst_destroy() is never called and 'lo' device refcnt doesn't go to zero, which can be seen in the logs as: unregister_netdevice: waiting for lo to become free. Usage count = 1 Adding mdelay() between above two lines makes it easily reproducible. Fix it similar to nh_pcpu_rth_output case. Fixes: d2d68ba ("ipv4: Cache input routes in fib_info nexthops.") Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4f837c3 commit dcdfdf5

File tree

1 file changed

+6
-2
lines changed

1 file changed

+6
-2
lines changed

Diff for: net/ipv4/route.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -1776,8 +1776,12 @@ out: return err;
17761776
rth->dst.error= -err;
17771777
rth->rt_flags &= ~RTCF_LOCAL;
17781778
}
1779-
if (do_cache)
1780-
rt_cache_route(&FIB_RES_NH(res), rth);
1779+
if (do_cache) {
1780+
if (unlikely(!rt_cache_route(&FIB_RES_NH(res), rth))) {
1781+
rth->dst.flags |= DST_NOCACHE;
1782+
rt_add_uncached_list(rth);
1783+
}
1784+
}
17811785
skb_dst_set(skb, &rth->dst);
17821786
err = 0;
17831787
goto out;

0 commit comments

Comments
 (0)