From: Eric Dumazet <edumazet@xxxxxxxxxx> commit 213f5f8f31f10aa1e83187ae20fb7fa4e626b724 upstream. Before commit faa041a40b9f ("ipv4: Create cleanup helper for fib_nh") changes to net->ipv4.fib_num_tclassid_users were protected by RTNL. After the change, this is no longer the case, as free_fib_info_rcu() runs after rcu grace period, without rtnl being held. Fixes: faa041a40b9f ("ipv4: Create cleanup helper for fib_nh") Signed-off-by: Eric Dumazet <edumazet@xxxxxxxxxx> Cc: David Ahern <dsahern@xxxxxxxxxx> Reviewed-by: David Ahern <dsahern@xxxxxxxxxx> Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- include/net/ip_fib.h | 2 +- include/net/netns/ipv4.h | 2 +- net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_rules.c | 4 ++-- net/ipv4/fib_semantics.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -437,7 +437,7 @@ int fib_validate_source(struct sk_buff * #ifdef CONFIG_IP_ROUTE_CLASSID static inline int fib_num_tclassid_users(struct net *net) { - return net->ipv4.fib_num_tclassid_users; + return atomic_read(&net->ipv4.fib_num_tclassid_users); } #else static inline int fib_num_tclassid_users(struct net *net) --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -61,7 +61,7 @@ struct netns_ipv4 { #endif bool fib_has_custom_local_routes; #ifdef CONFIG_IP_ROUTE_CLASSID - int fib_num_tclassid_users; + atomic_t fib_num_tclassid_users; #endif struct hlist_head *fib_table_hash; bool fib_offload_disabled; --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1578,7 +1578,7 @@ static int __net_init fib_net_init(struc int error; #ifdef CONFIG_IP_ROUTE_CLASSID - net->ipv4.fib_num_tclassid_users = 0; + atomic_set(&net->ipv4.fib_num_tclassid_users, 0); #endif error = ip_fib_net_init(net); if (error < 0) --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -264,7 +264,7 @@ static int fib4_rule_configure(struct fi if (tb[FRA_FLOW]) { rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); if (rule4->tclassid) - net->ipv4.fib_num_tclassid_users++; + atomic_inc(&net->ipv4.fib_num_tclassid_users); } #endif @@ -296,7 +296,7 @@ static int fib4_rule_delete(struct fib_r #ifdef CONFIG_IP_ROUTE_CLASSID if (((struct fib4_rule *)rule)->tclassid) - net->ipv4.fib_num_tclassid_users--; + atomic_dec(&net->ipv4.fib_num_tclassid_users); #endif net->ipv4.fib_has_custom_rules = true; --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -222,7 +222,7 @@ void fib_nh_release(struct net *net, str { #ifdef CONFIG_IP_ROUTE_CLASSID if (fib_nh->nh_tclassid) - net->ipv4.fib_num_tclassid_users--; + atomic_dec(&net->ipv4.fib_num_tclassid_users); #endif fib_nh_common_release(&fib_nh->nh_common); } @@ -633,7 +633,7 @@ int fib_nh_init(struct net *net, struct #ifdef CONFIG_IP_ROUTE_CLASSID nh->nh_tclassid = cfg->fc_flow; if (nh->nh_tclassid) - net->ipv4.fib_num_tclassid_users++; + atomic_inc(&net->ipv4.fib_num_tclassid_users); #endif #ifdef CONFIG_IP_ROUTE_MULTIPATH nh->fib_nh_weight = nh_weight;