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 sign to twsk

Add support for sockets in time-wait state.
ao_info as well as all keys are inherited on transition to time-wait
socket. The lifetime of ao_info is now protected by ref counter, so
that tcp_ao_destroy_sock() will destruct it only when the last user is
gone.

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

+183 -50
+3
include/linux/tcp.h
··· 514 514 #ifdef CONFIG_TCP_MD5SIG 515 515 struct tcp_md5sig_key *tw_md5_key; 516 516 #endif 517 + #ifdef CONFIG_TCP_AO 518 + struct tcp_ao_info __rcu *ao_info; 519 + #endif 517 520 }; 518 521 519 522 static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
+9 -2
include/net/tcp_ao.h
··· 85 85 __unused :31; 86 86 __be32 lisn; 87 87 __be32 risn; 88 + refcount_t refcnt; /* Protects twsk destruction */ 88 89 struct rcu_head rcu; 89 90 }; 90 91 ··· 125 124 int sndid, int rcvid); 126 125 int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx, 127 126 unsigned int len, struct tcp_sigpool *hp); 128 - void tcp_ao_destroy_sock(struct sock *sk); 127 + void tcp_ao_destroy_sock(struct sock *sk, bool twsk); 128 + void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp); 129 129 struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, 130 130 const union tcp_ao_addr *addr, 131 131 int family, int sndid, int rcvid); ··· 184 182 return NULL; 185 183 } 186 184 187 - static inline void tcp_ao_destroy_sock(struct sock *sk) 185 + static inline void tcp_ao_destroy_sock(struct sock *sk, bool twsk) 188 186 { 189 187 } 190 188 ··· 193 191 } 194 192 195 193 static inline void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb) 194 + { 195 + } 196 + 197 + static inline void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, 198 + struct tcp_sock *tp) 196 199 { 197 200 } 198 201
+41 -8
net/ipv4/tcp_ao.c
··· 159 159 if (!ao) 160 160 return NULL; 161 161 INIT_HLIST_HEAD(&ao->head); 162 + refcount_set(&ao->refcnt, 1); 162 163 163 164 return ao; 164 165 } ··· 177 176 kfree_sensitive(key); 178 177 } 179 178 180 - void tcp_ao_destroy_sock(struct sock *sk) 179 + void tcp_ao_destroy_sock(struct sock *sk, bool twsk) 181 180 { 182 181 struct tcp_ao_info *ao; 183 182 struct tcp_ao_key *key; 184 183 struct hlist_node *n; 185 184 186 - ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1); 187 - tcp_sk(sk)->ao_info = NULL; 185 + if (twsk) { 186 + ao = rcu_dereference_protected(tcp_twsk(sk)->ao_info, 1); 187 + tcp_twsk(sk)->ao_info = NULL; 188 + } else { 189 + ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1); 190 + tcp_sk(sk)->ao_info = NULL; 191 + } 188 192 189 - if (!ao) 193 + if (!ao || !refcount_dec_and_test(&ao->refcnt)) 190 194 return; 191 195 192 196 hlist_for_each_entry_safe(key, n, &ao->head, node) { 193 197 hlist_del_rcu(&key->node); 194 - atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc); 198 + if (!twsk) 199 + atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc); 195 200 call_rcu(&key->rcu, tcp_ao_key_free_rcu); 196 201 } 197 202 198 203 kfree_rcu(ao, rcu); 204 + } 205 + 206 + void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp) 207 + { 208 + struct tcp_ao_info *ao_info = rcu_dereference_protected(tp->ao_info, 1); 209 + 210 + if (ao_info) { 211 + struct tcp_ao_key *key; 212 + struct hlist_node *n; 213 + int omem = 0; 214 + 215 + hlist_for_each_entry_safe(key, n, &ao_info->head, node) { 216 + omem += tcp_ao_sizeof_key(key); 217 + } 218 + 219 + refcount_inc(&ao_info->refcnt); 220 + atomic_sub(omem, &(((struct sock *)tp)->sk_omem_alloc)); 221 + rcu_assign_pointer(tcptw->ao_info, ao_info); 222 + } else { 223 + tcptw->ao_info = NULL; 224 + } 199 225 } 200 226 201 227 /* 4 tuple and ISNs are expected in NBO */ ··· 542 514 if (!sk) 543 515 return -ENOTCONN; 544 516 545 - if ((1 << sk->sk_state) & 546 - (TCPF_LISTEN | TCPF_NEW_SYN_RECV | TCPF_TIME_WAIT)) 517 + if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) { 547 518 return -1; 548 519 549 - ao_info = rcu_dereference(tcp_sk(sk)->ao_info); 520 + if (sk->sk_state == TCP_TIME_WAIT) 521 + ao_info = rcu_dereference(tcp_twsk(sk)->ao_info); 522 + else 523 + ao_info = rcu_dereference(tcp_sk(sk)->ao_info); 550 524 if (!ao_info) 551 525 return -ENOENT; 552 526 ··· 939 909 { 940 910 if (sk_fullsock(sk)) { 941 911 return rcu_dereference_protected(tcp_sk(sk)->ao_info, 912 + lockdep_sock_is_held(sk)); 913 + } else if (sk->sk_state == TCP_TIME_WAIT) { 914 + return rcu_dereference_protected(tcp_twsk(sk)->ao_info, 942 915 lockdep_sock_is_held(sk)); 943 916 } 944 917 return ERR_PTR(-ESOCKTNOSUPPORT);
+73 -19
net/ipv4/tcp_ipv4.c
··· 911 911 static void tcp_v4_send_ack(const struct sock *sk, 912 912 struct sk_buff *skb, u32 seq, u32 ack, 913 913 u32 win, u32 tsval, u32 tsecr, int oif, 914 - struct tcp_md5sig_key *key, 914 + struct tcp_key *key, 915 915 int reply_flags, u8 tos, u32 txhash) 916 916 { 917 917 const struct tcphdr *th = tcp_hdr(skb); 918 918 struct { 919 919 struct tcphdr th; 920 - __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) 921 - #ifdef CONFIG_TCP_MD5SIG 922 - + (TCPOLEN_MD5SIG_ALIGNED >> 2) 923 - #endif 924 - ]; 920 + __be32 opt[(MAX_TCP_OPTION_SPACE >> 2)]; 925 921 } rep; 926 922 struct net *net = sock_net(sk); 927 923 struct ip_reply_arg arg; ··· 948 952 rep.th.window = htons(win); 949 953 950 954 #ifdef CONFIG_TCP_MD5SIG 951 - if (key) { 955 + if (tcp_key_is_md5(key)) { 952 956 int offset = (tsecr) ? 3 : 0; 953 957 954 958 rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | ··· 959 963 rep.th.doff = arg.iov[0].iov_len/4; 960 964 961 965 tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset], 962 - key, ip_hdr(skb)->saddr, 966 + key->md5_key, ip_hdr(skb)->saddr, 963 967 ip_hdr(skb)->daddr, &rep.th); 968 + } 969 + #endif 970 + #ifdef CONFIG_TCP_AO 971 + if (tcp_key_is_ao(key)) { 972 + int offset = (tsecr) ? 3 : 0; 973 + 974 + rep.opt[offset++] = htonl((TCPOPT_AO << 24) | 975 + (tcp_ao_len(key->ao_key) << 16) | 976 + (key->ao_key->sndid << 8) | 977 + key->rcv_next); 978 + arg.iov[0].iov_len += round_up(tcp_ao_len(key->ao_key), 4); 979 + rep.th.doff = arg.iov[0].iov_len / 4; 980 + 981 + tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset], 982 + key->ao_key, key->traffic_key, 983 + (union tcp_ao_addr *)&ip_hdr(skb)->saddr, 984 + (union tcp_ao_addr *)&ip_hdr(skb)->daddr, 985 + &rep.th, key->sne); 964 986 } 965 987 #endif 966 988 arg.flags = reply_flags; ··· 1013 999 { 1014 1000 struct inet_timewait_sock *tw = inet_twsk(sk); 1015 1001 struct tcp_timewait_sock *tcptw = tcp_twsk(sk); 1002 + struct tcp_key key = {}; 1003 + #ifdef CONFIG_TCP_AO 1004 + struct tcp_ao_info *ao_info; 1005 + 1006 + /* FIXME: the segment to-be-acked is not verified yet */ 1007 + ao_info = rcu_dereference(tcptw->ao_info); 1008 + if (ao_info) { 1009 + const struct tcp_ao_hdr *aoh; 1010 + 1011 + if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh)) { 1012 + inet_twsk_put(tw); 1013 + return; 1014 + } 1015 + 1016 + if (aoh) 1017 + key.ao_key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1); 1018 + } 1019 + if (key.ao_key) { 1020 + struct tcp_ao_key *rnext_key; 1021 + 1022 + key.traffic_key = snd_other_key(key.ao_key); 1023 + rnext_key = READ_ONCE(ao_info->rnext_key); 1024 + key.rcv_next = rnext_key->rcvid; 1025 + key.type = TCP_KEY_AO; 1026 + #else 1027 + if (0) { 1028 + #endif 1029 + #ifdef CONFIG_TCP_MD5SIG 1030 + } else if (static_branch_unlikely(&tcp_md5_needed.key)) { 1031 + key.md5_key = tcp_twsk_md5_key(tcptw); 1032 + if (key.md5_key) 1033 + key.type = TCP_KEY_MD5; 1034 + #endif 1035 + } 1016 1036 1017 1037 tcp_v4_send_ack(sk, skb, 1018 1038 tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, 1019 1039 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, 1020 1040 tcp_tw_tsval(tcptw), 1021 1041 tcptw->tw_ts_recent, 1022 - tw->tw_bound_dev_if, 1023 - tcp_twsk_md5_key(tcptw), 1042 + tw->tw_bound_dev_if, &key, 1024 1043 tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, 1025 1044 tw->tw_tos, 1026 - tw->tw_txhash 1027 - ); 1045 + tw->tw_txhash); 1028 1046 1029 1047 inet_twsk_put(tw); 1030 1048 } ··· 1064 1018 static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, 1065 1019 struct request_sock *req) 1066 1020 { 1067 - const union tcp_md5_addr *addr; 1068 - int l3index; 1021 + struct tcp_key key = {}; 1069 1022 1070 1023 /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV 1071 1024 * sk->sk_state == TCP_SYN_RECV -> for Fast Open. ··· 1077 1032 * exception of <SYN> segments, MUST be right-shifted by 1078 1033 * Rcv.Wind.Shift bits: 1079 1034 */ 1080 - addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr; 1081 - l3index = tcp_v4_sdif(skb) ? inet_iif(skb) : 0; 1035 + #ifdef CONFIG_TCP_MD5SIG 1036 + if (static_branch_unlikely(&tcp_md5_needed.key)) { 1037 + const union tcp_md5_addr *addr; 1038 + int l3index; 1039 + 1040 + addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr; 1041 + l3index = tcp_v4_sdif(skb) ? inet_iif(skb) : 0; 1042 + key.md5_key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET); 1043 + if (key.md5_key) 1044 + key.type = TCP_KEY_MD5; 1045 + } 1046 + #endif 1082 1047 tcp_v4_send_ack(sk, skb, seq, 1083 1048 tcp_rsk(req)->rcv_nxt, 1084 1049 req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, 1085 1050 tcp_rsk_tsval(tcp_rsk(req)), 1086 1051 READ_ONCE(req->ts_recent), 1087 - 0, 1088 - tcp_md5_do_lookup(sk, l3index, addr, AF_INET), 1052 + 0, &key, 1089 1053 inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, 1090 1054 ip_hdr(skb)->tos, 1091 1055 READ_ONCE(tcp_rsk(req)->txhash)); ··· 2458 2404 rcu_assign_pointer(tp->md5sig_info, NULL); 2459 2405 } 2460 2406 #endif 2461 - tcp_ao_destroy_sock(sk); 2407 + tcp_ao_destroy_sock(sk, false); 2462 2408 2463 2409 /* Clean up a referenced TCP bind bucket. */ 2464 2410 if (inet_csk(sk)->icsk_bind_hash)
+3 -1
net/ipv4/tcp_minisocks.c
··· 279 279 void tcp_time_wait(struct sock *sk, int state, int timeo) 280 280 { 281 281 const struct inet_connection_sock *icsk = inet_csk(sk); 282 - const struct tcp_sock *tp = tcp_sk(sk); 282 + struct tcp_sock *tp = tcp_sk(sk); 283 283 struct net *net = sock_net(sk); 284 284 struct inet_timewait_sock *tw; 285 285 ··· 316 316 #endif 317 317 318 318 tcp_time_wait_init(sk, tcptw); 319 + tcp_ao_time_wait(tcptw, tp); 319 320 320 321 /* Get the TIME_WAIT timeout firing. */ 321 322 if (timeo < rto) ··· 371 370 call_rcu(&twsk->tw_md5_key->rcu, tcp_md5_twsk_free_rcu); 372 371 } 373 372 #endif 373 + tcp_ao_destroy_sock(sk, true); 374 374 } 375 375 EXPORT_SYMBOL_GPL(tcp_twsk_destructor); 376 376
+1 -1
net/ipv4/tcp_output.c
··· 3997 3997 * then free up ao_info if allocated. 3998 3998 */ 3999 3999 if (needs_md5) { 4000 - tcp_ao_destroy_sock(sk); 4000 + tcp_ao_destroy_sock(sk, false); 4001 4001 } else if (needs_ao) { 4002 4002 tcp_clear_md5_list(sk); 4003 4003 kfree(rcu_replace_pointer(tp->md5sig_info, NULL,
+53 -19
net/ipv6/tcp_ipv6.c
··· 778 778 memset(md5_hash, 0, 16); 779 779 return 1; 780 780 } 781 - #else /* CONFIG_TCP_MD5SIG */ 782 - static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, 783 - const struct in6_addr *addr, 784 - int l3index) 785 - { 786 - return NULL; 787 - } 788 781 #endif 789 782 790 783 static void tcp_v6_init_req(struct request_sock *req, ··· 1127 1134 1128 1135 static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, 1129 1136 u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, 1130 - struct tcp_md5sig_key *md5_key, u8 tclass, 1137 + struct tcp_key *key, u8 tclass, 1131 1138 __be32 label, u32 priority, u32 txhash) 1132 1139 { 1133 - struct tcp_key key = { 1134 - .md5_key = md5_key, 1135 - .type = md5_key ? TCP_KEY_MD5 : TCP_KEY_NONE, 1136 - }; 1137 - 1138 1140 tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, 0, 1139 - tclass, label, priority, txhash, &key); 1141 + tclass, label, priority, txhash, key); 1140 1142 } 1141 1143 1142 1144 static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) 1143 1145 { 1144 1146 struct inet_timewait_sock *tw = inet_twsk(sk); 1145 1147 struct tcp_timewait_sock *tcptw = tcp_twsk(sk); 1148 + struct tcp_key key = {}; 1149 + #ifdef CONFIG_TCP_AO 1150 + struct tcp_ao_info *ao_info; 1151 + 1152 + /* FIXME: the segment to-be-acked is not verified yet */ 1153 + ao_info = rcu_dereference(tcptw->ao_info); 1154 + if (ao_info) { 1155 + const struct tcp_ao_hdr *aoh; 1156 + 1157 + /* Invalid TCP option size or twice included auth */ 1158 + if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh)) 1159 + goto out; 1160 + if (aoh) { 1161 + key.ao_key = tcp_ao_established_key(ao_info, 1162 + aoh->rnext_keyid, -1); 1163 + } 1164 + } 1165 + if (key.ao_key) { 1166 + struct tcp_ao_key *rnext_key; 1167 + 1168 + key.traffic_key = snd_other_key(key.ao_key); 1169 + /* rcv_next switches to our rcv_next */ 1170 + rnext_key = READ_ONCE(ao_info->rnext_key); 1171 + key.rcv_next = rnext_key->rcvid; 1172 + key.type = TCP_KEY_AO; 1173 + #else 1174 + if (0) { 1175 + #endif 1176 + #ifdef CONFIG_TCP_MD5SIG 1177 + } else if (static_branch_unlikely(&tcp_md5_needed.key)) { 1178 + key.md5_key = tcp_twsk_md5_key(tcptw); 1179 + if (key.md5_key) 1180 + key.type = TCP_KEY_MD5; 1181 + #endif 1182 + } 1146 1183 1147 1184 tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, 1148 1185 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, 1149 1186 tcp_tw_tsval(tcptw), 1150 - tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), 1187 + tcptw->tw_ts_recent, tw->tw_bound_dev_if, &key, 1151 1188 tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority, 1152 1189 tw->tw_txhash); 1153 1190 1191 + #ifdef CONFIG_TCP_AO 1192 + out: 1193 + #endif 1154 1194 inet_twsk_put(tw); 1155 1195 } 1156 1196 1157 1197 static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, 1158 1198 struct request_sock *req) 1159 1199 { 1160 - int l3index; 1200 + struct tcp_key key = {}; 1161 1201 1162 - l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 1202 + #ifdef CONFIG_TCP_MD5SIG 1203 + if (static_branch_unlikely(&tcp_md5_needed.key)) { 1204 + int l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 1205 + 1206 + key.md5_key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, 1207 + l3index); 1208 + if (key.md5_key) 1209 + key.type = TCP_KEY_MD5; 1210 + } 1211 + #endif 1163 1212 1164 1213 /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV 1165 1214 * sk->sk_state == TCP_SYN_RECV -> for Fast Open. ··· 1217 1182 req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, 1218 1183 tcp_rsk_tsval(tcp_rsk(req)), 1219 1184 READ_ONCE(req->ts_recent), sk->sk_bound_dev_if, 1220 - tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, l3index), 1221 - ipv6_get_dsfield(ipv6_hdr(skb)), 0, 1185 + &key, ipv6_get_dsfield(ipv6_hdr(skb)), 0, 1222 1186 READ_ONCE(sk->sk_priority), 1223 1187 READ_ONCE(tcp_rsk(req)->txhash)); 1224 1188 }