Skip to content

Commit 00355fa

Browse files
akodanevdavem330
authored andcommitted
tcp: setup timestamp offset when write_seq already set
Found that when randomized tcp offsets are enabled (by default) TCP client can still start new connections without them. Later, if server does active close and re-uses sockets in TIME-WAIT state, new SYN from client can be rejected on PAWS check inside tcp_timewait_state_process(), because either tw_ts_recent or rcv_tsval doesn't really have an offset set. Here is how to reproduce it with LTP netstress tool: netstress -R 1 & netstress -H 127.0.0.1 -lr 1000000 -a1 [...] < S seq 1956977072 win 43690 TS val 295618 ecr 459956970 > . ack 1956911535 win 342 TS val 459967184 ecr 1547117608 < R seq 1956911535 win 0 length 0 +1. < S seq 1956977072 win 43690 TS val 296640 ecr 459956970 > S. seq 657450664 ack 1956977073 win 43690 TS val 459968205 ecr 296640 Fixes: 95a22ca ("tcp: randomize tcp timestamp offsets for each connection") Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent ec7cb62 commit 00355fa

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

net/ipv4/tcp_ipv4.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
145145
struct flowi4 *fl4;
146146
struct rtable *rt;
147147
int err;
148+
u32 seq;
148149
struct ip_options_rcu *inet_opt;
149150
struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
150151

@@ -234,12 +235,15 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
234235
sk_setup_caps(sk, &rt->dst);
235236
rt = NULL;
236237

237-
if (!tp->write_seq && likely(!tp->repair))
238-
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
239-
inet->inet_daddr,
240-
inet->inet_sport,
241-
usin->sin_port,
242-
&tp->tsoffset);
238+
if (likely(!tp->repair)) {
239+
seq = secure_tcp_sequence_number(inet->inet_saddr,
240+
inet->inet_daddr,
241+
inet->inet_sport,
242+
usin->sin_port,
243+
&tp->tsoffset);
244+
if (!tp->write_seq)
245+
tp->write_seq = seq;
246+
}
243247

244248
inet->inet_id = tp->write_seq ^ jiffies;
245249

net/ipv6/tcp_ipv6.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
122122
struct flowi6 fl6;
123123
struct dst_entry *dst;
124124
int addr_type;
125+
u32 seq;
125126
int err;
126127
struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
127128

@@ -285,12 +286,15 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
285286

286287
sk_set_txhash(sk);
287288

288-
if (!tp->write_seq && likely(!tp->repair))
289-
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
290-
sk->sk_v6_daddr.s6_addr32,
291-
inet->inet_sport,
292-
inet->inet_dport,
293-
&tp->tsoffset);
289+
if (likely(!tp->repair)) {
290+
seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
291+
sk->sk_v6_daddr.s6_addr32,
292+
inet->inet_sport,
293+
inet->inet_dport,
294+
&tp->tsoffset);
295+
if (!tp->write_seq)
296+
tp->write_seq = seq;
297+
}
294298

295299
if (tcp_fastopen_defer_connect(sk, &err))
296300
return err;

0 commit comments

Comments
 (0)