Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net/tcp: Add TCP-AO SNE support

Add Sequence Number Extension (SNE) for TCP-AO.
This is needed to protect long-living TCP-AO connections from replaying
attacks after sequence number roll-over, see RFC5925 (6.2).

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>

authored by

Dmitry Safonov and committed by
David S. Miller
64382c71 af09a341

+104 -13
+21 -1
include/net/tcp_ao.h
··· 95 95 __unused :31; 96 96 __be32 lisn; 97 97 __be32 risn; 98 + /* Sequence Number Extension (SNE) are upper 4 bytes for SEQ, 99 + * that protect TCP-AO connection from replayed old TCP segments. 100 + * See RFC5925 (6.2). 101 + * In order to get correct SNE, there's a helper tcp_ao_compute_sne(). 102 + * It needs SEQ basis to understand whereabouts are lower SEQ numbers. 103 + * According to that basis vector, it can provide incremented SNE 104 + * when SEQ rolls over or provide decremented SNE when there's 105 + * a retransmitted segment from before-rolling over. 106 + * - for request sockets such basis is rcv_isn/snt_isn, which seems 107 + * good enough as it's unexpected to receive 4 Gbytes on reqsk. 108 + * - for full sockets the basis is rcv_nxt/snd_una. snd_una is 109 + * taken instead of snd_nxt as currently it's easier to track 110 + * in tcp_snd_una_update(), rather than updating SNE in all 111 + * WRITE_ONCE(tp->snd_nxt, ...) 112 + * - for time-wait sockets the basis is tw_rcv_nxt/tw_snd_nxt. 113 + * tw_snd_nxt is not expected to change, while tw_rcv_nxt may. 114 + */ 115 + u32 snd_sne; 116 + u32 rcv_sne; 98 117 refcount_t refcnt; /* Protects twsk destruction */ 99 118 struct rcu_head rcu; 100 119 }; ··· 166 147 const struct sk_buff *skb, unsigned short int family, 167 148 const struct request_sock *req, 168 149 const struct tcp_ao_hdr *aoh); 150 + u32 tcp_ao_compute_sne(u32 next_sne, u32 next_seq, u32 seq); 169 151 struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, 170 152 const union tcp_ao_addr *addr, 171 153 int family, int sndid, int rcvid); ··· 176 156 const union tcp_ao_addr *saddr, 177 157 const struct tcphdr *th, u32 sne); 178 158 int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb, 179 - const struct tcp_ao_hdr *aoh, int l3index, 159 + const struct tcp_ao_hdr *aoh, int l3index, u32 seq, 180 160 struct tcp_ao_key **key, char **traffic_key, 181 161 bool *allocated_traffic_key, u8 *keyid, u32 *sne); 182 162
+37 -9
net/ipv4/tcp_ao.c
··· 401 401 return -EAFNOSUPPORT; 402 402 } 403 403 404 + u32 tcp_ao_compute_sne(u32 next_sne, u32 next_seq, u32 seq) 405 + { 406 + u32 sne = next_sne; 407 + 408 + if (before(seq, next_seq)) { 409 + if (seq > next_seq) 410 + sne--; 411 + } else { 412 + if (seq < next_seq) 413 + sne++; 414 + } 415 + 416 + return sne; 417 + } 418 + 404 419 /* tcp_ao_hash_sne(struct tcp_sigpool *hp) 405 420 * @hp - used for hashing 406 421 * @sne - sne value ··· 626 611 } 627 612 628 613 int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb, 629 - const struct tcp_ao_hdr *aoh, int l3index, 614 + const struct tcp_ao_hdr *aoh, int l3index, u32 seq, 630 615 struct tcp_ao_key **key, char **traffic_key, 631 616 bool *allocated_traffic_key, u8 *keyid, u32 *sne) 632 617 { ··· 654 639 655 640 sisn = htonl(tcp_rsk(req)->rcv_isn); 656 641 disn = htonl(tcp_rsk(req)->snt_isn); 657 - *sne = 0; 642 + *sne = tcp_ao_compute_sne(0, tcp_rsk(req)->snt_isn, seq); 658 643 } else { 659 644 sisn = th->seq; 660 645 disn = 0; ··· 685 670 *keyid = (*key)->rcvid; 686 671 } else { 687 672 struct tcp_ao_key *rnext_key; 673 + u32 snd_basis; 688 674 689 - if (sk->sk_state == TCP_TIME_WAIT) 675 + if (sk->sk_state == TCP_TIME_WAIT) { 690 676 ao_info = rcu_dereference(tcp_twsk(sk)->ao_info); 691 - else 677 + snd_basis = tcp_twsk(sk)->tw_snd_nxt; 678 + } else { 692 679 ao_info = rcu_dereference(tcp_sk(sk)->ao_info); 680 + snd_basis = tcp_sk(sk)->snd_una; 681 + } 693 682 if (!ao_info) 694 683 return -ENOENT; 695 684 ··· 703 684 *traffic_key = snd_other_key(*key); 704 685 rnext_key = READ_ONCE(ao_info->rnext_key); 705 686 *keyid = rnext_key->rcvid; 706 - *sne = 0; 687 + *sne = tcp_ao_compute_sne(READ_ONCE(ao_info->snd_sne), 688 + snd_basis, seq); 707 689 } 708 690 return 0; 709 691 } ··· 718 698 struct tcp_ao_info *ao; 719 699 void *tkey_buf = NULL; 720 700 u8 *traffic_key; 701 + u32 sne; 721 702 722 703 ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 723 704 lockdep_sock_is_held(sk)); ··· 738 717 tp->af_specific->ao_calc_key_sk(key, traffic_key, 739 718 sk, ao->lisn, disn, true); 740 719 } 720 + sne = tcp_ao_compute_sne(READ_ONCE(ao->snd_sne), READ_ONCE(tp->snd_una), 721 + ntohl(th->seq)); 741 722 tp->af_specific->calc_ao_hash(hash_location, key, sk, skb, traffic_key, 742 - hash_location - (u8 *)th, 0); 723 + hash_location - (u8 *)th, sne); 743 724 kfree(tkey_buf); 744 725 return 0; 745 726 } ··· 869 846 if (unlikely(th->syn && !th->ack)) 870 847 goto verify_hash; 871 848 872 - sne = 0; 849 + sne = tcp_ao_compute_sne(info->rcv_sne, tcp_sk(sk)->rcv_nxt, 850 + ntohl(th->seq)); 873 851 /* Established socket, traffic key are cached */ 874 852 traffic_key = rcv_other_key(key); 875 853 err = tcp_ao_verify_hash(sk, skb, family, info, aoh, key, ··· 905 881 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) { 906 882 /* Make the initial syn the likely case here */ 907 883 if (unlikely(req)) { 908 - sne = 0; 884 + sne = tcp_ao_compute_sne(0, tcp_rsk(req)->rcv_isn, 885 + ntohl(th->seq)); 909 886 sisn = htonl(tcp_rsk(req)->rcv_isn); 910 887 disn = htonl(tcp_rsk(req)->snt_isn); 911 888 } else if (unlikely(th->ack && !th->syn)) { 912 889 /* Possible syncookie packet */ 913 890 sisn = htonl(ntohl(th->seq) - 1); 914 891 disn = htonl(ntohl(th->ack_seq) - 1); 915 - sne = 0; 892 + sne = tcp_ao_compute_sne(0, ntohl(sisn), 893 + ntohl(th->seq)); 916 894 } else if (unlikely(!th->syn)) { 917 895 /* no way to figure out initial sisn/disn - drop */ 918 896 return SKB_DROP_REASON_TCP_FLAGS; ··· 1012 986 tp->tcp_header_len += tcp_ao_len(key); 1013 987 1014 988 ao_info->lisn = htonl(tp->write_seq); 989 + ao_info->snd_sne = 0; 1015 990 } else { 1016 991 /* Can't happen: tcp_connect() verifies that there's 1017 992 * at least one tcp-ao key that matches the remote peer. ··· 1048 1021 return; 1049 1022 1050 1023 WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); 1024 + ao->rcv_sne = 0; 1051 1025 1052 1026 hlist_for_each_entry_rcu(key, &ao->head, node) 1053 1027 tcp_ao_cache_traffic_keys(sk, ao, key);
+28
net/ipv4/tcp_input.c
··· 3576 3576 static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) 3577 3577 { 3578 3578 u32 delta = ack - tp->snd_una; 3579 + #ifdef CONFIG_TCP_AO 3580 + struct tcp_ao_info *ao; 3581 + #endif 3579 3582 3580 3583 sock_owned_by_me((struct sock *)tp); 3581 3584 tp->bytes_acked += delta; 3585 + #ifdef CONFIG_TCP_AO 3586 + ao = rcu_dereference_protected(tp->ao_info, 3587 + lockdep_sock_is_held((struct sock *)tp)); 3588 + if (ao && ack < tp->snd_una) 3589 + ao->snd_sne++; 3590 + #endif 3582 3591 tp->snd_una = ack; 3583 3592 } 3584 3593 ··· 3595 3586 static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) 3596 3587 { 3597 3588 u32 delta = seq - tp->rcv_nxt; 3589 + #ifdef CONFIG_TCP_AO 3590 + struct tcp_ao_info *ao; 3591 + #endif 3598 3592 3599 3593 sock_owned_by_me((struct sock *)tp); 3600 3594 tp->bytes_received += delta; 3595 + #ifdef CONFIG_TCP_AO 3596 + ao = rcu_dereference_protected(tp->ao_info, 3597 + lockdep_sock_is_held((struct sock *)tp)); 3598 + if (ao && seq < tp->rcv_nxt) 3599 + ao->rcv_sne++; 3600 + #endif 3601 3601 WRITE_ONCE(tp->rcv_nxt, seq); 3602 3602 } 3603 3603 ··· 6474 6456 * simultaneous connect with crossed SYNs. 6475 6457 * Particularly, it can be connect to self. 6476 6458 */ 6459 + #ifdef CONFIG_TCP_AO 6460 + struct tcp_ao_info *ao; 6461 + 6462 + ao = rcu_dereference_protected(tp->ao_info, 6463 + lockdep_sock_is_held(sk)); 6464 + if (ao) { 6465 + WRITE_ONCE(ao->risn, th->seq); 6466 + ao->rcv_sne = 0; 6467 + } 6468 + #endif 6477 6469 tcp_set_state(sk, TCP_SYN_RECV); 6478 6470 6479 6471 if (tp->rx_opt.saw_tstamp) {
+2 -1
net/ipv4/tcp_ipv4.c
··· 676 676 u8 keyid; 677 677 678 678 rcu_read_lock(); 679 - if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, 679 + if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, ntohl(reply->seq), 680 680 &key, &traffic_key, &allocated_traffic_key, 681 681 &keyid, &ao_sne)) 682 682 goto out; ··· 1034 1034 struct tcp_ao_key *rnext_key; 1035 1035 1036 1036 key.traffic_key = snd_other_key(key.ao_key); 1037 + key.sne = READ_ONCE(ao_info->snd_sne); 1037 1038 rnext_key = READ_ONCE(ao_info->rnext_key); 1038 1039 key.rcv_next = rnext_key->rcvid; 1039 1040 key.type = TCP_KEY_AO;
+14 -1
net/ipv4/tcp_minisocks.c
··· 51 51 return TCP_TW_SUCCESS; 52 52 } 53 53 54 + static void twsk_rcv_nxt_update(struct tcp_timewait_sock *tcptw, u32 seq) 55 + { 56 + #ifdef CONFIG_TCP_AO 57 + struct tcp_ao_info *ao; 58 + 59 + ao = rcu_dereference(tcptw->ao_info); 60 + if (unlikely(ao && seq < tcptw->tw_rcv_nxt)) 61 + WRITE_ONCE(ao->rcv_sne, ao->rcv_sne + 1); 62 + #endif 63 + tcptw->tw_rcv_nxt = seq; 64 + } 65 + 54 66 /* 55 67 * * Main purpose of TIME-WAIT state is to close connection gracefully, 56 68 * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN ··· 148 136 149 137 /* FIN arrived, enter true time-wait state. */ 150 138 tw->tw_substate = TCP_TIME_WAIT; 151 - tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq; 139 + twsk_rcv_nxt_update(tcptw, TCP_SKB_CB(skb)->end_seq); 140 + 152 141 if (tmp_opt.saw_tstamp) { 153 142 tcptw->tw_ts_recent_stamp = ktime_get_seconds(); 154 143 tcptw->tw_ts_recent = tmp_opt.rcv_tsval;
+2 -1
net/ipv6/tcp_ipv6.c
··· 1090 1090 int l3index; 1091 1091 1092 1092 l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 1093 - if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, 1093 + if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, seq, 1094 1094 &key.ao_key, &key.traffic_key, 1095 1095 &allocated_traffic_key, 1096 1096 &key.rcv_next, &key.sne)) ··· 1167 1167 /* rcv_next switches to our rcv_next */ 1168 1168 rnext_key = READ_ONCE(ao_info->rnext_key); 1169 1169 key.rcv_next = rnext_key->rcvid; 1170 + key.sne = READ_ONCE(ao_info->snd_sne); 1170 1171 key.type = TCP_KEY_AO; 1171 1172 #else 1172 1173 if (0) {