mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-03 19:55:31 +00:00
af_unix: Annotate data-race of sk->sk_state in unix_inq_len().
ioctl(SIOCINQ) calls unix_inq_len() that checks sk->sk_state first
and returns -EINVAL if it's TCP_LISTEN.
Then, for SOCK_STREAM sockets, unix_inq_len() returns the number of
bytes in recvq.
However, unix_inq_len() does not hold unix_state_lock(), and the
concurrent listen() might change the state after checking sk->sk_state.
If the race occurs, 0 is returned for the listener, instead of -EINVAL,
because the length of skb with embryo is 0.
We could hold unix_state_lock() in unix_inq_len(), but it's overkill
given the result is true for pre-listen() TCP_CLOSE state.
So, let's use READ_ONCE() for sk->sk_state in unix_inq_len().
Fixes: 1da177e4c3
("Linux-2.6.12-rc2")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
942238f973
commit
3a0f38eb28
@ -3017,7 +3017,7 @@ long unix_inq_len(struct sock *sk)
|
||||
struct sk_buff *skb;
|
||||
long amount = 0;
|
||||
|
||||
if (sk->sk_state == TCP_LISTEN)
|
||||
if (READ_ONCE(sk->sk_state) == TCP_LISTEN)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&sk->sk_receive_queue.lock);
|
||||
|
Loading…
Reference in New Issue
Block a user