inet: make sure to grab rcu_read_lock before using ireq->ireq_opt
[ Upstream commitpull/10/head2ab2ddd301
] Timer handlers do not imply rcu_read_lock(), so my recent fix triggered a LOCKDEP warning when SYNACK is retransmit. Lets add rcu_read_lock()/rcu_read_unlock() pairs around ireq->ireq_opt usages instead of guessing what is done by callers, since it is not worth the pain. Get rid of ireq_opt_deref() helper since it hides the logic without real benefit, since it is now a standard rcu_dereference(). Fixes:1ad98e9d1b
("tcp/dccp: fix lockdep issue when SYN is backlogged") Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
parent
17af5475ae
commit
c5df581389
|
@ -129,11 +129,6 @@ static inline int inet_request_bound_dev_if(const struct sock *sk,
|
||||||
return sk->sk_bound_dev_if;
|
return sk->sk_bound_dev_if;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq)
|
|
||||||
{
|
|
||||||
return rcu_dereference(ireq->ireq_opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct inet_cork {
|
struct inet_cork {
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
__be32 addr;
|
__be32 addr;
|
||||||
|
|
|
@ -493,9 +493,11 @@ static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req
|
||||||
|
|
||||||
dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr,
|
dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr,
|
||||||
ireq->ir_rmt_addr);
|
ireq->ir_rmt_addr);
|
||||||
|
rcu_read_lock();
|
||||||
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
||||||
ireq->ir_rmt_addr,
|
ireq->ir_rmt_addr,
|
||||||
ireq_opt_deref(ireq));
|
rcu_dereference(ireq->ireq_opt));
|
||||||
|
rcu_read_unlock();
|
||||||
err = net_xmit_eval(err);
|
err = net_xmit_eval(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -542,7 +542,8 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
|
||||||
struct ip_options_rcu *opt;
|
struct ip_options_rcu *opt;
|
||||||
struct rtable *rt;
|
struct rtable *rt;
|
||||||
|
|
||||||
opt = ireq_opt_deref(ireq);
|
rcu_read_lock();
|
||||||
|
opt = rcu_dereference(ireq->ireq_opt);
|
||||||
|
|
||||||
flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark,
|
flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark,
|
||||||
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
|
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
|
||||||
|
@ -556,11 +557,13 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
|
||||||
goto no_route;
|
goto no_route;
|
||||||
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
|
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
|
||||||
goto route_err;
|
goto route_err;
|
||||||
|
rcu_read_unlock();
|
||||||
return &rt->dst;
|
return &rt->dst;
|
||||||
|
|
||||||
route_err:
|
route_err:
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
no_route:
|
no_route:
|
||||||
|
rcu_read_unlock();
|
||||||
__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
|
__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -875,9 +875,11 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
|
||||||
if (skb) {
|
if (skb) {
|
||||||
__tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
|
__tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
|
||||||
ireq->ir_rmt_addr,
|
ireq->ir_rmt_addr,
|
||||||
ireq_opt_deref(ireq));
|
rcu_dereference(ireq->ireq_opt));
|
||||||
|
rcu_read_unlock();
|
||||||
err = net_xmit_eval(err);
|
err = net_xmit_eval(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue