Skip to content

Commit 9427c6a

Browse files
0x7f454c46davem330
authored andcommitted
net/tcp: Sign SYN-ACK segments with TCP-AO
Similarly to RST segments, wire SYN-ACKs to TCP-AO. tcp_rsk_used_ao() is handy here to check if the request socket used AO and needs a signature on the outgoing segments. Co-developed-by: Francesco Ruggeri <[email protected]> Signed-off-by: Francesco Ruggeri <[email protected]> Co-developed-by: Salam Noureddine <[email protected]> Signed-off-by: Salam Noureddine <[email protected]> Signed-off-by: Dmitry Safonov <[email protected]> Acked-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 06b22ef commit 9427c6a

File tree

7 files changed

+111
-16
lines changed

7 files changed

+111
-16
lines changed

include/net/tcp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,6 +2221,9 @@ struct tcp_request_sock_ops {
22212221
struct request_sock *req,
22222222
int sndid, int rcvid);
22232223
int (*ao_calc_key)(struct tcp_ao_key *mkt, u8 *key, struct request_sock *sk);
2224+
int (*ao_synack_hash)(char *ao_hash, struct tcp_ao_key *mkt,
2225+
struct request_sock *req, const struct sk_buff *skb,
2226+
int hash_offset, u32 sne);
22242227
#endif
22252228
#ifdef CONFIG_SYN_COOKIES
22262229
__u32 (*cookie_init_seq)(const struct sk_buff *skb,

include/net/tcp_ao.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
147147
int tcp_v4_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen);
148148
struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk,
149149
int sndid, int rcvid);
150+
int tcp_v4_ao_synack_hash(char *ao_hash, struct tcp_ao_key *mkt,
151+
struct request_sock *req, const struct sk_buff *skb,
152+
int hash_offset, u32 sne);
150153
int tcp_v4_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
151154
const struct sock *sk,
152155
__be32 sisn, __be32 disn, bool send);
@@ -181,6 +184,9 @@ int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
181184
const struct sock *sk, const struct sk_buff *skb,
182185
const u8 *tkey, int hash_offset, u32 sne);
183186
int tcp_v6_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen);
187+
int tcp_v6_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key,
188+
struct request_sock *req, const struct sk_buff *skb,
189+
int hash_offset, u32 sne);
184190
void tcp_ao_established(struct sock *sk);
185191
void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb);
186192
void tcp_ao_connect_init(struct sock *sk);

net/ipv4/tcp_ao.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,28 @@ int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
568568
tkey, hash_offset, sne);
569569
}
570570

571+
int tcp_v4_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key,
572+
struct request_sock *req, const struct sk_buff *skb,
573+
int hash_offset, u32 sne)
574+
{
575+
void *hash_buf = NULL;
576+
int err;
577+
578+
hash_buf = kmalloc(tcp_ao_digest_size(ao_key), GFP_ATOMIC);
579+
if (!hash_buf)
580+
return -ENOMEM;
581+
582+
err = tcp_v4_ao_calc_key_rsk(ao_key, hash_buf, req);
583+
if (err)
584+
goto out;
585+
586+
err = tcp_ao_hash_skb(AF_INET, ao_hash, ao_key, req_to_sk(req), skb,
587+
hash_buf, hash_offset, sne);
588+
out:
589+
kfree(hash_buf);
590+
return err;
591+
}
592+
571593
struct tcp_ao_key *tcp_v4_ao_lookup_rsk(const struct sock *sk,
572594
struct request_sock *req,
573595
int sndid, int rcvid)

net/ipv4/tcp_ipv4.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
16811681
#ifdef CONFIG_TCP_AO
16821682
.ao_lookup = tcp_v4_ao_lookup_rsk,
16831683
.ao_calc_key = tcp_v4_ao_calc_key_rsk,
1684+
.ao_synack_hash = tcp_v4_ao_synack_hash,
16841685
#endif
16851686
#ifdef CONFIG_SYN_COOKIES
16861687
.cookie_init_seq = cookie_v4_init_sequence,

net/ipv4/tcp_output.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -886,16 +886,15 @@ static unsigned int tcp_synack_options(const struct sock *sk,
886886
struct request_sock *req,
887887
unsigned int mss, struct sk_buff *skb,
888888
struct tcp_out_options *opts,
889-
const struct tcp_md5sig_key *md5,
889+
const struct tcp_key *key,
890890
struct tcp_fastopen_cookie *foc,
891891
enum tcp_synack_type synack_type,
892892
struct sk_buff *syn_skb)
893893
{
894894
struct inet_request_sock *ireq = inet_rsk(req);
895895
unsigned int remaining = MAX_TCP_OPTION_SPACE;
896896

897-
#ifdef CONFIG_TCP_MD5SIG
898-
if (md5) {
897+
if (tcp_key_is_md5(key)) {
899898
opts->options |= OPTION_MD5;
900899
remaining -= TCPOLEN_MD5SIG_ALIGNED;
901900

@@ -906,8 +905,11 @@ static unsigned int tcp_synack_options(const struct sock *sk,
906905
*/
907906
if (synack_type != TCP_SYNACK_COOKIE)
908907
ireq->tstamp_ok &= !ireq->sack_ok;
908+
} else if (tcp_key_is_ao(key)) {
909+
opts->options |= OPTION_AO;
910+
remaining -= tcp_ao_len(key->ao_key);
911+
ireq->tstamp_ok &= !ireq->sack_ok;
909912
}
910-
#endif
911913

912914
/* We always send an MSS option. */
913915
opts->mss = mss;
@@ -3653,7 +3655,6 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
36533655
{
36543656
struct inet_request_sock *ireq = inet_rsk(req);
36553657
const struct tcp_sock *tp = tcp_sk(sk);
3656-
struct tcp_md5sig_key *md5 = NULL;
36573658
struct tcp_out_options opts;
36583659
struct tcp_key key = {};
36593660
struct sk_buff *skb;
@@ -3707,18 +3708,48 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
37073708
tcp_rsk(req)->snt_synack = tcp_skb_timestamp_us(skb);
37083709
}
37093710

3710-
#ifdef CONFIG_TCP_MD5SIG
3711+
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
37113712
rcu_read_lock();
3712-
md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));
3713-
if (md5)
3714-
key.type = TCP_KEY_MD5;
37153713
#endif
3714+
if (tcp_rsk_used_ao(req)) {
3715+
#ifdef CONFIG_TCP_AO
3716+
struct tcp_ao_key *ao_key = NULL;
3717+
u8 maclen = tcp_rsk(req)->maclen;
3718+
u8 keyid = tcp_rsk(req)->ao_keyid;
3719+
3720+
ao_key = tcp_sk(sk)->af_specific->ao_lookup(sk, req_to_sk(req),
3721+
keyid, -1);
3722+
/* If there is no matching key - avoid sending anything,
3723+
* especially usigned segments. It could try harder and lookup
3724+
* for another peer-matching key, but the peer has requested
3725+
* ao_keyid (RFC5925 RNextKeyID), so let's keep it simple here.
3726+
*/
3727+
if (unlikely(!ao_key || tcp_ao_maclen(ao_key) != maclen)) {
3728+
u8 key_maclen = ao_key ? tcp_ao_maclen(ao_key) : 0;
3729+
3730+
rcu_read_unlock();
3731+
kfree_skb(skb);
3732+
net_warn_ratelimited("TCP-AO: the keyid %u with maclen %u|%u from SYN packet is not present - not sending SYNACK\n",
3733+
keyid, maclen, key_maclen);
3734+
return NULL;
3735+
}
3736+
key.ao_key = ao_key;
3737+
key.type = TCP_KEY_AO;
3738+
#endif
3739+
} else {
3740+
#ifdef CONFIG_TCP_MD5SIG
3741+
key.md5_key = tcp_rsk(req)->af_specific->req_md5_lookup(sk,
3742+
req_to_sk(req));
3743+
if (key.md5_key)
3744+
key.type = TCP_KEY_MD5;
3745+
#endif
3746+
}
37163747
skb_set_hash(skb, READ_ONCE(tcp_rsk(req)->txhash), PKT_HASH_TYPE_L4);
37173748
/* bpf program will be interested in the tcp_flags */
37183749
TCP_SKB_CB(skb)->tcp_flags = TCPHDR_SYN | TCPHDR_ACK;
3719-
tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,
3720-
foc, synack_type,
3721-
syn_skb) + sizeof(*th);
3750+
tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts,
3751+
&key, foc, synack_type, syn_skb)
3752+
+ sizeof(*th);
37223753

37233754
skb_push(skb, tcp_header_size);
37243755
skb_reset_transport_header(skb);
@@ -3738,15 +3769,24 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
37383769

37393770
/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
37403771
th->window = htons(min(req->rsk_rcv_wnd, 65535U));
3741-
tcp_options_write(th, NULL, NULL, &opts, &key);
3772+
tcp_options_write(th, NULL, tcp_rsk(req), &opts, &key);
37423773
th->doff = (tcp_header_size >> 2);
37433774
TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
37443775

3745-
#ifdef CONFIG_TCP_MD5SIG
37463776
/* Okay, we have all we need - do the md5 hash if needed */
3747-
if (md5)
3777+
if (tcp_key_is_md5(&key)) {
3778+
#ifdef CONFIG_TCP_MD5SIG
37483779
tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
3749-
md5, req_to_sk(req), skb);
3780+
key.md5_key, req_to_sk(req), skb);
3781+
#endif
3782+
} else if (tcp_key_is_ao(&key)) {
3783+
#ifdef CONFIG_TCP_AO
3784+
tcp_rsk(req)->af_specific->ao_synack_hash(opts.hash_location,
3785+
key.ao_key, req, skb,
3786+
opts.hash_location - (u8 *)th, 0);
3787+
#endif
3788+
}
3789+
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
37503790
rcu_read_unlock();
37513791
#endif
37523792

net/ipv6/tcp_ao.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,25 @@ int tcp_v6_parse_ao(struct sock *sk, int cmd,
144144
{
145145
return tcp_parse_ao(sk, cmd, AF_INET6, optval, optlen);
146146
}
147+
148+
int tcp_v6_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key,
149+
struct request_sock *req, const struct sk_buff *skb,
150+
int hash_offset, u32 sne)
151+
{
152+
void *hash_buf = NULL;
153+
int err;
154+
155+
hash_buf = kmalloc(tcp_ao_digest_size(ao_key), GFP_ATOMIC);
156+
if (!hash_buf)
157+
return -ENOMEM;
158+
159+
err = tcp_v6_ao_calc_key_rsk(ao_key, hash_buf, req);
160+
if (err)
161+
goto out;
162+
163+
err = tcp_ao_hash_skb(AF_INET6, ao_hash, ao_key, req_to_sk(req), skb,
164+
hash_buf, hash_offset, sne);
165+
out:
166+
kfree(hash_buf);
167+
return err;
168+
}

net/ipv6/tcp_ipv6.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
839839
#ifdef CONFIG_TCP_AO
840840
.ao_lookup = tcp_v6_ao_lookup_rsk,
841841
.ao_calc_key = tcp_v6_ao_calc_key_rsk,
842+
.ao_synack_hash = tcp_v6_ao_synack_hash,
842843
#endif
843844
#ifdef CONFIG_SYN_COOKIES
844845
.cookie_init_seq = cookie_v6_init_sequence,

0 commit comments

Comments
 (0)