From: Leonard Crestez <cdleonard@gmail.com>
To: David Ahern <dsahern@kernel.org>,
Eric Dumazet <edumazet@google.com>,
Philip Paeps <philip@trouble.is>
Cc: Dmitry Safonov <0x7f454c46@gmail.com>,
Shuah Khan <shuah@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Herbert Xu <herbert@gondor.apana.org.au>,
Kuniyuki Iwashima <kuniyu@amazon.co.jp>,
Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>,
Jakub Kicinski <kuba@kernel.org>,
Yuchung Cheng <ycheng@google.com>,
Francesco Ruggeri <fruggeri@arista.com>,
Mat Martineau <mathew.j.martineau@linux.intel.com>,
Christoph Paasch <cpaasch@apple.com>,
Ivan Delalande <colona@arista.com>,
Caowangbao <caowangbao@huawei.com>,
Priyaranjan Jha <priyarjha@google.com>,
netdev@vger.kernel.org, linux-crypto@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v7 06/26] tcp: Refactor tcp_inbound_md5_hash into tcp_inbound_sig_hash
Date: Thu, 18 Aug 2022 22:59:40 +0300 [thread overview]
Message-ID: <42b7fa32c0fca77abb1e6a234f2dac45798f605b.1660852705.git.cdleonard@gmail.com> (raw)
In-Reply-To: <cover.1660852705.git.cdleonard@gmail.com>
The TCP-MD5 and TCP-AO signature options must be handled together so
replace the old tcp_inbound_md5_hash with tcp_inbound_sig_hash which
will handle both options.
As a side effect of this change Linux will start dropping packets where
both MD5 and AO are present instead of ignoring the so-far unrecognized
AO option. This is a direct requirement from RFC5925 2.2
This difference can be detected remotely without ever establishing a
connection and used to fingerprint linux version. This seems acceptable.
Signed-off-by: Leonard Crestez <cdleonard@gmail.com>
---
include/net/dropreason.h | 4 ++++
include/net/tcp.h | 52 +++++++++++++++++++++++++++++-----------
net/ipv4/tcp.c | 39 ++++++++++++++++++++++++++----
net/ipv4/tcp_input.c | 39 ++++++++++++++++++++++--------
net/ipv4/tcp_ipv4.c | 12 +++++-----
net/ipv6/tcp_ipv6.c | 8 +++----
6 files changed, 115 insertions(+), 39 deletions(-)
diff --git a/include/net/dropreason.h b/include/net/dropreason.h
index fae9b40e54fa..c5397c24296c 100644
--- a/include/net/dropreason.h
+++ b/include/net/dropreason.h
@@ -229,10 +229,14 @@ enum skb_drop_reason {
/**
* @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the
* MTU)
*/
SKB_DROP_REASON_PKT_TOO_BIG,
+ /**
+ * @SKB_DROP_REASON_TCP_BOTHAOMD5: Both AO and MD5 found in packet.
+ */
+ SKB_DROP_REASON_TCP_BOTHAOMD5,
/**
* @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
* used as a real 'reason'
*/
SKB_DROP_REASON_MAX,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index fbe18b5bf576..96e7e406e324 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -424,11 +424,33 @@ int tcp_mmap(struct file *file, struct socket *sock,
struct vm_area_struct *vma);
#endif
void tcp_parse_options(const struct net *net, const struct sk_buff *skb,
struct tcp_options_received *opt_rx,
int estab, struct tcp_fastopen_cookie *foc);
-const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
+#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
+enum skb_drop_reason tcp_parse_sig_options(const struct tcphdr *th,
+ const u8 **md5ptr,
+ const u8 **aoptr);
+#else
+static inline enum skb_drop_reason tcp_parse_sig_options(const struct tcphdr *th,
+ const u8 **md5ptr,
+ const u8 **aoptr)
+{
+ *aoptr = NULL;
+ *md5ptr = NULL;
+ return 0;
+}
+#endif
+static inline const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
+{
+ const u8 *md5, *ao;
+ int ret;
+
+ ret = tcp_parse_sig_options(th, &md5, &ao);
+
+ return (md5 && !ao && !ret) ? md5 : NULL;
+}
/*
* BPF SKB-less helpers
*/
u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
@@ -1685,32 +1707,19 @@ tcp_md5_do_lookup(const struct sock *sk, int l3index,
if (!static_branch_unlikely(&tcp_md5_needed))
return NULL;
return __tcp_md5_do_lookup(sk, l3index, addr, family);
}
-enum skb_drop_reason
-tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
- const void *saddr, const void *daddr,
- int family, int dif, int sdif);
-
-
#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_key)
#else
static inline struct tcp_md5sig_key *
tcp_md5_do_lookup(const struct sock *sk, int l3index,
const union tcp_md5_addr *addr, int family)
{
return NULL;
}
-static inline enum skb_drop_reason
-tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
- const void *saddr, const void *daddr,
- int family, int dif, int sdif)
-{
- return SKB_NOT_DROPPED_YET;
-}
#define tcp_twsk_md5_key(twsk) NULL
#endif
bool tcp_alloc_md5sig_pool(void);
@@ -1723,10 +1732,25 @@ static inline void tcp_put_md5sig_pool(void)
int tcp_sig_hash_skb_data(struct ahash_request *, const struct sk_buff *,
unsigned int header_len);
int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
const struct tcp_md5sig_key *key);
+#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
+enum skb_drop_reason
+tcp_inbound_sig_hash(const struct sock *sk, const struct sk_buff *skb,
+ const void *saddr, const void *daddr,
+ int family, int dif, int sdif);
+#else
+static inline enum skb_drop_reason
+tcp_inbound_sig_hash(const struct sock *sk, const struct sk_buff *skb,
+ const void *saddr, const void *daddr,
+ int family, int dif, int sdif)
+{
+ return SKB_NOT_DROPPED_YET;
+}
+#endif
+
/* From tcp_fastopen.c */
void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
struct tcp_fastopen_cookie *cookie);
void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
struct tcp_fastopen_cookie *cookie, bool syn_lost,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 4c61c32ccf49..0611a2160b63 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4568,24 +4568,24 @@ int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *ke
return data_race(crypto_ahash_update(hp->md5_req));
}
EXPORT_SYMBOL(tcp_md5_hash_key);
/* Called with rcu_read_lock() */
-enum skb_drop_reason
+static enum skb_drop_reason
tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
const void *saddr, const void *daddr,
- int family, int dif, int sdif)
+ int family, int dif, int sdif,
+ const u8 *hash_location)
{
/*
* This gets called for each TCP segment that arrives
* so we want to be efficient.
* We have 3 drop cases:
* o No MD5 hash and one expected.
* o MD5 hash and we're not expecting one.
* o MD5 hash and its wrong.
*/
- const __u8 *hash_location = NULL;
struct tcp_md5sig_key *hash_expected;
const struct tcphdr *th = tcp_hdr(skb);
struct tcp_sock *tp = tcp_sk(sk);
int genhash, l3index;
u8 newhash[16];
@@ -4594,11 +4594,10 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
* in an L3 domain and dif is set to the l3mdev
*/
l3index = sdif ? dif : 0;
hash_expected = tcp_md5_do_lookup(sk, l3index, saddr, family);
- hash_location = tcp_parse_md5sig_option(th);
/* We've parsed the options - do we have a hash? */
if (!hash_expected && !hash_location)
return SKB_NOT_DROPPED_YET;
@@ -4641,14 +4640,44 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
}
return SKB_DROP_REASON_TCP_MD5FAILURE;
}
return SKB_NOT_DROPPED_YET;
}
-EXPORT_SYMBOL(tcp_inbound_md5_hash);
#endif /* CONFIG_TCP_MD5SIG */
+#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
+
+enum skb_drop_reason
+tcp_inbound_sig_hash(const struct sock *sk, const struct sk_buff *skb,
+ const void *saddr, const void *daddr,
+ int family, int dif, int sdif)
+{
+ /* FIXME: Restore reqsk handling */
+ const u8 *md5, *ao;
+ enum skb_drop_reason ret;
+ const struct sock *parent_sk;
+
+ if (sk->sk_state == TCP_NEW_SYN_RECV)
+ parent_sk = inet_reqsk(sk)->rsk_listener;
+ else
+ parent_sk = sk;
+
+ ret = tcp_parse_sig_options(tcp_hdr(skb), &md5, &ao);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_TCP_MD5SIG
+ return tcp_inbound_md5_hash(parent_sk, skb, saddr, daddr, family, dif, sdif, md5);
+#else
+ return SKB_NOT_DROPPED_YET;
+#endif
+}
+EXPORT_SYMBOL(tcp_inbound_sig_hash);
+
+#endif /* defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT) */
+
void tcp_done(struct sock *sk)
{
struct request_sock *req;
/* We might be called with a new socket, after
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ab5f0ea166f1..fa20afd15248 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4186,43 +4186,62 @@ static bool tcp_fast_parse_options(const struct net *net,
tp->rx_opt.rcv_tsecr -= tp->tsoffset;
return true;
}
-#ifdef CONFIG_TCP_MD5SIG
+#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
/*
- * Parse MD5 Signature option
+ * Parse MD5 and AO options
+ *
+ * md5ptr: pointer to content of MD5 option (16-byte hash)
+ * aoptr: pointer to start of AO option (variable length)
*/
-const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
+enum skb_drop_reason tcp_parse_sig_options(const struct tcphdr *th,
+ const u8 **md5ptr,
+ const u8 **aoptr)
{
int length = (th->doff << 2) - sizeof(*th);
const u8 *ptr = (const u8 *)(th + 1);
+ *md5ptr = NULL;
+ *aoptr = NULL;
+
/* If not enough data remaining, we can short cut */
- while (length >= TCPOLEN_MD5SIG) {
+ while (length >= 4) {
int opcode = *ptr++;
int opsize;
switch (opcode) {
case TCPOPT_EOL:
- return NULL;
+ goto out;
case TCPOPT_NOP:
length--;
continue;
default:
opsize = *ptr++;
if (opsize < 2 || opsize > length)
- return NULL;
- if (opcode == TCPOPT_MD5SIG)
- return opsize == TCPOLEN_MD5SIG ? ptr : NULL;
+ goto out;
+ if (opcode == TCPOPT_MD5SIG && opsize == TCPOLEN_MD5SIG)
+ *md5ptr = ptr;
+ if (opcode == TCPOPT_AUTHOPT)
+ *aoptr = ptr - 2;
}
ptr += opsize - 2;
length -= opsize;
}
- return NULL;
+
+out:
+ /* RFC5925 2.2: An endpoint MUST NOT use TCP-AO for the same connection
+ * in which TCP MD5 is used. When both options appear, TCP MUST silently
+ * discard the segment.
+ */
+ if (*md5ptr && *aoptr)
+ return SKB_DROP_REASON_TCP_BOTHAOMD5;
+
+ return SKB_NOT_DROPPED_YET;
}
-EXPORT_SYMBOL(tcp_parse_md5sig_option);
+EXPORT_SYMBOL(tcp_parse_sig_options);
#endif
/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
*
* It is not fatal. If this ACK does _not_ change critical state (seqs, window)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 46ba754afd2b..58b5f197bde1 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1964,17 +1964,17 @@ int tcp_v4_rcv(struct sk_buff *skb)
if (sk->sk_state == TCP_NEW_SYN_RECV) {
struct request_sock *req = inet_reqsk(sk);
bool req_stolen = false;
struct sock *nsk;
- sk = req->rsk_listener;
- if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
+ if (!xfrm4_policy_check(req->rsk_listener, XFRM_POLICY_IN, skb))
drop_reason = SKB_DROP_REASON_XFRM_POLICY;
else
- drop_reason = tcp_inbound_md5_hash(sk, skb,
- &iph->saddr, &iph->daddr,
- AF_INET, dif, sdif);
+ drop_reason = tcp_inbound_sig_hash(sk, skb,
+ &iph->saddr, &iph->daddr,
+ AF_INET, dif, sdif);
+ sk = req->rsk_listener;
if (unlikely(drop_reason)) {
sk_drops_add(sk, skb);
reqsk_put(req);
goto discard_it;
}
@@ -2046,11 +2046,11 @@ int tcp_v4_rcv(struct sk_buff *skb)
if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
drop_reason = SKB_DROP_REASON_XFRM_POLICY;
goto discard_and_relse;
}
- drop_reason = tcp_inbound_md5_hash(sk, skb, &iph->saddr,
+ drop_reason = tcp_inbound_sig_hash(sk, skb, &iph->saddr,
&iph->daddr, AF_INET, dif, sdif);
if (drop_reason)
goto discard_and_relse;
nf_reset_ct(skb);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 30dc9d4eec83..2edfe631878e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1632,14 +1632,14 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
if (sk->sk_state == TCP_NEW_SYN_RECV) {
struct request_sock *req = inet_reqsk(sk);
bool req_stolen = false;
struct sock *nsk;
- sk = req->rsk_listener;
- drop_reason = tcp_inbound_md5_hash(sk, skb,
+ drop_reason = tcp_inbound_sig_hash(sk, skb,
&hdr->saddr, &hdr->daddr,
AF_INET6, dif, sdif);
+ sk = req->rsk_listener;
if (drop_reason) {
sk_drops_add(sk, skb);
reqsk_put(req);
goto discard_it;
}
@@ -1707,12 +1707,12 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
drop_reason = SKB_DROP_REASON_XFRM_POLICY;
goto discard_and_relse;
}
- drop_reason = tcp_inbound_md5_hash(sk, skb, &hdr->saddr, &hdr->daddr,
- AF_INET6, dif, sdif);
+ drop_reason = tcp_inbound_sig_hash(sk, skb, &hdr->saddr,
+ &hdr->daddr, AF_INET6, dif, sdif);
if (drop_reason)
goto discard_and_relse;
if (tcp_filter(sk, skb)) {
drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
--
2.25.1
next prev parent reply other threads:[~2022-08-18 20:00 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-18 19:59 [PATCH v7 00/26] tcp: Initial support for RFC5925 auth option Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 01/26] tcp: authopt: Initial support and key management Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 02/26] docs: Add user documentation for tcp_authopt Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 03/26] tcp: authopt: Add crypto initialization Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 04/26] tcp: Refactor tcp_sig_hash_skb_data for AO Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 05/26] tcp: authopt: Compute packet signatures Leonard Crestez
2022-08-18 19:59 ` Leonard Crestez [this message]
2022-08-18 19:59 ` [PATCH v7 07/26] tcp: authopt: Hook into tcp core Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 08/26] tcp: authopt: Disable via sysctl by default Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 09/26] tcp: authopt: Implement Sequence Number Extension Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 10/26] tcp: ipv6: Add AO signing for tcp_v6_send_response Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 11/26] tcp: authopt: Add support for signing skb-less replies Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 12/26] tcp: ipv4: Add AO signing for " Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 13/26] tcp: authopt: Add key selection controls Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 14/26] tcp: authopt: Add initial l3index support Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 15/26] tcp: authopt: Add NOSEND/NORECV flags Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 16/26] tcp: authopt: Add prefixlen support Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 17/26] tcp: authopt: Add v4mapped ipv6 address support Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 18/26] tcp: authopt: Add /proc/net/tcp_authopt listing all keys Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 19/26] selftests: nettest: Rename md5_prefix to key_addr_prefix Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 20/26] selftests: nettest: Initial tcp_authopt support Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 21/26] selftests: net/fcnal: " Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 22/26] tcp: authopt: Try to respect rnextkeyid from SYN on SYNACK Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 23/26] tcp: authopt: tcp_authopt_lookup_send: Add anykey output param Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 24/26] tcp: authopt: Initial support for TCP_AUTHOPT_FLAG_ACTIVE Leonard Crestez
2022-08-18 19:59 ` [PATCH v7 25/26] tcp: authopt: If no keys are valid for send report an error Leonard Crestez
2022-08-18 20:00 ` [PATCH v7 26/26] tcp: authopt: Initial implementation of TCP_REPAIR_AUTHOPT Leonard Crestez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=42b7fa32c0fca77abb1e6a234f2dac45798f605b.1660852705.git.cdleonard@gmail.com \
--to=cdleonard@gmail.com \
--cc=0x7f454c46@gmail.com \
--cc=caowangbao@huawei.com \
--cc=colona@arista.com \
--cc=cpaasch@apple.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=fruggeri@arista.com \
--cc=herbert@gondor.apana.org.au \
--cc=kuba@kernel.org \
--cc=kuniyu@amazon.co.jp \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mathew.j.martineau@linux.intel.com \
--cc=netdev@vger.kernel.org \
--cc=philip@trouble.is \
--cc=priyarjha@google.com \
--cc=shuah@kernel.org \
--cc=ycheng@google.com \
--cc=yoshfuji@linux-ipv6.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).