tcp: Fix data-races around sysctl knobs related to SYN option.

[ Upstream commit 3666f666e99600518ab20982af04a078bbdad277 ]

While reading these knobs, they can be changed concurrently.
Thus, we need to add READ_ONCE() to their readers.

  - tcp_sack
  - tcp_window_scaling
  - tcp_timestamps

Fixes: 1da177e4c3 ("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>
This commit is contained in:
Kuniyuki Iwashima 2022-07-18 10:26:44 -07:00 committed by Greg Kroah-Hartman
parent f39b03bd72
commit 795aee11fd
5 changed files with 16 additions and 16 deletions

View File

@ -1103,8 +1103,8 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
csk->sndbuf = newsk->sk_sndbuf; csk->sndbuf = newsk->sk_sndbuf;
csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx; csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx;
RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk), RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
sock_net(newsk)-> READ_ONCE(sock_net(newsk)->
ipv4.sysctl_tcp_window_scaling, ipv4.sysctl_tcp_window_scaling),
tp->window_clamp); tp->window_clamp);
neigh_release(n); neigh_release(n);
inet_inherit_port(&tcp_hashinfo, lsk, newsk); inet_inherit_port(&tcp_hashinfo, lsk, newsk);
@ -1235,7 +1235,7 @@ static void chtls_pass_accept_request(struct sock *sk,
chtls_set_req_addr(oreq, iph->daddr, iph->saddr); chtls_set_req_addr(oreq, iph->daddr, iph->saddr);
ip_dsfield = ipv4_get_dsfield(iph); ip_dsfield = ipv4_get_dsfield(iph);
if (req->tcpopt.wsf <= 14 && if (req->tcpopt.wsf <= 14 &&
sock_net(sk)->ipv4.sysctl_tcp_window_scaling) { READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
inet_rsk(oreq)->wscale_ok = 1; inet_rsk(oreq)->wscale_ok = 1;
inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf; inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf;
} }

View File

@ -65,7 +65,7 @@ u32 secure_tcpv6_ts_off(const struct net *net,
.daddr = *(struct in6_addr *)daddr, .daddr = *(struct in6_addr *)daddr,
}; };
if (net->ipv4.sysctl_tcp_timestamps != 1) if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
return 0; return 0;
ts_secret_init(); ts_secret_init();
@ -121,7 +121,7 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#ifdef CONFIG_INET #ifdef CONFIG_INET
u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr) u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
{ {
if (net->ipv4.sysctl_tcp_timestamps != 1) if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
return 0; return 0;
ts_secret_init(); ts_secret_init();

View File

@ -243,12 +243,12 @@ bool cookie_timestamp_decode(const struct net *net,
return true; return true;
} }
if (!net->ipv4.sysctl_tcp_timestamps) if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps))
return false; return false;
tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0; tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0;
if (tcp_opt->sack_ok && !net->ipv4.sysctl_tcp_sack) if (tcp_opt->sack_ok && !READ_ONCE(net->ipv4.sysctl_tcp_sack))
return false; return false;
if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK) if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK)
@ -257,7 +257,7 @@ bool cookie_timestamp_decode(const struct net *net,
tcp_opt->wscale_ok = 1; tcp_opt->wscale_ok = 1;
tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK; tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK;
return net->ipv4.sysctl_tcp_window_scaling != 0; return READ_ONCE(net->ipv4.sysctl_tcp_window_scaling) != 0;
} }
EXPORT_SYMBOL(cookie_timestamp_decode); EXPORT_SYMBOL(cookie_timestamp_decode);

View File

@ -3906,7 +3906,7 @@ void tcp_parse_options(const struct net *net,
break; break;
case TCPOPT_WINDOW: case TCPOPT_WINDOW:
if (opsize == TCPOLEN_WINDOW && th->syn && if (opsize == TCPOLEN_WINDOW && th->syn &&
!estab && net->ipv4.sysctl_tcp_window_scaling) { !estab && READ_ONCE(net->ipv4.sysctl_tcp_window_scaling)) {
__u8 snd_wscale = *(__u8 *)ptr; __u8 snd_wscale = *(__u8 *)ptr;
opt_rx->wscale_ok = 1; opt_rx->wscale_ok = 1;
if (snd_wscale > TCP_MAX_WSCALE) { if (snd_wscale > TCP_MAX_WSCALE) {
@ -3922,7 +3922,7 @@ void tcp_parse_options(const struct net *net,
case TCPOPT_TIMESTAMP: case TCPOPT_TIMESTAMP:
if ((opsize == TCPOLEN_TIMESTAMP) && if ((opsize == TCPOLEN_TIMESTAMP) &&
((estab && opt_rx->tstamp_ok) || ((estab && opt_rx->tstamp_ok) ||
(!estab && net->ipv4.sysctl_tcp_timestamps))) { (!estab && READ_ONCE(net->ipv4.sysctl_tcp_timestamps)))) {
opt_rx->saw_tstamp = 1; opt_rx->saw_tstamp = 1;
opt_rx->rcv_tsval = get_unaligned_be32(ptr); opt_rx->rcv_tsval = get_unaligned_be32(ptr);
opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4); opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
@ -3930,7 +3930,7 @@ void tcp_parse_options(const struct net *net,
break; break;
case TCPOPT_SACK_PERM: case TCPOPT_SACK_PERM:
if (opsize == TCPOLEN_SACK_PERM && th->syn && if (opsize == TCPOLEN_SACK_PERM && th->syn &&
!estab && net->ipv4.sysctl_tcp_sack) { !estab && READ_ONCE(net->ipv4.sysctl_tcp_sack)) {
opt_rx->sack_ok = TCP_SACK_SEEN; opt_rx->sack_ok = TCP_SACK_SEEN;
tcp_sack_reset(opt_rx); tcp_sack_reset(opt_rx);
} }

View File

@ -620,18 +620,18 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
opts->mss = tcp_advertise_mss(sk); opts->mss = tcp_advertise_mss(sk);
remaining -= TCPOLEN_MSS_ALIGNED; remaining -= TCPOLEN_MSS_ALIGNED;
if (likely(sock_net(sk)->ipv4.sysctl_tcp_timestamps && !*md5)) { if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps) && !*md5)) {
opts->options |= OPTION_TS; opts->options |= OPTION_TS;
opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset; opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
opts->tsecr = tp->rx_opt.ts_recent; opts->tsecr = tp->rx_opt.ts_recent;
remaining -= TCPOLEN_TSTAMP_ALIGNED; remaining -= TCPOLEN_TSTAMP_ALIGNED;
} }
if (likely(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) { if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling))) {
opts->ws = tp->rx_opt.rcv_wscale; opts->ws = tp->rx_opt.rcv_wscale;
opts->options |= OPTION_WSCALE; opts->options |= OPTION_WSCALE;
remaining -= TCPOLEN_WSCALE_ALIGNED; remaining -= TCPOLEN_WSCALE_ALIGNED;
} }
if (likely(sock_net(sk)->ipv4.sysctl_tcp_sack)) { if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_sack))) {
opts->options |= OPTION_SACK_ADVERTISE; opts->options |= OPTION_SACK_ADVERTISE;
if (unlikely(!(OPTION_TS & opts->options))) if (unlikely(!(OPTION_TS & opts->options)))
remaining -= TCPOLEN_SACKPERM_ALIGNED; remaining -= TCPOLEN_SACKPERM_ALIGNED;
@ -3407,7 +3407,7 @@ static void tcp_connect_init(struct sock *sk)
* See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
*/ */
tp->tcp_header_len = sizeof(struct tcphdr); tp->tcp_header_len = sizeof(struct tcphdr);
if (sock_net(sk)->ipv4.sysctl_tcp_timestamps) if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps))
tp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED; tp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED;
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
@ -3443,7 +3443,7 @@ static void tcp_connect_init(struct sock *sk)
tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
&tp->rcv_wnd, &tp->rcv_wnd,
&tp->window_clamp, &tp->window_clamp,
sock_net(sk)->ipv4.sysctl_tcp_window_scaling, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling),
&rcv_wscale, &rcv_wscale,
rcv_wnd); rcv_wnd);