OSDN Git Service

inet: make sure to grab rcu_read_lock before using ireq->ireq_opt
authorEric Dumazet <edumazet@google.com>
Tue, 2 Oct 2018 19:35:05 +0000 (12:35 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Oct 2018 07:13:23 +0000 (09:13 +0200)
[ Upstream commit 2ab2ddd301a22ca3c5f0b743593e4ad2953dfa53 ]

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: 1ad98e9d1bdf ("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>
include/net/inet_sock.h
net/dccp/ipv4.c
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_ipv4.c

index 02255bf..6213a90 100644 (file)
@@ -132,11 +132,6 @@ 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(ireq->ireq_opt);
-}
-
 struct inet_cork {
        unsigned int            flags;
        __be32                  addr;
index 6697b18..28ad6f1 100644 (file)
@@ -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,
                                                              ireq->ir_rmt_addr);
+               rcu_read_lock();
                err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
                                            ireq->ir_rmt_addr,
-                                           ireq_opt_deref(ireq));
+                                           rcu_dereference(ireq->ireq_opt));
+               rcu_read_unlock();
                err = net_xmit_eval(err);
        }
 
index d1cab49..528a677 100644 (file)
@@ -410,7 +410,8 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
        struct ip_options_rcu *opt;
        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,
                           RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
@@ -424,11 +425,13 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
                goto no_route;
        if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
                goto route_err;
+       rcu_read_unlock();
        return &rt->dst;
 
 route_err:
        ip_rt_put(rt);
 no_route:
+       rcu_read_unlock();
        __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
        return NULL;
 }
index 16dea67..1ea0c91 100644 (file)
@@ -859,9 +859,11 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
        if (skb) {
                __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,
                                            ireq->ir_rmt_addr,
-                                           ireq_opt_deref(ireq));
+                                           rcu_dereference(ireq->ireq_opt));
+               rcu_read_unlock();
                err = net_xmit_eval(err);
        }