Skip to content

Commit 092b5b5

Browse files
q2venRezaT4795
authored andcommitted
net: Fix data-races around sysctl_[rw]mem(_offset)?.
[ Upstream commit 02739545951ad4c1215160db7fbf9b7a918d3c0b ] While reading these sysctl variables, they can be changed concurrently. Thus, we need to add READ_ONCE() to their readers. - .sysctl_rmem - .sysctl_rwmem - .sysctl_rmem_offset - .sysctl_wmem_offset - sysctl_tcp_rmem[1, 2] - sysctl_tcp_wmem[1, 2] - sysctl_decnet_rmem[1] - sysctl_decnet_wmem[1] - sysctl_tipc_rmem[1] Fixes: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e4a2ebc commit 092b5b5

File tree

7 files changed

+21
-20
lines changed

7 files changed

+21
-20
lines changed

include/net/sock.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,18 +2765,18 @@ static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto)
27652765
{
27662766
/* Does this proto have per netns sysctl_wmem ? */
27672767
if (proto->sysctl_wmem_offset)
2768-
return *(int *)((void *)sock_net(sk) + proto->sysctl_wmem_offset);
2768+
return READ_ONCE(*(int *)((void *)sock_net(sk) + proto->sysctl_wmem_offset));
27692769

2770-
return *proto->sysctl_wmem;
2770+
return READ_ONCE(*proto->sysctl_wmem);
27712771
}
27722772

27732773
static inline int sk_get_rmem0(const struct sock *sk, const struct proto *proto)
27742774
{
27752775
/* Does this proto have per netns sysctl_rmem ? */
27762776
if (proto->sysctl_rmem_offset)
2777-
return *(int *)((void *)sock_net(sk) + proto->sysctl_rmem_offset);
2777+
return READ_ONCE(*(int *)((void *)sock_net(sk) + proto->sysctl_rmem_offset));
27782778

2779-
return *proto->sysctl_rmem;
2779+
return READ_ONCE(*proto->sysctl_rmem);
27802780
}
27812781

27822782
/* Default TCP Small queue budget is ~1 ms of data (1sec >> 10)

net/decnet/af_decnet.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,8 @@ static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gf
480480
sk->sk_family = PF_DECnet;
481481
sk->sk_protocol = 0;
482482
sk->sk_allocation = gfp;
483-
sk->sk_sndbuf = sysctl_decnet_wmem[1];
484-
sk->sk_rcvbuf = sysctl_decnet_rmem[1];
483+
sk->sk_sndbuf = READ_ONCE(sysctl_decnet_wmem[1]);
484+
sk->sk_rcvbuf = READ_ONCE(sysctl_decnet_rmem[1]);
485485

486486
/* Initialization of DECnet Session Control Port */
487487
scp = DN_SK(sk);

net/ipv4/tcp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ void tcp_init_sock(struct sock *sk)
458458

459459
icsk->icsk_sync_mss = tcp_sync_mss;
460460

461-
WRITE_ONCE(sk->sk_sndbuf, sock_net(sk)->ipv4.sysctl_tcp_wmem[1]);
462-
WRITE_ONCE(sk->sk_rcvbuf, sock_net(sk)->ipv4.sysctl_tcp_rmem[1]);
461+
WRITE_ONCE(sk->sk_sndbuf, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[1]));
462+
WRITE_ONCE(sk->sk_rcvbuf, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[1]));
463463

464464
sk_sockets_allocated_inc(sk);
465465
sk->sk_route_forced_caps = NETIF_F_GSO;
@@ -1722,7 +1722,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
17221722
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
17231723
cap = sk->sk_rcvbuf >> 1;
17241724
else
1725-
cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1;
1725+
cap = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1;
17261726
val = min(val, cap);
17271727
WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
17281728

net/ipv4/tcp_input.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ static void tcp_sndbuf_expand(struct sock *sk)
426426

427427
if (sk->sk_sndbuf < sndmem)
428428
WRITE_ONCE(sk->sk_sndbuf,
429-
min(sndmem, sock_net(sk)->ipv4.sysctl_tcp_wmem[2]));
429+
min(sndmem, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[2])));
430430
}
431431

432432
/* 2. Tuning advertised window (window_clamp, rcv_ssthresh)
@@ -461,7 +461,7 @@ static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb,
461461
struct tcp_sock *tp = tcp_sk(sk);
462462
/* Optimize this! */
463463
int truesize = tcp_win_from_space(sk, skbtruesize) >> 1;
464-
int window = tcp_win_from_space(sk, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1;
464+
int window = tcp_win_from_space(sk, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])) >> 1;
465465

466466
while (tp->rcv_ssthresh <= window) {
467467
if (truesize <= skb->len)
@@ -566,16 +566,17 @@ static void tcp_clamp_window(struct sock *sk)
566566
struct tcp_sock *tp = tcp_sk(sk);
567567
struct inet_connection_sock *icsk = inet_csk(sk);
568568
struct net *net = sock_net(sk);
569+
int rmem2;
569570

570571
icsk->icsk_ack.quick = 0;
572+
rmem2 = READ_ONCE(net->ipv4.sysctl_tcp_rmem[2]);
571573

572-
if (sk->sk_rcvbuf < net->ipv4.sysctl_tcp_rmem[2] &&
574+
if (sk->sk_rcvbuf < rmem2 &&
573575
!(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
574576
!tcp_under_memory_pressure(sk) &&
575577
sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) {
576578
WRITE_ONCE(sk->sk_rcvbuf,
577-
min(atomic_read(&sk->sk_rmem_alloc),
578-
net->ipv4.sysctl_tcp_rmem[2]));
579+
min(atomic_read(&sk->sk_rmem_alloc), rmem2));
579580
}
580581
if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
581582
tp->rcv_ssthresh = min(tp->window_clamp, 2U * tp->advmss);
@@ -737,7 +738,7 @@ void tcp_rcv_space_adjust(struct sock *sk)
737738

738739
do_div(rcvwin, tp->advmss);
739740
rcvbuf = min_t(u64, rcvwin * rcvmem,
740-
sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
741+
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
741742
if (rcvbuf > sk->sk_rcvbuf) {
742743
WRITE_ONCE(sk->sk_rcvbuf, rcvbuf);
743744

net/ipv4/tcp_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
238238
*rcv_wscale = 0;
239239
if (wscale_ok) {
240240
/* Set window scaling on max possible window */
241-
space = max_t(u32, space, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
241+
space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
242242
space = max_t(u32, space, sysctl_rmem_max);
243243
space = min_t(u32, space, *window_clamp);
244244
*rcv_wscale = clamp_t(int, ilog2(space) - 15,

net/mptcp/protocol.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,7 +1899,7 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
18991899

19001900
do_div(rcvwin, advmss);
19011901
rcvbuf = min_t(u64, rcvwin * rcvmem,
1902-
sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
1902+
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
19031903

19041904
if (rcvbuf > sk->sk_rcvbuf) {
19051905
u32 window_clamp;
@@ -2532,8 +2532,8 @@ static int mptcp_init_sock(struct sock *sk)
25322532
icsk->icsk_ca_ops = NULL;
25332533

25342534
sk_sockets_allocated_inc(sk);
2535-
sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1];
2536-
sk->sk_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[1];
2535+
sk->sk_rcvbuf = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[1]);
2536+
sk->sk_sndbuf = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[1]);
25372537

25382538
return 0;
25392539
}

net/tipc/socket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
517517
timer_setup(&sk->sk_timer, tipc_sk_timeout, 0);
518518
sk->sk_shutdown = 0;
519519
sk->sk_backlog_rcv = tipc_sk_backlog_rcv;
520-
sk->sk_rcvbuf = sysctl_tipc_rmem[1];
520+
sk->sk_rcvbuf = READ_ONCE(sysctl_tipc_rmem[1]);
521521
sk->sk_data_ready = tipc_data_ready;
522522
sk->sk_write_space = tipc_write_space;
523523
sk->sk_destruct = tipc_sock_destruct;

0 commit comments

Comments
 (0)