Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 795aee11 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Greg Kroah-Hartman
Browse files

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: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent f39b03bd
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1103,8 +1103,8 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
	csk->sndbuf = newsk->sk_sndbuf;
	csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx;
	RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
					   sock_net(newsk)->
						ipv4.sysctl_tcp_window_scaling,
					   READ_ONCE(sock_net(newsk)->
						     ipv4.sysctl_tcp_window_scaling),
					   tp->window_clamp);
	neigh_release(n);
	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);
	ip_dsfield = ipv4_get_dsfield(iph);
	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)->snd_wscale = req->tcpopt.wsf;
	}
+2 −2
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ u32 secure_tcpv6_ts_off(const struct net *net,
		.daddr = *(struct in6_addr *)daddr,
	};

	if (net->ipv4.sysctl_tcp_timestamps != 1)
	if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
		return 0;

	ts_secret_init();
@@ -121,7 +121,7 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#ifdef CONFIG_INET
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;

	ts_secret_init();
+3 −3
Original line number Diff line number Diff line
@@ -243,12 +243,12 @@ bool cookie_timestamp_decode(const struct net *net,
		return true;
	}

	if (!net->ipv4.sysctl_tcp_timestamps)
	if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps))
		return false;

	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;

	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->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);

+3 −3
Original line number Diff line number Diff line
@@ -3906,7 +3906,7 @@ void tcp_parse_options(const struct net *net,
				break;
			case TCPOPT_WINDOW:
				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;
					opt_rx->wscale_ok = 1;
					if (snd_wscale > TCP_MAX_WSCALE) {
@@ -3922,7 +3922,7 @@ void tcp_parse_options(const struct net *net,
			case TCPOPT_TIMESTAMP:
				if ((opsize == TCPOLEN_TIMESTAMP) &&
				    ((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->rcv_tsval = get_unaligned_be32(ptr);
					opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
@@ -3930,7 +3930,7 @@ void tcp_parse_options(const struct net *net,
				break;
			case TCPOPT_SACK_PERM:
				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;
					tcp_sack_reset(opt_rx);
				}
+5 −5
Original line number Diff line number Diff line
@@ -620,18 +620,18 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
	opts->mss = tcp_advertise_mss(sk);
	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->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
		opts->tsecr = tp->rx_opt.ts_recent;
		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->options |= OPTION_WSCALE;
		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;
		if (unlikely(!(OPTION_TS & opts->options)))
			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.
	 */
	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;

#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->rcv_wnd,
				  &tp->window_clamp,
				  sock_net(sk)->ipv4.sysctl_tcp_window_scaling,
				  READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling),
				  &rcv_wscale,
				  rcv_wnd);