Skip to content

Commit decde25

Browse files
0x7f454c46davem330
authored andcommitted
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 <[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 ba7783a commit decde25

File tree

7 files changed

+183
-50
lines changed

7 files changed

+183
-50
lines changed

include/linux/tcp.h

+3
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ struct tcp_timewait_sock {
514514
#ifdef CONFIG_TCP_MD5SIG
515515
struct tcp_md5sig_key *tw_md5_key;
516516
#endif
517+
#ifdef CONFIG_TCP_AO
518+
struct tcp_ao_info __rcu *ao_info;
519+
#endif
517520
};
518521

519522
static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)

include/net/tcp_ao.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct tcp_ao_info {
8585
__unused :31;
8686
__be32 lisn;
8787
__be32 risn;
88+
refcount_t refcnt; /* Protects twsk destruction */
8889
struct rcu_head rcu;
8990
};
9091

@@ -124,7 +125,8 @@ struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao,
124125
int sndid, int rcvid);
125126
int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx,
126127
unsigned int len, struct tcp_sigpool *hp);
127-
void tcp_ao_destroy_sock(struct sock *sk);
128+
void tcp_ao_destroy_sock(struct sock *sk, bool twsk);
129+
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp);
128130
struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk,
129131
const union tcp_ao_addr *addr,
130132
int family, int sndid, int rcvid);
@@ -182,7 +184,7 @@ static inline struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk,
182184
return NULL;
183185
}
184186

185-
static inline void tcp_ao_destroy_sock(struct sock *sk)
187+
static inline void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
186188
{
187189
}
188190

@@ -194,6 +196,11 @@ static inline void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb)
194196
{
195197
}
196198

199+
static inline void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw,
200+
struct tcp_sock *tp)
201+
{
202+
}
203+
197204
static inline void tcp_ao_connect_init(struct sock *sk)
198205
{
199206
}

net/ipv4/tcp_ao.c

+41-8
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ static struct tcp_ao_info *tcp_ao_alloc_info(gfp_t flags)
159159
if (!ao)
160160
return NULL;
161161
INIT_HLIST_HEAD(&ao->head);
162+
refcount_set(&ao->refcnt, 1);
162163

163164
return ao;
164165
}
@@ -176,27 +177,54 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head)
176177
kfree_sensitive(key);
177178
}
178179

179-
void tcp_ao_destroy_sock(struct sock *sk)
180+
void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
180181
{
181182
struct tcp_ao_info *ao;
182183
struct tcp_ao_key *key;
183184
struct hlist_node *n;
184185

185-
ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1);
186-
tcp_sk(sk)->ao_info = NULL;
186+
if (twsk) {
187+
ao = rcu_dereference_protected(tcp_twsk(sk)->ao_info, 1);
188+
tcp_twsk(sk)->ao_info = NULL;
189+
} else {
190+
ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 1);
191+
tcp_sk(sk)->ao_info = NULL;
192+
}
187193

188-
if (!ao)
194+
if (!ao || !refcount_dec_and_test(&ao->refcnt))
189195
return;
190196

191197
hlist_for_each_entry_safe(key, n, &ao->head, node) {
192198
hlist_del_rcu(&key->node);
193-
atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc);
199+
if (!twsk)
200+
atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc);
194201
call_rcu(&key->rcu, tcp_ao_key_free_rcu);
195202
}
196203

197204
kfree_rcu(ao, rcu);
198205
}
199206

207+
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp)
208+
{
209+
struct tcp_ao_info *ao_info = rcu_dereference_protected(tp->ao_info, 1);
210+
211+
if (ao_info) {
212+
struct tcp_ao_key *key;
213+
struct hlist_node *n;
214+
int omem = 0;
215+
216+
hlist_for_each_entry_safe(key, n, &ao_info->head, node) {
217+
omem += tcp_ao_sizeof_key(key);
218+
}
219+
220+
refcount_inc(&ao_info->refcnt);
221+
atomic_sub(omem, &(((struct sock *)tp)->sk_omem_alloc));
222+
rcu_assign_pointer(tcptw->ao_info, ao_info);
223+
} else {
224+
tcptw->ao_info = NULL;
225+
}
226+
}
227+
200228
/* 4 tuple and ISNs are expected in NBO */
201229
static int tcp_v4_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
202230
__be32 saddr, __be32 daddr,
@@ -514,11 +542,13 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
514542
if (!sk)
515543
return -ENOTCONN;
516544

517-
if ((1 << sk->sk_state) &
518-
(TCPF_LISTEN | TCPF_NEW_SYN_RECV | TCPF_TIME_WAIT))
545+
if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) {
519546
return -1;
520547

521-
ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
548+
if (sk->sk_state == TCP_TIME_WAIT)
549+
ao_info = rcu_dereference(tcp_twsk(sk)->ao_info);
550+
else
551+
ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
522552
if (!ao_info)
523553
return -ENOENT;
524554

@@ -910,6 +940,9 @@ static struct tcp_ao_info *setsockopt_ao_info(struct sock *sk)
910940
if (sk_fullsock(sk)) {
911941
return rcu_dereference_protected(tcp_sk(sk)->ao_info,
912942
lockdep_sock_is_held(sk));
943+
} else if (sk->sk_state == TCP_TIME_WAIT) {
944+
return rcu_dereference_protected(tcp_twsk(sk)->ao_info,
945+
lockdep_sock_is_held(sk));
913946
}
914947
return ERR_PTR(-ESOCKTNOSUPPORT);
915948
}

net/ipv4/tcp_ipv4.c

+73-19
Original file line numberDiff line numberDiff line change
@@ -911,17 +911,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
911911
static void tcp_v4_send_ack(const struct sock *sk,
912912
struct sk_buff *skb, u32 seq, u32 ack,
913913
u32 win, u32 tsval, u32 tsecr, int oif,
914-
struct tcp_md5sig_key *key,
914+
struct tcp_key *key,
915915
int reply_flags, u8 tos, u32 txhash)
916916
{
917917
const struct tcphdr *th = tcp_hdr(skb);
918918
struct {
919919
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)];
925921
} rep;
926922
struct net *net = sock_net(sk);
927923
struct ip_reply_arg arg;
@@ -952,7 +948,7 @@ static void tcp_v4_send_ack(const struct sock *sk,
952948
rep.th.window = htons(win);
953949

954950
#ifdef CONFIG_TCP_MD5SIG
955-
if (key) {
951+
if (tcp_key_is_md5(key)) {
956952
int offset = (tsecr) ? 3 : 0;
957953

958954
rep.opt[offset++] = htonl((TCPOPT_NOP << 24) |
@@ -963,9 +959,27 @@ static void tcp_v4_send_ack(const struct sock *sk,
963959
rep.th.doff = arg.iov[0].iov_len/4;
964960

965961
tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset],
966-
key, ip_hdr(skb)->saddr,
962+
key->md5_key, ip_hdr(skb)->saddr,
967963
ip_hdr(skb)->daddr, &rep.th);
968964
}
965+
#endif
966+
#ifdef CONFIG_TCP_AO
967+
if (tcp_key_is_ao(key)) {
968+
int offset = (tsecr) ? 3 : 0;
969+
970+
rep.opt[offset++] = htonl((TCPOPT_AO << 24) |
971+
(tcp_ao_len(key->ao_key) << 16) |
972+
(key->ao_key->sndid << 8) |
973+
key->rcv_next);
974+
arg.iov[0].iov_len += round_up(tcp_ao_len(key->ao_key), 4);
975+
rep.th.doff = arg.iov[0].iov_len / 4;
976+
977+
tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset],
978+
key->ao_key, key->traffic_key,
979+
(union tcp_ao_addr *)&ip_hdr(skb)->saddr,
980+
(union tcp_ao_addr *)&ip_hdr(skb)->daddr,
981+
&rep.th, key->sne);
982+
}
969983
#endif
970984
arg.flags = reply_flags;
971985
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -999,27 +1013,58 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
9991013
{
10001014
struct inet_timewait_sock *tw = inet_twsk(sk);
10011015
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
1016+
struct tcp_key key = {};
1017+
#ifdef CONFIG_TCP_AO
1018+
struct tcp_ao_info *ao_info;
1019+
1020+
/* FIXME: the segment to-be-acked is not verified yet */
1021+
ao_info = rcu_dereference(tcptw->ao_info);
1022+
if (ao_info) {
1023+
const struct tcp_ao_hdr *aoh;
1024+
1025+
if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh)) {
1026+
inet_twsk_put(tw);
1027+
return;
1028+
}
1029+
1030+
if (aoh)
1031+
key.ao_key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1);
1032+
}
1033+
if (key.ao_key) {
1034+
struct tcp_ao_key *rnext_key;
1035+
1036+
key.traffic_key = snd_other_key(key.ao_key);
1037+
rnext_key = READ_ONCE(ao_info->rnext_key);
1038+
key.rcv_next = rnext_key->rcvid;
1039+
key.type = TCP_KEY_AO;
1040+
#else
1041+
if (0) {
1042+
#endif
1043+
#ifdef CONFIG_TCP_MD5SIG
1044+
} else if (static_branch_unlikely(&tcp_md5_needed.key)) {
1045+
key.md5_key = tcp_twsk_md5_key(tcptw);
1046+
if (key.md5_key)
1047+
key.type = TCP_KEY_MD5;
1048+
#endif
1049+
}
10021050

10031051
tcp_v4_send_ack(sk, skb,
10041052
tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
10051053
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
10061054
tcp_tw_tsval(tcptw),
10071055
tcptw->tw_ts_recent,
1008-
tw->tw_bound_dev_if,
1009-
tcp_twsk_md5_key(tcptw),
1056+
tw->tw_bound_dev_if, &key,
10101057
tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0,
10111058
tw->tw_tos,
1012-
tw->tw_txhash
1013-
);
1059+
tw->tw_txhash);
10141060

10151061
inet_twsk_put(tw);
10161062
}
10171063

10181064
static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
10191065
struct request_sock *req)
10201066
{
1021-
const union tcp_md5_addr *addr;
1022-
int l3index;
1067+
struct tcp_key key = {};
10231068

10241069
/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
10251070
* sk->sk_state == TCP_SYN_RECV -> for Fast Open.
@@ -1032,15 +1077,24 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
10321077
* exception of <SYN> segments, MUST be right-shifted by
10331078
* Rcv.Wind.Shift bits:
10341079
*/
1035-
addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr;
1036-
l3index = tcp_v4_sdif(skb) ? inet_iif(skb) : 0;
1080+
#ifdef CONFIG_TCP_MD5SIG
1081+
if (static_branch_unlikely(&tcp_md5_needed.key)) {
1082+
const union tcp_md5_addr *addr;
1083+
int l3index;
1084+
1085+
addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr;
1086+
l3index = tcp_v4_sdif(skb) ? inet_iif(skb) : 0;
1087+
key.md5_key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);
1088+
if (key.md5_key)
1089+
key.type = TCP_KEY_MD5;
1090+
}
1091+
#endif
10371092
tcp_v4_send_ack(sk, skb, seq,
10381093
tcp_rsk(req)->rcv_nxt,
10391094
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
10401095
tcp_rsk_tsval(tcp_rsk(req)),
10411096
READ_ONCE(req->ts_recent),
1042-
0,
1043-
tcp_md5_do_lookup(sk, l3index, addr, AF_INET),
1097+
0, &key,
10441098
inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
10451099
ip_hdr(skb)->tos,
10461100
READ_ONCE(tcp_rsk(req)->txhash));
@@ -2404,7 +2458,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
24042458
rcu_assign_pointer(tp->md5sig_info, NULL);
24052459
}
24062460
#endif
2407-
tcp_ao_destroy_sock(sk);
2461+
tcp_ao_destroy_sock(sk, false);
24082462

24092463
/* Clean up a referenced TCP bind bucket. */
24102464
if (inet_csk(sk)->icsk_bind_hash)

net/ipv4/tcp_minisocks.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ static void tcp_time_wait_init(struct sock *sk, struct tcp_timewait_sock *tcptw)
279279
void tcp_time_wait(struct sock *sk, int state, int timeo)
280280
{
281281
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);
283283
struct net *net = sock_net(sk);
284284
struct inet_timewait_sock *tw;
285285

@@ -316,6 +316,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
316316
#endif
317317

318318
tcp_time_wait_init(sk, tcptw);
319+
tcp_ao_time_wait(tcptw, tp);
319320

320321
/* Get the TIME_WAIT timeout firing. */
321322
if (timeo < rto)
@@ -370,6 +371,7 @@ void tcp_twsk_destructor(struct sock *sk)
370371
call_rcu(&twsk->tw_md5_key->rcu, tcp_md5_twsk_free_rcu);
371372
}
372373
#endif
374+
tcp_ao_destroy_sock(sk, true);
373375
}
374376
EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
375377

net/ipv4/tcp_output.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3997,7 +3997,7 @@ int tcp_connect(struct sock *sk)
39973997
* then free up ao_info if allocated.
39983998
*/
39993999
if (needs_md5) {
4000-
tcp_ao_destroy_sock(sk);
4000+
tcp_ao_destroy_sock(sk, false);
40014001
} else if (needs_ao) {
40024002
tcp_clear_md5_list(sk);
40034003
kfree(rcu_replace_pointer(tp->md5sig_info, NULL,

0 commit comments

Comments
 (0)