Thread (42 messages) 42 messages, 6 authors, 2022-11-28
STALE1300d
Revisions (3)
  1. v6 [diff vs current]
  2. v7 [diff vs current]
  3. v8 current

[PATCH v8 21/26] tcp: authopt: Try to respect rnextkeyid from SYN on SYNACK

From: Leonard Crestez <hidden>
Date: 2022-09-05 07:09:24
Also in: linux-crypto, linux-kselftest, lkml
Subsystem: networking [general], networking [tcp], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Linus Torvalds

According to the RFC we should use the key that the peer suggests via
rnextkeyid.

This is currently done by storing recv_rnextkeyid in tcp_authopt_info
but this does not work for the SYNACK case because the tcp_request_sock
does not hold an info pointer for reasons of memory usage.

Handle this by storing recv_rnextkeyid inside tcp_request_sock. This
doesn't increase the memory usage because there are unused bytes at the
end.

Signed-off-by: Leonard Crestez <redacted>
---
 include/linux/tcp.h    |  6 ++++++
 net/ipv4/tcp_authopt.c | 14 +++++++++++---
 net/ipv4/tcp_input.c   | 12 ++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 551942883f06..6a4ff0ed55c6 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -125,10 +125,13 @@ struct tcp_options_received {
 	u8	saw_unknown:1,	/* Received unknown option		*/
 		unused:7;
 	u8	num_sacks;	/* Number of SACK blocks		*/
 	u16	user_mss;	/* mss requested by user in ioctl	*/
 	u16	mss_clamp;	/* Maximal mss, negotiated at connection setup */
+#if IS_ENABLED(CONFIG_TCP_AUTHOPT)
+	u8	rnextkeyid;
+#endif
 };
 
 static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
 {
 	rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
@@ -163,10 +166,13 @@ struct tcp_request_sock {
 	u32				rcv_nxt; /* the ack # by SYNACK. For
 						  * FastOpen it's the seq#
 						  * after data-in-SYN.
 						  */
 	u8				syn_tos;
+#if IS_ENABLED(CONFIG_TCP_AUTHOPT)
+	u8				recv_rnextkeyid;
+#endif
 };
 
 static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
 {
 	return (struct tcp_request_sock *)req;
diff --git a/net/ipv4/tcp_authopt.c b/net/ipv4/tcp_authopt.c
index 2a1ddae69b27..a141439d9ebe 100644
--- a/net/ipv4/tcp_authopt.c
+++ b/net/ipv4/tcp_authopt.c
@@ -547,21 +547,29 @@ struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk,
 	struct netns_tcp_authopt *net = sock_net_tcp_authopt(sk);
 	bool anykey = false;
 	int pref_send_id;
 
 	/* Listen sockets don't refer to any specific connection so we don't try
-	 * to keep using the same key and ignore any received keyids.
+	 * to keep using the same key.
+	 * The rnextkeyid is stored in tcp_request_sock
 	 */
 	if (sk->sk_state == TCP_LISTEN) {
+		struct tcp_request_sock *rsk;
+
+		if (WARN_ONCE(addr_sk->sk_state != TCP_NEW_SYN_RECV, "bad socket state"))
+			return NULL;
+		rsk = tcp_rsk((struct request_sock *)addr_sk);
+		/* Forcing a specific send_keyid on a listen socket forces it for
+		 * all clients so is unlikely to be useful.
+		 */
 		if (info->flags & TCP_AUTHOPT_FLAG_LOCK_KEYID)
 			pref_send_id = info->user_pref_send_keyid;
 		else
-			pref_send_id = -1;
+			pref_send_id = rsk->recv_rnextkeyid;
 		key = tcp_authopt_lookup_send(net, addr_sk, pref_send_id, rnextkeyid, &anykey);
 		if (!key && anykey)
 			return ERR_PTR(-ENOKEY);
-
 		return key;
 	}
 
 	/* Try to keep the same sending key unless user or peer requires a different key
 	 * User request (via TCP_AUTHOPT_FLAG_LOCK_KEYID) always overrides peer request.
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4da39c32b934..6f477b110896 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4108,10 +4108,18 @@ void tcp_parse_options(const struct net *net,
 				/*
 				 * The MD5 Hash has already been
 				 * checked (see tcp_v{4,6}_do_rcv()).
 				 */
 				break;
+#endif
+#ifdef CONFIG_TCP_AUTHOPT
+			case TCPOPT_AUTHOPT:
+				/* Hash has already been checked.
+				 * We parse rnextkeyid here so we can match it on synack
+				 */
+				opt_rx->rnextkeyid = ptr[1];
+				break;
 #endif
 			case TCPOPT_FASTOPEN:
 				tcp_parse_fastopen_option(
 					opsize - TCPOLEN_FASTOPEN_BASE,
 					ptr, th->syn, foc, false);
@@ -6964,10 +6972,14 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 		tcp_clear_options(&tmp_opt);
 
 	if (IS_ENABLED(CONFIG_SMC) && want_cookie)
 		tmp_opt.smc_ok = 0;
 
+#if IS_ENABLED(CONFIG_TCP_AUTHOPT)
+	tcp_rsk(req)->recv_rnextkeyid = tmp_opt.rnextkeyid;
+#endif
+
 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 	tcp_openreq_init(req, &tmp_opt, skb, sk);
 	inet_rsk(req)->no_srccheck = inet_sk(sk)->transparent;
 
 	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
-- 
2.25.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help