Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80f03e27 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

tcp: md5: fix rcu lockdep splat



While timer handler effectively runs a rcu read locked section,
there is no explicit rcu_read_lock()/rcu_read_unlock() annotations
and lockdep can be confused here :

net/ipv4/tcp_ipv4.c-906-        /* caller either holds rcu_read_lock() or socket lock */
net/ipv4/tcp_ipv4.c:907:        md5sig = rcu_dereference_check(tp->md5sig_info,
net/ipv4/tcp_ipv4.c-908-                                       sock_owned_by_user(sk) ||
net/ipv4/tcp_ipv4.c-909-                                       lockdep_is_held(&sk->sk_lock.slock));

Let's explicitely acquire rcu_read_lock() in tcp_make_synack()

Before commit fa76ce73 ("inet: get rid of central tcp/dccp listener
timer"), we were holding listener lock so lockdep was happy.

Fixes: fa76ce73 ("inet: get rid of central tcp/dccp listener timer")
Signed-off-by: default avatarEric DUmazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9ead3527
Loading
Loading
Loading
Loading
+11 −9
Original line number Original line Diff line number Diff line
@@ -601,15 +601,14 @@ static unsigned int tcp_synack_options(struct sock *sk,
				   struct request_sock *req,
				   struct request_sock *req,
				   unsigned int mss, struct sk_buff *skb,
				   unsigned int mss, struct sk_buff *skb,
				   struct tcp_out_options *opts,
				   struct tcp_out_options *opts,
				   struct tcp_md5sig_key **md5,
				   const struct tcp_md5sig_key *md5,
				   struct tcp_fastopen_cookie *foc)
				   struct tcp_fastopen_cookie *foc)
{
{
	struct inet_request_sock *ireq = inet_rsk(req);
	struct inet_request_sock *ireq = inet_rsk(req);
	unsigned int remaining = MAX_TCP_OPTION_SPACE;
	unsigned int remaining = MAX_TCP_OPTION_SPACE;


#ifdef CONFIG_TCP_MD5SIG
#ifdef CONFIG_TCP_MD5SIG
	*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
	if (md5) {
	if (*md5) {
		opts->options |= OPTION_MD5;
		opts->options |= OPTION_MD5;
		remaining -= TCPOLEN_MD5SIG_ALIGNED;
		remaining -= TCPOLEN_MD5SIG_ALIGNED;


@@ -620,8 +619,6 @@ static unsigned int tcp_synack_options(struct sock *sk,
		 */
		 */
		ireq->tstamp_ok &= !ireq->sack_ok;
		ireq->tstamp_ok &= !ireq->sack_ok;
	}
	}
#else
	*md5 = NULL;
#endif
#endif


	/* We always send an MSS option. */
	/* We always send an MSS option. */
@@ -2913,7 +2910,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
	struct tcp_sock *tp = tcp_sk(sk);
	struct tcp_sock *tp = tcp_sk(sk);
	struct tcphdr *th;
	struct tcphdr *th;
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct tcp_md5sig_key *md5;
	struct tcp_md5sig_key *md5 = NULL;
	int tcp_header_size;
	int tcp_header_size;
	int mss;
	int mss;


@@ -2938,7 +2935,12 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
	else
	else
#endif
#endif
	skb_mstamp_get(&skb->skb_mstamp);
	skb_mstamp_get(&skb->skb_mstamp);
	tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,

#ifdef CONFIG_TCP_MD5SIG
	rcu_read_lock();
	md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
#endif
	tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,
					     foc) + sizeof(*th);
					     foc) + sizeof(*th);


	skb_push(skb, tcp_header_size);
	skb_push(skb, tcp_header_size);
@@ -2969,10 +2971,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,


#ifdef CONFIG_TCP_MD5SIG
#ifdef CONFIG_TCP_MD5SIG
	/* Okay, we have all we need - do the md5 hash if needed */
	/* Okay, we have all we need - do the md5 hash if needed */
	if (md5) {
	if (md5)
		tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
		tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
					       md5, NULL, req, skb);
					       md5, NULL, req, skb);
	}
	rcu_read_unlock();
#endif
#endif


	return skb;
	return skb;