net/tcp: Consistently align TCP-AO option in the header
authorDmitry Safonov <dima@arista.com>
Mon, 4 Dec 2023 19:00:41 +0000 (19:00 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Wed, 6 Dec 2023 11:36:55 +0000 (12:36 +0100)
Currently functions that pre-calculate TCP header options length use
unaligned TCP-AO header + MAC-length for skb reservation.
And the functions that actually write TCP-AO options into skb do align
the header. Nothing good can come out of this for ((maclen % 4) != 0).

Provide tcp_ao_len_aligned() helper and use it everywhere for TCP
header options space calculations.

Fixes: 1e03d32bea8e ("net/tcp: Add TCP-AO sign to outgoing packets")
Signed-off-by: Dmitry Safonov <dima@arista.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/tcp_ao.h
net/ipv4/tcp_ao.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv6/tcp_ipv6.c

index b56be10838f09a2cb56ab511242d2b583eb4c33b..6477810806137dbf7f0262ada4a64ebb568c690b 100644 (file)
@@ -62,11 +62,17 @@ static inline int tcp_ao_maclen(const struct tcp_ao_key *key)
        return key->maclen;
 }
 
+/* Use tcp_ao_len_aligned() for TCP header calculations */
 static inline int tcp_ao_len(const struct tcp_ao_key *key)
 {
        return tcp_ao_maclen(key) + sizeof(struct tcp_ao_hdr);
 }
 
+static inline int tcp_ao_len_aligned(const struct tcp_ao_key *key)
+{
+       return round_up(tcp_ao_len(key), 4);
+}
+
 static inline unsigned int tcp_ao_digest_size(struct tcp_ao_key *key)
 {
        return key->digest_size;
index 7696417d064011d3b437c2035b6fe1e5a3a0e6df..c8be1d526eac1bcbc92b1eb06316949218441426 100644 (file)
@@ -1100,7 +1100,7 @@ void tcp_ao_connect_init(struct sock *sk)
                        ao_info->current_key = key;
                if (!ao_info->rnext_key)
                        ao_info->rnext_key = key;
-               tp->tcp_header_len += tcp_ao_len(key);
+               tp->tcp_header_len += tcp_ao_len_aligned(key);
 
                ao_info->lisn = htonl(tp->write_seq);
                ao_info->snd_sne = 0;
@@ -1346,7 +1346,7 @@ static int tcp_ao_parse_crypto(struct tcp_ao_add *cmd, struct tcp_ao_key *key)
        syn_tcp_option_space -= TCPOLEN_MSS_ALIGNED;
        syn_tcp_option_space -= TCPOLEN_TSTAMP_ALIGNED;
        syn_tcp_option_space -= TCPOLEN_WSCALE_ALIGNED;
-       if (tcp_ao_len(key) > syn_tcp_option_space) {
+       if (tcp_ao_len_aligned(key) > syn_tcp_option_space) {
                err = -EMSGSIZE;
                goto err_kfree;
        }
index 5f693bbd578d2261b78aa0be6bf69499bbd5117e..0c50c5a32b84a3b601510655ecaa39b46a8f0b34 100644 (file)
@@ -690,7 +690,7 @@ static bool tcp_v4_ao_sign_reset(const struct sock *sk, struct sk_buff *skb,
 
        reply_options[0] = htonl((TCPOPT_AO << 24) | (tcp_ao_len(key) << 16) |
                                 (aoh->rnext_keyid << 8) | keyid);
-       arg->iov[0].iov_len += round_up(tcp_ao_len(key), 4);
+       arg->iov[0].iov_len += tcp_ao_len_aligned(key);
        reply->doff = arg->iov[0].iov_len / 4;
 
        if (tcp_ao_hash_hdr(AF_INET, (char *)&reply_options[1],
@@ -978,7 +978,7 @@ static void tcp_v4_send_ack(const struct sock *sk,
                                          (tcp_ao_len(key->ao_key) << 16) |
                                          (key->ao_key->sndid << 8) |
                                          key->rcv_next);
-               arg.iov[0].iov_len += round_up(tcp_ao_len(key->ao_key), 4);
+               arg.iov[0].iov_len += tcp_ao_len_aligned(key->ao_key);
                rep.th.doff = arg.iov[0].iov_len / 4;
 
                tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset],
index a9807eeb311ca6a276a8ab87ed359819f816cf41..9e85f2a0bddd4978b1bde6add1efc6aad351db8b 100644 (file)
@@ -615,7 +615,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
        ao_key = treq->af_specific->ao_lookup(sk, req,
                                tcp_rsk(req)->ao_keyid, -1);
        if (ao_key)
-               newtp->tcp_header_len += tcp_ao_len(ao_key);
+               newtp->tcp_header_len += tcp_ao_len_aligned(ao_key);
  #endif
        if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)
                newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
index eb13a55d660c2376968f11ee3265280f8cc9e1bd..93eef1dbbc552922b3b3e72e400f7f3804d3a4cb 100644 (file)
@@ -825,7 +825,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
                timestamps = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps);
                if (tcp_key_is_ao(key)) {
                        opts->options |= OPTION_AO;
-                       remaining -= tcp_ao_len(key->ao_key);
+                       remaining -= tcp_ao_len_aligned(key->ao_key);
                }
        }
 
@@ -915,7 +915,7 @@ static unsigned int tcp_synack_options(const struct sock *sk,
                        ireq->tstamp_ok &= !ireq->sack_ok;
        } else if (tcp_key_is_ao(key)) {
                opts->options |= OPTION_AO;
-               remaining -= tcp_ao_len(key->ao_key);
+               remaining -= tcp_ao_len_aligned(key->ao_key);
                ireq->tstamp_ok &= !ireq->sack_ok;
        }
 
@@ -982,7 +982,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
                size += TCPOLEN_MD5SIG_ALIGNED;
        } else if (tcp_key_is_ao(key)) {
                opts->options |= OPTION_AO;
-               size += tcp_ao_len(key->ao_key);
+               size += tcp_ao_len_aligned(key->ao_key);
        }
 
        if (likely(tp->rx_opt.tstamp_ok)) {
index 937a02c2e5345390ed592b19faa661cd703a23f0..8c6623496dd7e9daf4cb63528a4817b3c65a334a 100644 (file)
@@ -881,7 +881,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
        if (tcp_key_is_md5(key))
                tot_len += TCPOLEN_MD5SIG_ALIGNED;
        if (tcp_key_is_ao(key))
-               tot_len += tcp_ao_len(key->ao_key);
+               tot_len += tcp_ao_len_aligned(key->ao_key);
 
 #ifdef CONFIG_MPTCP
        if (rst && !tcp_key_is_md5(key)) {