Message ID | 1508858431.30291.112.camel@edumazet-glaptop3.roam.corp.google.com |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
Series | [v3,net] tcp/dccp: fix other lockdep splats accessing ireq_opt | expand |
From: Eric Dumazet <eric.dumazet@gmail.com> Date: Tue, 24 Oct 2017 08:20:31 -0700 > From: Eric Dumazet <edumazet@google.com> > > In my first attempt to fix the lockdep splat, I forgot we could > enter inet_csk_route_req() with a freshly allocated request socket, > for which refcount has not yet been elevated, due to complex > SLAB_TYPESAFE_BY_RCU rules. > > We either are in rcu_read_lock() section _or_ we own a refcount on the > request. > > Correct RCU verb to use here is rcu_dereference_check(), although it is > not possible to prove we actually own a reference on a shared > refcount :/ > > In v2, I added ireq_opt_deref() helper and use in three places, to fix other > possible splats. ... > Fixes: a6ca7abe53633 ("tcp/dccp: fix lockdep splat in inet_csk_route_req()") > Fixes: c92e8c02fe66 ("tcp/dccp: fix ireq->opt races") > Signed-off-by: Eric Dumazet <edumazet@google.com> > Reported-by: kernel test robot <fengguang.wu@intel.com> > Reported-by: Maciej Żenczykowski <maze@google.com> > --- > v3: fix typo in predicate Applied and queued up for -stable.
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 425752f768d2f1a0efb13964204e07f27609e9db..db8162dd8c0bcbcaffcb1a0f6da1be139a5008d4 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -132,6 +132,12 @@ static inline int inet_request_bound_dev_if(const struct sock *sk, return sk->sk_bound_dev_if; } +static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq) +{ + return rcu_dereference_check(ireq->ireq_opt, + refcount_read(&ireq->req.rsk_refcnt) > 0); +} + struct inet_cork { unsigned int flags; __be32 addr; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 0490916864f93d5466e87f5b97dc524b3ee57a2e..e65fcb45c3f6c1edc70fc9898ebe6404175b102f 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -495,7 +495,7 @@ static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req ireq->ir_rmt_addr); err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, - rcu_dereference(ireq->ireq_opt)); + ireq_opt_deref(ireq)); err = net_xmit_eval(err); } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 18cd2eae758ff1a9d8a736e143417c7007b99067..b47a59cb3573b3b77aa5cbb9c2739a12ef37a237 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -543,8 +543,8 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, struct ip_options_rcu *opt; struct rtable *rt; - opt = rcu_dereference_protected(ireq->ireq_opt, - refcount_read(&req->rsk_refcnt) > 0); + opt = ireq_opt_deref(ireq); + flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4c43365c374c8bf868fc0b862333244ca26d5016..5b027c69cbc540d4e933189f9de5baab5472eadb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -877,7 +877,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, - rcu_dereference(ireq->ireq_opt)); + ireq_opt_deref(ireq)); err = net_xmit_eval(err); }