]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tcp/dccp: fix other lockdep splats accessing ireq_opt
authorEric Dumazet <edumazet@google.com>
Tue, 24 Oct 2017 15:20:31 +0000 (08:20 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 18 Nov 2017 10:11:07 +0000 (11:11 +0100)
[ Upstream commit 06f877d613be3621604c2520ec0351d9fbdca15f ]

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.

[   49.844590]  lockdep_rcu_suspicious+0xea/0xf3
[   49.846487]  inet_csk_route_req+0x53/0x14d
[   49.848334]  tcp_v4_route_req+0xe/0x10
[   49.850174]  tcp_conn_request+0x31c/0x6a0
[   49.851992]  ? __lock_acquire+0x614/0x822
[   49.854015]  tcp_v4_conn_request+0x5a/0x79
[   49.855957]  ? tcp_v4_conn_request+0x5a/0x79
[   49.858052]  tcp_rcv_state_process+0x98/0xdcc
[   49.859990]  ? sk_filter_trim_cap+0x2f6/0x307
[   49.862085]  tcp_v4_do_rcv+0xfc/0x145
[   49.864055]  ? tcp_v4_do_rcv+0xfc/0x145
[   49.866173]  tcp_v4_rcv+0x5ab/0xaf9
[   49.868029]  ip_local_deliver_finish+0x1af/0x2e7
[   49.870064]  ip_local_deliver+0x1b2/0x1c5
[   49.871775]  ? inet_del_offload+0x45/0x45
[   49.873916]  ip_rcv_finish+0x3f7/0x471
[   49.875476]  ip_rcv+0x3f1/0x42f
[   49.876991]  ? ip_local_deliver_finish+0x2e7/0x2e7
[   49.878791]  __netif_receive_skb_core+0x6d3/0x950
[   49.880701]  ? process_backlog+0x7e/0x216
[   49.882589]  __netif_receive_skb+0x1d/0x5e
[   49.884122]  process_backlog+0x10c/0x216
[   49.885812]  net_rx_action+0x147/0x3df

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>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/net/inet_sock.h
net/dccp/ipv4.c
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_ipv4.c

index e2113db93d5f1b3efc1bd10c9073cdd92457eb14..95aa999f31d7c4813b515a5c3ba01b471e16796e 100644 (file)
@@ -113,6 +113,12 @@ static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb)
        return sk->sk_mark;
 }
 
+static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq)
+{
+       return rcu_dereference_check(ireq->ireq_opt,
+                                    atomic_read(&ireq->req.rsk_refcnt) > 0);
+}
+
 struct inet_cork {
        unsigned int            flags;
        __be32                  addr;
index 888ff5a24ec4178bb620dda322077b6bff60aec7..6eb2bbf9873b97c805cd81411af81ce26cc6027f 100644 (file)
@@ -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);
        }
 
index 74bc77ae551b37d3a0e574c167e0085deedc17b8..01acb94c4963441f93f6a19d81325e224de58326 100644 (file)
@@ -415,8 +415,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,
-                                       atomic_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),
index 85293a285c500eeb2c857d6cf64be49ae14ecd31..a5d790c13ef5e015ebdee6c0910de3c0ba3f2e28 100644 (file)
@@ -856,7 +856,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);
        }