Skip to content

Commit ee60ad2

Browse files
lxindavem330
authored andcommittedMar 8, 2019
route: set the deleted fnhe fnhe_daddr to 0 in ip_del_fnhe to fix a race
The race occurs in __mkroute_output() when 2 threads lookup a dst: CPU A CPU B find_exception() find_exception() [fnhe expires] ip_del_fnhe() [fnhe is deleted] rt_bind_exception() In rt_bind_exception() it will bind a deleted fnhe with the new dst, and this dst will get no chance to be freed. It causes a dev defcnt leak and consecutive dmesg warnings: unregister_netdevice: waiting for ethX to become free. Usage count = 1 Especially thanks Jon to identify the issue. This patch fixes it by setting fnhe_daddr to 0 in ip_del_fnhe() to stop binding the deleted fnhe with a new dst when checking fnhe's fnhe_daddr and daddr in rt_bind_exception(). It works as both ip_del_fnhe() and rt_bind_exception() are protected by fnhe_lock and the fhne is freed by kfree_rcu(). Fixes: deed49d ("route: check and remove route cache when we get route") Signed-off-by: Jon Maxwell <jmaxwell37@gmail.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Reviewed-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 1e02796 commit ee60ad2

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed
 

‎net/ipv4/route.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,10 @@ static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr)
13031303
if (fnhe->fnhe_daddr == daddr) {
13041304
rcu_assign_pointer(*fnhe_p, rcu_dereference_protected(
13051305
fnhe->fnhe_next, lockdep_is_held(&fnhe_lock)));
1306+
/* set fnhe_daddr to 0 to ensure it won't bind with
1307+
* new dsts in rt_bind_exception().
1308+
*/
1309+
fnhe->fnhe_daddr = 0;
13061310
fnhe_flush_routes(fnhe);
13071311
kfree_rcu(fnhe, rcu);
13081312
break;

0 commit comments

Comments
 (0)
Please sign in to comment.