Skip to content

Commit ec4040a

Browse files
committed
Merge branch 'net-sk_err-lockless-annotate'
Eric Dumazet says: ==================== net: annotate lockless accesses to sk_err[_soft] This patch series is inspired by yet another syzbot report. Most poll() handlers are lockless and read sk->sk_err while other cpus can change it. Add READ_ONCE/WRITE_ONCE() to major/usual offenders. More to come later. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 731b73d + cc04410 commit ec4040a

20 files changed

+63
-56
lines changed

fs/dlm/lowcomms.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ static void lowcomms_error_report(struct sock *sk)
601601
"sk_err=%d/%d\n", dlm_our_nodeid(),
602602
con->nodeid, &inet->inet_daddr,
603603
ntohs(inet->inet_dport), sk->sk_err,
604-
sk->sk_err_soft);
604+
READ_ONCE(sk->sk_err_soft));
605605
break;
606606
#if IS_ENABLED(CONFIG_IPV6)
607607
case AF_INET6:
@@ -610,14 +610,15 @@ static void lowcomms_error_report(struct sock *sk)
610610
"dport %d, sk_err=%d/%d\n", dlm_our_nodeid(),
611611
con->nodeid, &sk->sk_v6_daddr,
612612
ntohs(inet->inet_dport), sk->sk_err,
613-
sk->sk_err_soft);
613+
READ_ONCE(sk->sk_err_soft));
614614
break;
615615
#endif
616616
default:
617617
printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
618618
"invalid socket family %d set, "
619619
"sk_err=%d/%d\n", dlm_our_nodeid(),
620-
sk->sk_family, sk->sk_err, sk->sk_err_soft);
620+
sk->sk_family, sk->sk_err,
621+
READ_ONCE(sk->sk_err_soft));
621622
break;
622623
}
623624

net/atm/signaling.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
125125
break;
126126
case as_addparty:
127127
case as_dropparty:
128-
sk->sk_err_soft = -msg->reply;
128+
WRITE_ONCE(sk->sk_err_soft, -msg->reply);
129129
/* < 0 failure, otherwise ep_ref */
130130
clear_bit(ATM_VF_WAITING, &vcc->flags);
131131
break;

net/dccp/ipv4.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
177177
* for the case, if this connection will not able to recover.
178178
*/
179179
if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst))
180-
sk->sk_err_soft = EMSGSIZE;
180+
WRITE_ONCE(sk->sk_err_soft, EMSGSIZE);
181181

182182
mtu = dst_mtu(dst);
183183

@@ -339,8 +339,9 @@ static int dccp_v4_err(struct sk_buff *skb, u32 info)
339339
sk_error_report(sk);
340340

341341
dccp_done(sk);
342-
} else
343-
sk->sk_err_soft = err;
342+
} else {
343+
WRITE_ONCE(sk->sk_err_soft, err);
344+
}
344345
goto out;
345346
}
346347

@@ -364,8 +365,9 @@ static int dccp_v4_err(struct sk_buff *skb, u32 info)
364365
if (!sock_owned_by_user(sk) && inet->recverr) {
365366
sk->sk_err = err;
366367
sk_error_report(sk);
367-
} else /* Only an error on timeout */
368-
sk->sk_err_soft = err;
368+
} else { /* Only an error on timeout */
369+
WRITE_ONCE(sk->sk_err_soft, err);
370+
}
369371
out:
370372
bh_unlock_sock(sk);
371373
sock_put(sk);

net/dccp/ipv6.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,18 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
174174
*/
175175
sk_error_report(sk);
176176
dccp_done(sk);
177-
} else
178-
sk->sk_err_soft = err;
177+
} else {
178+
WRITE_ONCE(sk->sk_err_soft, err);
179+
}
179180
goto out;
180181
}
181182

182183
if (!sock_owned_by_user(sk) && np->recverr) {
183184
sk->sk_err = err;
184185
sk_error_report(sk);
185-
} else
186-
sk->sk_err_soft = err;
187-
186+
} else {
187+
WRITE_ONCE(sk->sk_err_soft, err);
188+
}
188189
out:
189190
bh_unlock_sock(sk);
190191
sock_put(sk);

net/dccp/timer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ int sysctl_dccp_retries2 __read_mostly = TCP_RETR2;
1919

2020
static void dccp_write_err(struct sock *sk)
2121
{
22-
sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
22+
sk->sk_err = READ_ONCE(sk->sk_err_soft) ? : ETIMEDOUT;
2323
sk_error_report(sk);
2424

2525
dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);

net/ipv4/af_inet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,7 @@ int inet_sk_rebuild_header(struct sock *sk)
13221322
sk->sk_state != TCP_SYN_SENT ||
13231323
(sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
13241324
(err = inet_sk_reselect_saddr(sk)) != 0)
1325-
sk->sk_err_soft = -err;
1325+
WRITE_ONCE(sk->sk_err_soft, -err);
13261326
}
13271327

13281328
return err;

net/ipv4/tcp.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,8 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
589589
}
590590
/* This barrier is coupled with smp_wmb() in tcp_reset() */
591591
smp_rmb();
592-
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
592+
if (READ_ONCE(sk->sk_err) ||
593+
!skb_queue_empty_lockless(&sk->sk_error_queue))
593594
mask |= EPOLLERR;
594595

595596
return mask;
@@ -3094,17 +3095,17 @@ int tcp_disconnect(struct sock *sk, int flags)
30943095
if (old_state == TCP_LISTEN) {
30953096
inet_csk_listen_stop(sk);
30963097
} else if (unlikely(tp->repair)) {
3097-
sk->sk_err = ECONNABORTED;
3098+
WRITE_ONCE(sk->sk_err, ECONNABORTED);
30983099
} else if (tcp_need_reset(old_state) ||
30993100
(tp->snd_nxt != tp->write_seq &&
31003101
(1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
31013102
/* The last check adjusts for discrepancy of Linux wrt. RFC
31023103
* states
31033104
*/
31043105
tcp_send_active_reset(sk, gfp_any());
3105-
sk->sk_err = ECONNRESET;
3106+
WRITE_ONCE(sk->sk_err, ECONNRESET);
31063107
} else if (old_state == TCP_SYN_SENT)
3107-
sk->sk_err = ECONNRESET;
3108+
WRITE_ONCE(sk->sk_err, ECONNRESET);
31083109

31093110
tcp_clear_xmit_timers(sk);
31103111
__skb_queue_purge(&sk->sk_receive_queue);
@@ -4692,7 +4693,7 @@ int tcp_abort(struct sock *sk, int err)
46924693
bh_lock_sock(sk);
46934694

46944695
if (!sock_flag(sk, SOCK_DEAD)) {
4695-
sk->sk_err = err;
4696+
WRITE_ONCE(sk->sk_err, err);
46964697
/* This barrier is coupled with smp_rmb() in tcp_poll() */
46974698
smp_wmb();
46984699
sk_error_report(sk);

net/ipv4/tcp_input.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3874,7 +3874,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
38743874
/* We passed data and got it acked, remove any soft error
38753875
* log. Something worked...
38763876
*/
3877-
sk->sk_err_soft = 0;
3877+
WRITE_ONCE(sk->sk_err_soft, 0);
38783878
icsk->icsk_probes_out = 0;
38793879
tp->rcv_tstamp = tcp_jiffies32;
38803880
if (!prior_packets)
@@ -4322,15 +4322,15 @@ void tcp_reset(struct sock *sk, struct sk_buff *skb)
43224322
/* We want the right error as BSD sees it (and indeed as we do). */
43234323
switch (sk->sk_state) {
43244324
case TCP_SYN_SENT:
4325-
sk->sk_err = ECONNREFUSED;
4325+
WRITE_ONCE(sk->sk_err, ECONNREFUSED);
43264326
break;
43274327
case TCP_CLOSE_WAIT:
4328-
sk->sk_err = EPIPE;
4328+
WRITE_ONCE(sk->sk_err, EPIPE);
43294329
break;
43304330
case TCP_CLOSE:
43314331
return;
43324332
default:
4333-
sk->sk_err = ECONNRESET;
4333+
WRITE_ONCE(sk->sk_err, ECONNRESET);
43344334
}
43354335
/* This barrier is coupled with smp_rmb() in tcp_poll() */
43364336
smp_wmb();

net/ipv4/tcp_ipv4.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ void tcp_v4_mtu_reduced(struct sock *sk)
361361
* for the case, if this connection will not able to recover.
362362
*/
363363
if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst))
364-
sk->sk_err_soft = EMSGSIZE;
364+
WRITE_ONCE(sk->sk_err_soft, EMSGSIZE);
365365

366366
mtu = dst_mtu(dst);
367367

@@ -596,13 +596,13 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
596596
ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th);
597597

598598
if (!sock_owned_by_user(sk)) {
599-
sk->sk_err = err;
599+
WRITE_ONCE(sk->sk_err, err);
600600

601601
sk_error_report(sk);
602602

603603
tcp_done(sk);
604604
} else {
605-
sk->sk_err_soft = err;
605+
WRITE_ONCE(sk->sk_err_soft, err);
606606
}
607607
goto out;
608608
}
@@ -625,10 +625,10 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
625625

626626
inet = inet_sk(sk);
627627
if (!sock_owned_by_user(sk) && inet->recverr) {
628-
sk->sk_err = err;
628+
WRITE_ONCE(sk->sk_err, err);
629629
sk_error_report(sk);
630630
} else { /* Only an error on timeout */
631-
sk->sk_err_soft = err;
631+
WRITE_ONCE(sk->sk_err_soft, err);
632632
}
633633

634634
out:

net/ipv4/tcp_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3699,7 +3699,7 @@ static void tcp_connect_init(struct sock *sk)
36993699
tp->rx_opt.rcv_wscale = rcv_wscale;
37003700
tp->rcv_ssthresh = tp->rcv_wnd;
37013701

3702-
sk->sk_err = 0;
3702+
WRITE_ONCE(sk->sk_err, 0);
37033703
sock_reset_flag(sk, SOCK_DONE);
37043704
tp->snd_wnd = 0;
37053705
tcp_init_wl(tp, 0);

net/ipv4/tcp_timer.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
6767

6868
static void tcp_write_err(struct sock *sk)
6969
{
70-
sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
70+
WRITE_ONCE(sk->sk_err, READ_ONCE(sk->sk_err_soft) ? : ETIMEDOUT);
7171
sk_error_report(sk);
7272

7373
tcp_write_queue_purge(sk);
@@ -110,7 +110,7 @@ static int tcp_out_of_resources(struct sock *sk, bool do_reset)
110110
shift++;
111111

112112
/* If some dubious ICMP arrived, penalize even more. */
113-
if (sk->sk_err_soft)
113+
if (READ_ONCE(sk->sk_err_soft))
114114
shift++;
115115

116116
if (tcp_check_oom(sk, shift)) {
@@ -146,7 +146,7 @@ static int tcp_orphan_retries(struct sock *sk, bool alive)
146146
int retries = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_orphan_retries); /* May be zero. */
147147

148148
/* We know from an ICMP that something is wrong. */
149-
if (sk->sk_err_soft && !alive)
149+
if (READ_ONCE(sk->sk_err_soft) && !alive)
150150
retries = 0;
151151

152152
/* However, if socket sent something recently, select some safe

net/ipv6/af_inet6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
845845
dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
846846
if (IS_ERR(dst)) {
847847
sk->sk_route_caps = 0;
848-
sk->sk_err_soft = -PTR_ERR(dst);
848+
WRITE_ONCE(sk->sk_err_soft, -PTR_ERR(dst));
849849
return PTR_ERR(dst);
850850
}
851851

net/ipv6/inet6_connection_sock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
120120

121121
dst = inet6_csk_route_socket(sk, &fl6);
122122
if (IS_ERR(dst)) {
123-
sk->sk_err_soft = -PTR_ERR(dst);
123+
WRITE_ONCE(sk->sk_err_soft, -PTR_ERR(dst));
124124
sk->sk_route_caps = 0;
125125
kfree_skb(skb);
126126
return PTR_ERR(dst);

net/ipv6/tcp_ipv6.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -493,12 +493,13 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
493493
ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th);
494494

495495
if (!sock_owned_by_user(sk)) {
496-
sk->sk_err = err;
496+
WRITE_ONCE(sk->sk_err, err);
497497
sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
498498

499499
tcp_done(sk);
500-
} else
501-
sk->sk_err_soft = err;
500+
} else {
501+
WRITE_ONCE(sk->sk_err_soft, err);
502+
}
502503
goto out;
503504
case TCP_LISTEN:
504505
break;
@@ -512,11 +513,11 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
512513
}
513514

514515
if (!sock_owned_by_user(sk) && np->recverr) {
515-
sk->sk_err = err;
516+
WRITE_ONCE(sk->sk_err, err);
516517
sk_error_report(sk);
517-
} else
518-
sk->sk_err_soft = err;
519-
518+
} else {
519+
WRITE_ONCE(sk->sk_err_soft, err);
520+
}
520521
out:
521522
bh_unlock_sock(sk);
522523
sock_put(sk);

net/mptcp/pm_netlink.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ static int mptcp_event_put_token_and_ssk(struct sk_buff *skb,
20192019
nla_put_s32(skb, MPTCP_ATTR_IF_IDX, ssk->sk_bound_dev_if))
20202020
return -EMSGSIZE;
20212021

2022-
sk_err = ssk->sk_err;
2022+
sk_err = READ_ONCE(ssk->sk_err);
20232023
if (sk_err && sk->sk_state == TCP_ESTABLISHED &&
20242024
nla_put_u8(skb, MPTCP_ATTR_ERROR, sk_err))
20252025
return -EMSGSIZE;

net/mptcp/protocol.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,15 +2463,15 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
24632463
/* Mirror the tcp_reset() error propagation */
24642464
switch (sk->sk_state) {
24652465
case TCP_SYN_SENT:
2466-
sk->sk_err = ECONNREFUSED;
2466+
WRITE_ONCE(sk->sk_err, ECONNREFUSED);
24672467
break;
24682468
case TCP_CLOSE_WAIT:
2469-
sk->sk_err = EPIPE;
2469+
WRITE_ONCE(sk->sk_err, EPIPE);
24702470
break;
24712471
case TCP_CLOSE:
24722472
return;
24732473
default:
2474-
sk->sk_err = ECONNRESET;
2474+
WRITE_ONCE(sk->sk_err, ECONNRESET);
24752475
}
24762476

24772477
inet_sk_state_store(sk, TCP_CLOSE);
@@ -3791,7 +3791,7 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
37913791

37923792
/* This barrier is coupled with smp_wmb() in __mptcp_error_report() */
37933793
smp_rmb();
3794-
if (sk->sk_err)
3794+
if (READ_ONCE(sk->sk_err))
37953795
mask |= EPOLLERR;
37963796

37973797
return mask;

net/mptcp/subflow.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,7 +1335,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
13351335
subflow->reset_reason = MPTCP_RST_EMPTCP;
13361336

13371337
reset:
1338-
ssk->sk_err = EBADMSG;
1338+
WRITE_ONCE(ssk->sk_err, EBADMSG);
13391339
tcp_set_state(ssk, TCP_CLOSE);
13401340
while ((skb = skb_peek(&ssk->sk_receive_queue)))
13411341
sk_eat_skb(ssk, skb);
@@ -1419,7 +1419,7 @@ void __mptcp_error_report(struct sock *sk)
14191419
ssk_state = inet_sk_state_load(ssk);
14201420
if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
14211421
inet_sk_state_store(sk, ssk_state);
1422-
sk->sk_err = -err;
1422+
WRITE_ONCE(sk->sk_err, -err);
14231423

14241424
/* This barrier is coupled with smp_rmb() in mptcp_poll() */
14251425
smp_wmb();

net/sctp/input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ static void sctp_v4_err_handle(struct sctp_transport *t, struct sk_buff *skb,
585585
sk->sk_err = err;
586586
sk_error_report(sk);
587587
} else { /* Only an error on timeout */
588-
sk->sk_err_soft = err;
588+
WRITE_ONCE(sk->sk_err_soft, err);
589589
}
590590
}
591591

net/sctp/ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
155155
sk->sk_err = err;
156156
sk_error_report(sk);
157157
} else {
158-
sk->sk_err_soft = err;
158+
WRITE_ONCE(sk->sk_err_soft, err);
159159
}
160160
}
161161

0 commit comments

Comments
 (0)