Skip to content

Commit 3ba0752

Browse files
edumazetkuba-moo
authored andcommitted
tcp: be less liberal in TSEcr received while in SYN_RECV state
Yong-Hao Zou mentioned that linux was not strict as other OS in 3WHS, for flows using TCP TS option (RFC 7323) As hinted by an old comment in tcp_check_req(), we can check the TSEcr value in the incoming packet corresponds to one of the SYNACK TSval values we have sent. In this patch, I record the oldest and most recent values that SYNACK packets have used. Send a challenge ACK if we receive a TSEcr outside of this range, and increase a new SNMP counter. nstat -az | grep TSEcrRejected TcpExtTSEcrRejected 0 0.0 Due to TCP fastopen implementation, do not apply yet these checks for fastopen flows. v2: No longer use req->num_timeout, but treq->snt_tsval_first to detect when first SYNACK is prepared. This means we make sure to not send an initial zero TSval. Make sure MPTCP and TCP selftests are passing. Change MIB name to TcpExtTSEcrRejected v1: https://lore.kernel.org/netdev/CADVnQykD8i4ArpSZaPKaoNxLJ2if2ts9m4As+=Jvdkrgx1qMHw@mail.gmail.com/T/ Reported-by: Yong-Hao Zou <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Matthieu Baerts (NGI0) <[email protected]> Reviewed-by: Neal Cardwell <[email protected]> Reviewed-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 91c8d8e commit 3ba0752

File tree

8 files changed

+28
-11
lines changed

8 files changed

+28
-11
lines changed

Documentation/networking/net_cachelines/snmp.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ unsigned_long LINUX_MIB_TIMEWAITRECYCLED
3636
unsigned_long LINUX_MIB_TIMEWAITKILLED
3737
unsigned_long LINUX_MIB_PAWSACTIVEREJECTED
3838
unsigned_long LINUX_MIB_PAWSESTABREJECTED
39+
unsigned_long LINUX_MIB_TSECR_REJECTED
3940
unsigned_long LINUX_MIB_DELAYEDACKLOST
4041
unsigned_long LINUX_MIB_LISTENOVERFLOWS
4142
unsigned_long LINUX_MIB_LISTENDROPS

include/linux/tcp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ struct tcp_request_sock {
160160
u32 rcv_isn;
161161
u32 snt_isn;
162162
u32 ts_off;
163+
u32 snt_tsval_first;
164+
u32 snt_tsval_last;
163165
u32 last_oow_ack_time; /* last SYNACK */
164166
u32 rcv_nxt; /* the ack # by SYNACK. For
165167
* FastOpen it's the seq#

include/uapi/linux/snmp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ enum
186186
LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */
187187
LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */
188188
LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */
189+
LINUX_MIB_TSECRREJECTED, /* TSEcrRejected */
189190
LINUX_MIB_PAWS_OLD_ACK, /* PAWSOldAck */
190191
LINUX_MIB_DELAYEDACKS, /* DelayedACKs */
191192
LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */

net/ipv4/proc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ static const struct snmp_mib snmp4_net_list[] = {
189189
SNMP_MIB_ITEM("TWKilled", LINUX_MIB_TIMEWAITKILLED),
190190
SNMP_MIB_ITEM("PAWSActive", LINUX_MIB_PAWSACTIVEREJECTED),
191191
SNMP_MIB_ITEM("PAWSEstab", LINUX_MIB_PAWSESTABREJECTED),
192+
SNMP_MIB_ITEM("TSEcrRejected", LINUX_MIB_TSECRREJECTED),
192193
SNMP_MIB_ITEM("PAWSOldAck", LINUX_MIB_PAWS_OLD_ACK),
193194
SNMP_MIB_ITEM("DelayedACKs", LINUX_MIB_DELAYEDACKS),
194195
SNMP_MIB_ITEM("DelayedACKLocked", LINUX_MIB_DELAYEDACKLOCKED),

net/ipv4/syncookies.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb,
279279
ireq->smc_ok = 0;
280280

281281
treq->snt_synack = 0;
282+
treq->snt_tsval_first = 0;
282283
treq->tfo_listener = false;
283284
treq->txhash = net_tx_rndhash();
284285
treq->rcv_isn = ntohl(th->seq) - 1;

net/ipv4/tcp_input.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7081,6 +7081,7 @@ static void tcp_openreq_init(struct request_sock *req,
70817081
tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
70827082
tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
70837083
tcp_rsk(req)->snt_synack = 0;
7084+
tcp_rsk(req)->snt_tsval_first = 0;
70847085
tcp_rsk(req)->last_oow_ack_time = 0;
70857086
req->mss = rx_opt->mss_clamp;
70867087
req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;

net/ipv4/tcp_minisocks.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
663663
struct sock *child;
664664
const struct tcphdr *th = tcp_hdr(skb);
665665
__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
666+
bool tsecr_reject = false;
666667
bool paws_reject = false;
667668
bool own_req;
668669

@@ -672,8 +673,13 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
672673

673674
if (tmp_opt.saw_tstamp) {
674675
tmp_opt.ts_recent = READ_ONCE(req->ts_recent);
675-
if (tmp_opt.rcv_tsecr)
676+
if (tmp_opt.rcv_tsecr) {
677+
if (inet_rsk(req)->tstamp_ok && !fastopen)
678+
tsecr_reject = !between(tmp_opt.rcv_tsecr,
679+
tcp_rsk(req)->snt_tsval_first,
680+
READ_ONCE(tcp_rsk(req)->snt_tsval_last));
676681
tmp_opt.rcv_tsecr -= tcp_rsk(req)->ts_off;
682+
}
677683
/* We do not store true stamp, but it is not required,
678684
* it can be estimated (approximately)
679685
* from another data.
@@ -788,18 +794,14 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
788794
tcp_rsk(req)->snt_isn + 1))
789795
return sk;
790796

791-
/* Also, it would be not so bad idea to check rcv_tsecr, which
792-
* is essentially ACK extension and too early or too late values
793-
* should cause reset in unsynchronized states.
794-
*/
795-
796797
/* RFC793: "first check sequence number". */
797798

798-
if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq,
799-
TCP_SKB_CB(skb)->end_seq,
800-
tcp_rsk(req)->rcv_nxt,
801-
tcp_rsk(req)->rcv_nxt +
802-
tcp_synack_window(req))) {
799+
if (paws_reject || tsecr_reject ||
800+
!tcp_in_window(TCP_SKB_CB(skb)->seq,
801+
TCP_SKB_CB(skb)->end_seq,
802+
tcp_rsk(req)->rcv_nxt,
803+
tcp_rsk(req)->rcv_nxt +
804+
tcp_synack_window(req))) {
803805
/* Out of window: send ACK and drop. */
804806
if (!(flg & TCP_FLAG_RST) &&
805807
!tcp_oow_rate_limited(sock_net(sk), skb,
@@ -808,6 +810,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
808810
req->rsk_ops->send_ack(sk, skb, req);
809811
if (paws_reject)
810812
NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
813+
else if (tsecr_reject)
814+
NET_INC_STATS(sock_net(sk), LINUX_MIB_TSECRREJECTED);
811815
return NULL;
812816
}
813817

net/ipv4/tcp_output.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,12 @@ static unsigned int tcp_synack_options(const struct sock *sk,
943943
opts->options |= OPTION_TS;
944944
opts->tsval = tcp_skb_timestamp_ts(tcp_rsk(req)->req_usec_ts, skb) +
945945
tcp_rsk(req)->ts_off;
946+
if (!tcp_rsk(req)->snt_tsval_first) {
947+
if (!opts->tsval)
948+
opts->tsval = ~0U;
949+
tcp_rsk(req)->snt_tsval_first = opts->tsval;
950+
}
951+
WRITE_ONCE(tcp_rsk(req)->snt_tsval_last, opts->tsval);
946952
opts->tsecr = READ_ONCE(req->ts_recent);
947953
remaining -= TCPOLEN_TSTAMP_ALIGNED;
948954
}

0 commit comments

Comments
 (0)