Commit 2ab2ddd3 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

inet: make sure to grab rcu_read_lock before using ireq->ireq_opt



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: 1ad98e9d ("tcp/dccp: fix lockdep issue when SYN is backlogged")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ff58e2df
Loading
Loading
Loading
Loading
+0 −5
Original line number Original line Diff line number Diff line
@@ -130,11 +130,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;
+3 −1
Original line number Original line Diff line number Diff line
@@ -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);
	}
	}


+4 −1
Original line number Original line Diff line number Diff line
@@ -544,7 +544,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,
@@ -558,11 +559,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;
}
}
+3 −1
Original line number Original line Diff line number Diff line
@@ -943,9 +943,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);
	}
	}