net/tcp: Add tcp_parse_auth_options()

Introduce a helper that:
(1) shares the common code with TCP-MD5 header options parsing
(2) looks for hash signature only once for both TCP-MD5 and TCP-AO
(3) fails with -EEXIST if any TCP sign option is present twice, see
    RFC5925 (2.2):
    ">> A single TCP segment MUST NOT have more than one TCP-AO in its
    options sequence. When multiple TCP-AOs appear, TCP MUST discard
    the segment."

Co-developed-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
Co-developed-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Acked-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Dmitry Safonov
2023-10-23 20:21:59 +01:00
committed by David S. Miller
parent 1e03d32bea
commit f7dca36fc5
7 changed files with 93 additions and 22 deletions

View File

@@ -4255,39 +4255,58 @@ static bool tcp_fast_parse_options(const struct net *net,
return true;
}
#ifdef CONFIG_TCP_MD5SIG
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
/*
* Parse MD5 Signature option
* Parse Signature options
*/
const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
int tcp_do_parse_auth_options(const struct tcphdr *th,
const u8 **md5_hash, const u8 **ao_hash)
{
int length = (th->doff << 2) - sizeof(*th);
const u8 *ptr = (const u8 *)(th + 1);
unsigned int minlen = TCPOLEN_MD5SIG;
if (IS_ENABLED(CONFIG_TCP_AO))
minlen = sizeof(struct tcp_ao_hdr) + 1;
*md5_hash = NULL;
*ao_hash = NULL;
/* If not enough data remaining, we can short cut */
while (length >= TCPOLEN_MD5SIG) {
while (length >= minlen) {
int opcode = *ptr++;
int opsize;
switch (opcode) {
case TCPOPT_EOL:
return NULL;
return 0;
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;
return -EINVAL;
if (opcode == TCPOPT_MD5SIG) {
if (opsize != TCPOLEN_MD5SIG)
return -EINVAL;
if (unlikely(*md5_hash || *ao_hash))
return -EEXIST;
*md5_hash = ptr;
} else if (opcode == TCPOPT_AO) {
if (opsize <= sizeof(struct tcp_ao_hdr))
return -EINVAL;
if (unlikely(*md5_hash || *ao_hash))
return -EEXIST;
*ao_hash = ptr;
}
}
ptr += opsize - 2;
length -= opsize;
}
return NULL;
return 0;
}
EXPORT_SYMBOL(tcp_parse_md5sig_option);
EXPORT_SYMBOL(tcp_do_parse_auth_options);
#endif
/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM