Commit bc1fb82a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

net: annotate data-races around sk->sk_lingertime



sk_getsockopt() runs locklessly. This means sk->sk_lingertime
can be read while other threads are changing its value.

Other reads also happen without socket lock being held,
and must be annotated.

Remove preprocessor logic using BITS_PER_LONG, compilers
are smart enough to figure this by themselves.

v2: fixed a clang W=1 (-Wtautological-constant-out-of-range-compare) warning
    (Jakub)

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b4672c73
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -1475,7 +1475,7 @@ static int iso_sock_release(struct socket *sock)


	iso_sock_close(sk);
	iso_sock_close(sk);


	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
	if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
	    !(current->flags & PF_EXITING)) {
	    !(current->flags & PF_EXITING)) {
		lock_sock(sk);
		lock_sock(sk);
		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+1 −1
Original line number Original line Diff line number Diff line
@@ -1245,7 +1245,7 @@ static int sco_sock_release(struct socket *sock)


	sco_sock_close(sk);
	sco_sock_close(sk);


	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
	if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
	    !(current->flags & PF_EXITING)) {
	    !(current->flags & PF_EXITING)) {
		lock_sock(sk);
		lock_sock(sk);
		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+9 −9
Original line number Original line Diff line number Diff line
@@ -797,7 +797,7 @@ EXPORT_SYMBOL(sock_set_reuseport);
void sock_no_linger(struct sock *sk)
void sock_no_linger(struct sock *sk)
{
{
	lock_sock(sk);
	lock_sock(sk);
	sk->sk_lingertime = 0;
	WRITE_ONCE(sk->sk_lingertime, 0);
	sock_set_flag(sk, SOCK_LINGER);
	sock_set_flag(sk, SOCK_LINGER);
	release_sock(sk);
	release_sock(sk);
}
}
@@ -1230,15 +1230,15 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
			ret = -EFAULT;
			ret = -EFAULT;
			break;
			break;
		}
		}
		if (!ling.l_onoff)
		if (!ling.l_onoff) {
			sock_reset_flag(sk, SOCK_LINGER);
			sock_reset_flag(sk, SOCK_LINGER);
		else {
		} else {
#if (BITS_PER_LONG == 32)
			unsigned long t_sec = ling.l_linger;
			if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)

				sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
			if (t_sec >= MAX_SCHEDULE_TIMEOUT / HZ)
				WRITE_ONCE(sk->sk_lingertime, MAX_SCHEDULE_TIMEOUT);
			else
			else
#endif
				WRITE_ONCE(sk->sk_lingertime, t_sec * HZ);
				sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
			sock_set_flag(sk, SOCK_LINGER);
			sock_set_flag(sk, SOCK_LINGER);
		}
		}
		break;
		break;
@@ -1692,7 +1692,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
	case SO_LINGER:
	case SO_LINGER:
		lv		= sizeof(v.ling);
		lv		= sizeof(v.ling);
		v.ling.l_onoff	= sock_flag(sk, SOCK_LINGER);
		v.ling.l_onoff	= sock_flag(sk, SOCK_LINGER);
		v.ling.l_linger	= sk->sk_lingertime / HZ;
		v.ling.l_linger	= READ_ONCE(sk->sk_lingertime) / HZ;
		break;
		break;


	case SO_BSDCOMPAT:
	case SO_BSDCOMPAT:
+1 −1
Original line number Original line Diff line number Diff line
@@ -502,7 +502,7 @@ META_COLLECTOR(int_sk_lingertime)
		*err = -1;
		*err = -1;
		return;
		return;
	}
	}
	dst->value = sk->sk_lingertime / HZ;
	dst->value = READ_ONCE(sk->sk_lingertime) / HZ;
}
}


META_COLLECTOR(int_sk_err_qlen)
META_COLLECTOR(int_sk_err_qlen)
+1 −1
Original line number Original line Diff line number Diff line
@@ -1840,7 +1840,7 @@ void smc_close_non_accepted(struct sock *sk)
	lock_sock(sk);
	lock_sock(sk);
	if (!sk->sk_lingertime)
	if (!sk->sk_lingertime)
		/* wait for peer closing */
		/* wait for peer closing */
		sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT;
		WRITE_ONCE(sk->sk_lingertime, SMC_MAX_STREAM_WAIT_TIMEOUT);
	__smc_release(smc);
	__smc_release(smc);
	release_sock(sk);
	release_sock(sk);
	sock_put(sk); /* sock_hold above */
	sock_put(sk); /* sock_hold above */