Skip to content

Commit c0a1149

Browse files
edumazetkuba-moo
authored andcommitted
tcp: annotate data-races around tcptw->tw_rcv_nxt
No lock protects tcp tw fields. tcptw->tw_rcv_nxt can be changed from twsk_rcv_nxt_update() while other threads might read this field. Add READ_ONCE()/WRITE_ONCE() annotations, and make sure tcp_timewait_state_process() reads tcptw->tw_rcv_nxt only once. Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Jason Xing <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 3e5cbbb commit c0a1149

File tree

3 files changed

+18
-14
lines changed

3 files changed

+18
-14
lines changed

net/ipv4/tcp_ipv4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
10731073
}
10741074

10751075
tcp_v4_send_ack(sk, skb,
1076-
tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
1076+
tcptw->tw_snd_nxt, READ_ONCE(tcptw->tw_rcv_nxt),
10771077
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
10781078
tcp_tw_tsval(tcptw),
10791079
READ_ONCE(tcptw->tw_ts_recent),

net/ipv4/tcp_minisocks.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,17 @@ tcp_timewait_check_oow_rate_limit(struct inet_timewait_sock *tw,
5252
return TCP_TW_SUCCESS;
5353
}
5454

55-
static void twsk_rcv_nxt_update(struct tcp_timewait_sock *tcptw, u32 seq)
55+
static void twsk_rcv_nxt_update(struct tcp_timewait_sock *tcptw, u32 seq,
56+
u32 rcv_nxt)
5657
{
5758
#ifdef CONFIG_TCP_AO
5859
struct tcp_ao_info *ao;
5960

6061
ao = rcu_dereference(tcptw->ao_info);
61-
if (unlikely(ao && seq < tcptw->tw_rcv_nxt))
62+
if (unlikely(ao && seq < rcv_nxt))
6263
WRITE_ONCE(ao->rcv_sne, ao->rcv_sne + 1);
6364
#endif
64-
tcptw->tw_rcv_nxt = seq;
65+
WRITE_ONCE(tcptw->tw_rcv_nxt, seq);
6566
}
6667

6768
/*
@@ -98,8 +99,9 @@ enum tcp_tw_status
9899
tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
99100
const struct tcphdr *th, u32 *tw_isn)
100101
{
101-
struct tcp_options_received tmp_opt;
102102
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
103+
u32 rcv_nxt = READ_ONCE(tcptw->tw_rcv_nxt);
104+
struct tcp_options_received tmp_opt;
103105
bool paws_reject = false;
104106
int ts_recent_stamp;
105107

@@ -123,20 +125,20 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
123125
/* Out of window, send ACK */
124126
if (paws_reject ||
125127
!tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
126-
tcptw->tw_rcv_nxt,
127-
tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd))
128+
rcv_nxt,
129+
rcv_nxt + tcptw->tw_rcv_wnd))
128130
return tcp_timewait_check_oow_rate_limit(
129131
tw, skb, LINUX_MIB_TCPACKSKIPPEDFINWAIT2);
130132

131133
if (th->rst)
132134
goto kill;
133135

134-
if (th->syn && !before(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt))
136+
if (th->syn && !before(TCP_SKB_CB(skb)->seq, rcv_nxt))
135137
return TCP_TW_RST;
136138

137139
/* Dup ACK? */
138140
if (!th->ack ||
139-
!after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) ||
141+
!after(TCP_SKB_CB(skb)->end_seq, rcv_nxt) ||
140142
TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
141143
inet_twsk_put(tw);
142144
return TCP_TW_SUCCESS;
@@ -146,12 +148,13 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
146148
* reset.
147149
*/
148150
if (!th->fin ||
149-
TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1)
151+
TCP_SKB_CB(skb)->end_seq != rcv_nxt + 1)
150152
return TCP_TW_RST;
151153

152154
/* FIN arrived, enter true time-wait state. */
153155
WRITE_ONCE(tw->tw_substate, TCP_TIME_WAIT);
154-
twsk_rcv_nxt_update(tcptw, TCP_SKB_CB(skb)->end_seq);
156+
twsk_rcv_nxt_update(tcptw, TCP_SKB_CB(skb)->end_seq,
157+
rcv_nxt);
155158

156159
if (tmp_opt.saw_tstamp) {
157160
WRITE_ONCE(tcptw->tw_ts_recent_stamp,
@@ -182,7 +185,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
182185
*/
183186

184187
if (!paws_reject &&
185-
(TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt &&
188+
(TCP_SKB_CB(skb)->seq == rcv_nxt &&
186189
(TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) {
187190
/* In window segment, it may be only reset or bare ack. */
188191

@@ -229,7 +232,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
229232
*/
230233

231234
if (th->syn && !th->rst && !th->ack && !paws_reject &&
232-
(after(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt) ||
235+
(after(TCP_SKB_CB(skb)->seq, rcv_nxt) ||
233236
(tmp_opt.saw_tstamp &&
234237
(s32)(READ_ONCE(tcptw->tw_ts_recent) - tmp_opt.rcv_tsval) < 0))) {
235238
u32 isn = tcptw->tw_snd_nxt + 65535 + 2;

net/ipv6/tcp_ipv6.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
11931193
#endif
11941194
}
11951195

1196-
tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
1196+
tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt,
1197+
READ_ONCE(tcptw->tw_rcv_nxt),
11971198
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
11981199
tcp_tw_tsval(tcptw),
11991200
READ_ONCE(tcptw->tw_ts_recent), tw->tw_bound_dev_if,

0 commit comments

Comments
 (0)