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 AO sign to RST packets

Wire up sending resets to TCP-AO hashing.

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
ba7783ad f7dca36f

+245 -43
+6 -1
include/net/tcp.h
··· 2258 2258 2259 2259 struct tcp_key { 2260 2260 union { 2261 - struct tcp_ao_key *ao_key; 2261 + struct { 2262 + struct tcp_ao_key *ao_key; 2263 + char *traffic_key; 2264 + u32 sne; 2265 + u8 rcv_next; 2266 + }; 2262 2267 struct tcp_md5sig_key *md5_key; 2263 2268 }; 2264 2269 enum {
+12
include/net/tcp_ao.h
··· 120 120 const u8 *tkey, int hash_offset, u32 sne); 121 121 int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family, 122 122 sockptr_t optval, int optlen); 123 + struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao, 124 + int sndid, int rcvid); 123 125 int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx, 124 126 unsigned int len, struct tcp_sigpool *hp); 125 127 void tcp_ao_destroy_sock(struct sock *sk); 126 128 struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, 127 129 const union tcp_ao_addr *addr, 128 130 int family, int sndid, int rcvid); 131 + int tcp_ao_hash_hdr(unsigned short family, char *ao_hash, 132 + struct tcp_ao_key *key, const u8 *tkey, 133 + const union tcp_ao_addr *daddr, 134 + const union tcp_ao_addr *saddr, 135 + const struct tcphdr *th, u32 sne); 136 + int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb, 137 + const struct tcp_ao_hdr *aoh, int l3index, 138 + struct tcp_ao_key **key, char **traffic_key, 139 + bool *allocated_traffic_key, u8 *keyid, u32 *sne); 140 + 129 141 /* ipv4 specific functions */ 130 142 int tcp_v4_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen); 131 143 struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk,
+100 -2
net/ipv4/tcp_ao.c
··· 48 48 * it's known that the keys in ao_info are matching peer's 49 49 * family/address/VRF/etc. 50 50 */ 51 - static struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao, 52 - int sndid, int rcvid) 51 + struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao, 52 + int sndid, int rcvid) 53 53 { 54 54 struct tcp_ao_key *key; 55 55 ··· 369 369 return err; 370 370 } 371 371 372 + int tcp_ao_hash_hdr(unsigned short int family, char *ao_hash, 373 + struct tcp_ao_key *key, const u8 *tkey, 374 + const union tcp_ao_addr *daddr, 375 + const union tcp_ao_addr *saddr, 376 + const struct tcphdr *th, u32 sne) 377 + { 378 + int tkey_len = tcp_ao_digest_size(key); 379 + int hash_offset = ao_hash - (char *)th; 380 + struct tcp_sigpool hp; 381 + void *hash_buf = NULL; 382 + 383 + hash_buf = kmalloc(tkey_len, GFP_ATOMIC); 384 + if (!hash_buf) 385 + goto clear_hash_noput; 386 + 387 + if (tcp_sigpool_start(key->tcp_sigpool_id, &hp)) 388 + goto clear_hash_noput; 389 + 390 + if (crypto_ahash_setkey(crypto_ahash_reqtfm(hp.req), tkey, tkey_len)) 391 + goto clear_hash; 392 + 393 + if (crypto_ahash_init(hp.req)) 394 + goto clear_hash; 395 + 396 + if (tcp_ao_hash_sne(&hp, sne)) 397 + goto clear_hash; 398 + if (family == AF_INET) { 399 + if (tcp_v4_ao_hash_pseudoheader(&hp, daddr->a4.s_addr, 400 + saddr->a4.s_addr, th->doff * 4)) 401 + goto clear_hash; 402 + #if IS_ENABLED(CONFIG_IPV6) 403 + } else if (family == AF_INET6) { 404 + if (tcp_v6_ao_hash_pseudoheader(&hp, &daddr->a6, 405 + &saddr->a6, th->doff * 4)) 406 + goto clear_hash; 407 + #endif 408 + } else { 409 + WARN_ON_ONCE(1); 410 + goto clear_hash; 411 + } 412 + if (tcp_ao_hash_header(&hp, th, false, 413 + ao_hash, hash_offset, tcp_ao_maclen(key))) 414 + goto clear_hash; 415 + ahash_request_set_crypt(hp.req, NULL, hash_buf, 0); 416 + if (crypto_ahash_final(hp.req)) 417 + goto clear_hash; 418 + 419 + memcpy(ao_hash, hash_buf, tcp_ao_maclen(key)); 420 + tcp_sigpool_end(&hp); 421 + kfree(hash_buf); 422 + return 0; 423 + 424 + clear_hash: 425 + tcp_sigpool_end(&hp); 426 + clear_hash_noput: 427 + memset(ao_hash, 0, tcp_ao_maclen(key)); 428 + kfree(hash_buf); 429 + return 1; 430 + } 431 + 372 432 int tcp_ao_hash_skb(unsigned short int family, 373 433 char *ao_hash, struct tcp_ao_key *key, 374 434 const struct sock *sk, const struct sk_buff *skb, ··· 493 433 union tcp_ao_addr *addr = (union tcp_ao_addr *)&addr_sk->sk_daddr; 494 434 495 435 return tcp_ao_do_lookup(sk, addr, AF_INET, sndid, rcvid); 436 + } 437 + 438 + int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb, 439 + const struct tcp_ao_hdr *aoh, int l3index, 440 + struct tcp_ao_key **key, char **traffic_key, 441 + bool *allocated_traffic_key, u8 *keyid, u32 *sne) 442 + { 443 + struct tcp_ao_key *rnext_key; 444 + struct tcp_ao_info *ao_info; 445 + 446 + *allocated_traffic_key = false; 447 + /* If there's no socket - than initial sisn/disn are unknown. 448 + * Drop the segment. RFC5925 (7.7) advises to require graceful 449 + * restart [RFC4724]. Alternatively, the RFC5925 advises to 450 + * save/restore traffic keys before/after reboot. 451 + * Linux TCP-AO support provides TCP_AO_ADD_KEY and TCP_AO_REPAIR 452 + * options to restore a socket post-reboot. 453 + */ 454 + if (!sk) 455 + return -ENOTCONN; 456 + 457 + if ((1 << sk->sk_state) & 458 + (TCPF_LISTEN | TCPF_NEW_SYN_RECV | TCPF_TIME_WAIT)) 459 + return -1; 460 + 461 + ao_info = rcu_dereference(tcp_sk(sk)->ao_info); 462 + if (!ao_info) 463 + return -ENOENT; 464 + 465 + *key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1); 466 + if (!*key) 467 + return -ENOENT; 468 + *traffic_key = snd_other_key(*key); 469 + rnext_key = READ_ONCE(ao_info->rnext_key); 470 + *keyid = rnext_key->rcvid; 471 + *sne = 0; 472 + 473 + return 0; 496 474 } 497 475 498 476 int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb,
+56 -13
net/ipv4/tcp_ipv4.c
··· 657 657 } 658 658 EXPORT_SYMBOL(tcp_v4_send_check); 659 659 660 + #define REPLY_OPTIONS_LEN (MAX_TCP_OPTION_SPACE / sizeof(__be32)) 661 + 662 + static bool tcp_v4_ao_sign_reset(const struct sock *sk, struct sk_buff *skb, 663 + const struct tcp_ao_hdr *aoh, 664 + struct ip_reply_arg *arg, struct tcphdr *reply, 665 + __be32 reply_options[REPLY_OPTIONS_LEN]) 666 + { 667 + #ifdef CONFIG_TCP_AO 668 + int sdif = tcp_v4_sdif(skb); 669 + int dif = inet_iif(skb); 670 + int l3index = sdif ? dif : 0; 671 + bool allocated_traffic_key; 672 + struct tcp_ao_key *key; 673 + char *traffic_key; 674 + bool drop = true; 675 + u32 ao_sne = 0; 676 + u8 keyid; 677 + 678 + rcu_read_lock(); 679 + if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, 680 + &key, &traffic_key, &allocated_traffic_key, 681 + &keyid, &ao_sne)) 682 + goto out; 683 + 684 + reply_options[0] = htonl((TCPOPT_AO << 24) | (tcp_ao_len(key) << 16) | 685 + (aoh->rnext_keyid << 8) | keyid); 686 + arg->iov[0].iov_len += round_up(tcp_ao_len(key), 4); 687 + reply->doff = arg->iov[0].iov_len / 4; 688 + 689 + if (tcp_ao_hash_hdr(AF_INET, (char *)&reply_options[1], 690 + key, traffic_key, 691 + (union tcp_ao_addr *)&ip_hdr(skb)->saddr, 692 + (union tcp_ao_addr *)&ip_hdr(skb)->daddr, 693 + reply, ao_sne)) 694 + goto out; 695 + drop = false; 696 + out: 697 + rcu_read_unlock(); 698 + if (allocated_traffic_key) 699 + kfree(traffic_key); 700 + return drop; 701 + #else 702 + return true; 703 + #endif 704 + } 705 + 660 706 /* 661 707 * This routine will send an RST to the other tcp. 662 708 * ··· 716 670 * Exception: precedence violation. We do not implement it in any case. 717 671 */ 718 672 719 - #ifdef CONFIG_TCP_AO 720 - #define OPTION_BYTES MAX_TCP_OPTION_SPACE 721 - #elif defined(CONFIG_TCP_MD5SIG) 722 - #define OPTION_BYTES TCPOLEN_MD5SIG_ALIGNED 723 - #else 724 - #define OPTION_BYTES sizeof(__be32) 725 - #endif 726 - 727 673 static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) 728 674 { 729 675 const struct tcphdr *th = tcp_hdr(skb); 730 676 struct { 731 677 struct tcphdr th; 732 - __be32 opt[OPTION_BYTES / sizeof(__be32)]; 678 + __be32 opt[REPLY_OPTIONS_LEN]; 733 679 } rep; 680 + const __u8 *md5_hash_location = NULL; 681 + const struct tcp_ao_hdr *aoh; 734 682 struct ip_reply_arg arg; 735 683 #ifdef CONFIG_TCP_MD5SIG 736 - const __u8 *md5_hash_location = NULL; 737 684 struct tcp_md5sig_key *key = NULL; 738 685 unsigned char newhash[16]; 739 - int genhash; 740 686 struct sock *sk1 = NULL; 687 + int genhash; 741 688 #endif 742 689 u64 transmit_time = 0; 743 690 struct sock *ctl_sk; ··· 767 728 arg.iov[0].iov_len = sizeof(rep.th); 768 729 769 730 net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); 770 - #ifdef CONFIG_TCP_MD5SIG 731 + 771 732 /* Invalid TCP option size or twice included auth */ 772 - if (tcp_parse_auth_options(tcp_hdr(skb), &md5_hash_location, NULL)) 733 + if (tcp_parse_auth_options(tcp_hdr(skb), &md5_hash_location, &aoh)) 773 734 return; 774 735 736 + if (aoh && tcp_v4_ao_sign_reset(sk, skb, aoh, &arg, &rep.th, rep.opt)) 737 + return; 738 + 739 + #ifdef CONFIG_TCP_MD5SIG 775 740 rcu_read_lock(); 776 741 if (sk && sk_fullsock(sk)) { 777 742 const union tcp_md5_addr *addr;
+71 -27
net/ipv6/tcp_ipv6.c
··· 854 854 855 855 static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, 856 856 u32 ack, u32 win, u32 tsval, u32 tsecr, 857 - int oif, struct tcp_md5sig_key *key, int rst, 858 - u8 tclass, __be32 label, u32 priority, u32 txhash) 857 + int oif, int rst, u8 tclass, __be32 label, 858 + u32 priority, u32 txhash, struct tcp_key *key) 859 859 { 860 860 const struct tcphdr *th = tcp_hdr(skb); 861 861 struct tcphdr *t1; ··· 870 870 871 871 if (tsecr) 872 872 tot_len += TCPOLEN_TSTAMP_ALIGNED; 873 - #ifdef CONFIG_TCP_MD5SIG 874 - if (key) 873 + if (tcp_key_is_md5(key)) 875 874 tot_len += TCPOLEN_MD5SIG_ALIGNED; 876 - #endif 875 + if (tcp_key_is_ao(key)) 876 + tot_len += tcp_ao_len(key->ao_key); 877 877 878 878 #ifdef CONFIG_MPTCP 879 - if (rst && !key) { 879 + if (rst && !tcp_key_is_md5(key)) { 880 880 mrst = mptcp_reset_option(skb); 881 881 882 882 if (mrst) ··· 917 917 *topt++ = mrst; 918 918 919 919 #ifdef CONFIG_TCP_MD5SIG 920 - if (key) { 920 + if (tcp_key_is_md5(key)) { 921 921 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 922 922 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); 923 - tcp_v6_md5_hash_hdr((__u8 *)topt, key, 923 + tcp_v6_md5_hash_hdr((__u8 *)topt, key->md5_key, 924 924 &ipv6_hdr(skb)->saddr, 925 925 &ipv6_hdr(skb)->daddr, t1); 926 + } 927 + #endif 928 + #ifdef CONFIG_TCP_AO 929 + if (tcp_key_is_ao(key)) { 930 + *topt++ = htonl((TCPOPT_AO << 24) | 931 + (tcp_ao_len(key->ao_key) << 16) | 932 + (key->ao_key->sndid << 8) | 933 + (key->rcv_next)); 934 + 935 + tcp_ao_hash_hdr(AF_INET6, (char *)topt, key->ao_key, 936 + key->traffic_key, 937 + (union tcp_ao_addr *)&ipv6_hdr(skb)->saddr, 938 + (union tcp_ao_addr *)&ipv6_hdr(skb)->daddr, 939 + t1, key->sne); 926 940 } 927 941 #endif 928 942 ··· 1001 987 { 1002 988 const struct tcphdr *th = tcp_hdr(skb); 1003 989 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 1004 - u32 seq = 0, ack_seq = 0; 1005 - struct tcp_md5sig_key *key = NULL; 1006 - #ifdef CONFIG_TCP_MD5SIG 1007 990 const __u8 *md5_hash_location = NULL; 1008 - unsigned char newhash[16]; 1009 - int genhash; 1010 - struct sock *sk1 = NULL; 991 + #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO) 992 + bool allocated_traffic_key = false; 1011 993 #endif 994 + const struct tcp_ao_hdr *aoh; 995 + struct tcp_key key = {}; 996 + u32 seq = 0, ack_seq = 0; 1012 997 __be32 label = 0; 1013 998 u32 priority = 0; 1014 999 struct net *net; 1015 1000 u32 txhash = 0; 1016 1001 int oif = 0; 1002 + #ifdef CONFIG_TCP_MD5SIG 1003 + unsigned char newhash[16]; 1004 + int genhash; 1005 + struct sock *sk1 = NULL; 1006 + #endif 1017 1007 1018 1008 if (th->rst) 1019 1009 return; ··· 1029 1011 return; 1030 1012 1031 1013 net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); 1032 - #ifdef CONFIG_TCP_MD5SIG 1033 1014 /* Invalid TCP option size or twice included auth */ 1034 - if (tcp_parse_auth_options(th, &md5_hash_location, NULL)) 1015 + if (tcp_parse_auth_options(th, &md5_hash_location, &aoh)) 1035 1016 return; 1036 - 1017 + #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO) 1037 1018 rcu_read_lock(); 1019 + #endif 1020 + #ifdef CONFIG_TCP_MD5SIG 1038 1021 if (sk && sk_fullsock(sk)) { 1039 1022 int l3index; 1040 1023 ··· 1043 1024 * in an L3 domain and inet_iif is set to it. 1044 1025 */ 1045 1026 l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 1046 - key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr, l3index); 1027 + key.md5_key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr, l3index); 1028 + if (key.md5_key) 1029 + key.type = TCP_KEY_MD5; 1047 1030 } else if (md5_hash_location) { 1048 1031 int dif = tcp_v6_iif_l3_slave(skb); 1049 1032 int sdif = tcp_v6_sdif(skb); ··· 1070 1049 */ 1071 1050 l3index = tcp_v6_sdif(skb) ? dif : 0; 1072 1051 1073 - key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr, l3index); 1074 - if (!key) 1052 + key.md5_key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr, l3index); 1053 + if (!key.md5_key) 1075 1054 goto out; 1055 + key.type = TCP_KEY_MD5; 1076 1056 1077 - genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb); 1057 + genhash = tcp_v6_md5_hash_skb(newhash, key.md5_key, NULL, skb); 1078 1058 if (genhash || memcmp(md5_hash_location, newhash, 16) != 0) 1079 1059 goto out; 1080 1060 } ··· 1086 1064 else 1087 1065 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - 1088 1066 (th->doff << 2); 1067 + 1068 + #ifdef CONFIG_TCP_AO 1069 + if (aoh) { 1070 + int l3index; 1071 + 1072 + l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 1073 + if (tcp_ao_prepare_reset(sk, skb, aoh, l3index, 1074 + &key.ao_key, &key.traffic_key, 1075 + &allocated_traffic_key, 1076 + &key.rcv_next, &key.sne)) 1077 + goto out; 1078 + key.type = TCP_KEY_AO; 1079 + } 1080 + #endif 1089 1081 1090 1082 if (sk) { 1091 1083 oif = sk->sk_bound_dev_if; ··· 1120 1084 label = ip6_flowlabel(ipv6h); 1121 1085 } 1122 1086 1123 - tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 1124 - ipv6_get_dsfield(ipv6h), label, priority, txhash); 1087 + tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, 1, 1088 + ipv6_get_dsfield(ipv6h), label, priority, txhash, 1089 + &key); 1125 1090 1126 - #ifdef CONFIG_TCP_MD5SIG 1091 + #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO) 1127 1092 out: 1093 + if (allocated_traffic_key) 1094 + kfree(key.traffic_key); 1128 1095 rcu_read_unlock(); 1129 1096 #endif 1130 1097 } 1131 1098 1132 1099 static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, 1133 1100 u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, 1134 - struct tcp_md5sig_key *key, u8 tclass, 1101 + struct tcp_md5sig_key *md5_key, u8 tclass, 1135 1102 __be32 label, u32 priority, u32 txhash) 1136 1103 { 1137 - tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, 1138 - tclass, label, priority, txhash); 1104 + struct tcp_key key = { 1105 + .md5_key = md5_key, 1106 + .type = md5_key ? TCP_KEY_MD5 : TCP_KEY_NONE, 1107 + }; 1108 + 1109 + tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, 0, 1110 + tclass, label, priority, txhash, &key); 1139 1111 } 1140 1112 1141 1113 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)