summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRao Shoaib <rao.shoaib@oracle.com>2021-08-11 15:06:52 -0700
committerJakub Kicinski <kuba@kernel.org>2021-08-13 10:31:22 -0700
commit876c14ad014d0e39c57cbfde53e13d17cdb6d645 (patch)
treec72a0c3ee480651fe307963daf488c277735aa95 /net
parentf4083a752a3b7dc2076432129c8469d02c25318e (diff)
downloadlinux-876c14ad014d0e39c57cbfde53e13d17cdb6d645.tar.bz2
af_unix: fix holding spinlock in oob handling
syzkaller found that OOB code was holding spinlock while calling a function in which it could sleep. Reported-by: syzbot+8760ca6c1ee783ac4abd@syzkaller.appspotmail.com Fixes: 314001f0bf92 ("af_unix: Add OOB support") Signed-off-by: Rao Shoaib <rao.shoaib@oracle.com> Link: https://lore.kernel.org/r/20210811220652.567434-1-Rao.Shoaib@oracle.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/unix/af_unix.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ec02e70a549b..1c2224f05b51 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2426,19 +2426,37 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
struct sock *sk = sock->sk;
struct unix_sock *u = unix_sk(sk);
int chunk = 1;
+ struct sk_buff *oob_skb;
- if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb)
+ mutex_lock(&u->iolock);
+ unix_state_lock(sk);
+
+ if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb) {
+ unix_state_unlock(sk);
+ mutex_unlock(&u->iolock);
return -EINVAL;
+ }
- chunk = state->recv_actor(u->oob_skb, 0, chunk, state);
- if (chunk < 0)
- return -EFAULT;
+ oob_skb = u->oob_skb;
if (!(state->flags & MSG_PEEK)) {
- UNIXCB(u->oob_skb).consumed += 1;
- kfree_skb(u->oob_skb);
u->oob_skb = NULL;
}
+
+ unix_state_unlock(sk);
+
+ chunk = state->recv_actor(oob_skb, 0, chunk, state);
+
+ if (!(state->flags & MSG_PEEK)) {
+ UNIXCB(oob_skb).consumed += 1;
+ kfree_skb(oob_skb);
+ }
+
+ mutex_unlock(&u->iolock);
+
+ if (chunk < 0)
+ return -EFAULT;
+
state->msg->msg_flags |= MSG_OOB;
return 1;
}
@@ -2498,13 +2516,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
if (unlikely(flags & MSG_OOB)) {
err = -EOPNOTSUPP;
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
- mutex_lock(&u->iolock);
- unix_state_lock(sk);
-
err = unix_stream_recv_urg(state);
-
- unix_state_unlock(sk);
- mutex_unlock(&u->iolock);
#endif
goto out;
}