TCP_SKB_CB(skb)->tcp_tw_isn contains an ISN, chosen by tcp_timewait_state_process() , when SYN is received in TIMEWAIT state. But tcp_tw_isn is not used because it is overwritten by tcp_v4_restore_cb() after commit eeea10b83a13 ("tcp: add tcp_v4_fill_cb()/tcp_v4_restore_cb()").
To fix this case, we record tcp_tw_isn before tcp_v4_restore_cb() and then set it in tcp_v4_fill_cb(). V6 does the same. Fixes: eeea10b83a13 ("tcp: add tcp_v4_fill_cb()/tcp_v4_restore_cb()") Reported-by: chenc <che...@wangsu.com> Signed-off-by: Pengcheng Yang <yan...@wangsu.com> --- net/ipv4/tcp_ipv4.c | 14 ++++++++------ net/ipv6/tcp_ipv6.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 58207c7..c8cceaa 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1892,7 +1892,7 @@ static void tcp_v4_restore_cb(struct sk_buff *skb) } static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, - const struct tcphdr *th) + const struct tcphdr *th, __u32 isn) { /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() * barrier() makes sure compiler wont play fool^Waliasing games. @@ -1906,7 +1906,7 @@ static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, skb->len - th->doff * 4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->tcp_tw_isn = isn; TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); TCP_SKB_CB(skb)->sacked = 0; TCP_SKB_CB(skb)->has_rxtstamp = @@ -1927,6 +1927,7 @@ int tcp_v4_rcv(struct sk_buff *skb) const struct tcphdr *th; bool refcounted; struct sock *sk; + __u32 isn = 0; int ret; if (skb->pkt_type != PACKET_HOST) @@ -1993,7 +1994,7 @@ int tcp_v4_rcv(struct sk_buff *skb) if (!tcp_filter(sk, skb)) { th = (const struct tcphdr *)skb->data; iph = ip_hdr(skb); - tcp_v4_fill_cb(skb, iph, th); + tcp_v4_fill_cb(skb, iph, th, isn); nsk = tcp_check_req(sk, skb, req, false, &req_stolen); } if (!nsk) { @@ -2038,7 +2039,7 @@ int tcp_v4_rcv(struct sk_buff *skb) goto discard_and_relse; th = (const struct tcphdr *)skb->data; iph = ip_hdr(skb); - tcp_v4_fill_cb(skb, iph, th); + tcp_v4_fill_cb(skb, iph, th, isn); skb->dev = NULL; @@ -2075,7 +2076,7 @@ int tcp_v4_rcv(struct sk_buff *skb) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; - tcp_v4_fill_cb(skb, iph, th); + tcp_v4_fill_cb(skb, iph, th, isn); if (tcp_checksum_complete(skb)) { csum_error: @@ -2103,7 +2104,7 @@ int tcp_v4_rcv(struct sk_buff *skb) goto discard_it; } - tcp_v4_fill_cb(skb, iph, th); + tcp_v4_fill_cb(skb, iph, th, isn); if (tcp_checksum_complete(skb)) { inet_twsk_put(inet_twsk(sk)); @@ -2121,6 +2122,7 @@ int tcp_v4_rcv(struct sk_buff *skb) if (sk2) { inet_twsk_deschedule_put(inet_twsk(sk)); sk = sk2; + isn = TCP_SKB_CB(skb)->tcp_tw_isn; tcp_v4_restore_cb(skb); refcounted = false; goto process; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0e1509b..a2ff19d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1557,7 +1557,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) } static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, - const struct tcphdr *th) + const struct tcphdr *th, __u32 isn) { /* This is tricky: we move IP6CB at its correct location into * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because @@ -1573,7 +1573,7 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, skb->len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->tcp_tw_isn = isn; TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); TCP_SKB_CB(skb)->sacked = 0; TCP_SKB_CB(skb)->has_rxtstamp = @@ -1589,6 +1589,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) const struct ipv6hdr *hdr; bool refcounted; struct sock *sk; + __u32 isn = 0; int ret; struct net *net = dev_net(skb->dev); @@ -1652,7 +1653,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) if (!tcp_filter(sk, skb)) { th = (const struct tcphdr *)skb->data; hdr = ipv6_hdr(skb); - tcp_v6_fill_cb(skb, hdr, th); + tcp_v6_fill_cb(skb, hdr, th, isn); nsk = tcp_check_req(sk, skb, req, false, &req_stolen); } if (!nsk) { @@ -1695,7 +1696,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) goto discard_and_relse; th = (const struct tcphdr *)skb->data; hdr = ipv6_hdr(skb); - tcp_v6_fill_cb(skb, hdr, th); + tcp_v6_fill_cb(skb, hdr, th, isn); skb->dev = NULL; @@ -1730,7 +1731,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; - tcp_v6_fill_cb(skb, hdr, th); + tcp_v6_fill_cb(skb, hdr, th, isn); if (tcp_checksum_complete(skb)) { csum_error: @@ -1757,7 +1758,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) goto discard_it; } - tcp_v6_fill_cb(skb, hdr, th); + tcp_v6_fill_cb(skb, hdr, th, isn); if (tcp_checksum_complete(skb)) { inet_twsk_put(inet_twsk(sk)); @@ -1780,6 +1781,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); inet_twsk_deschedule_put(tw); sk = sk2; + isn = TCP_SKB_CB(skb)->tcp_tw_isn; tcp_v6_restore_cb(skb); refcounted = false; goto process; -- 1.8.3.1