diff options
author | Paolo Abeni <pabeni@redhat.com> | 2024-06-27 12:05:04 +0200 |
---|---|---|
committer | Paolo Abeni <pabeni@redhat.com> | 2024-06-27 12:05:05 +0200 |
commit | 3f4d9e4f825c617c711f5e1da3059238722f08c1 (patch) | |
tree | 6bc49b2afe71a1a032b3443ad01df4a88b4fcd75 /net/unix/af_unix.c | |
parent | bab4923132feb3e439ae45962979c5d9d5c7c1f1 (diff) | |
parent | 91b7186c8d141fb89412930d6b9974c9cba24af7 (diff) | |
download | linux-3f4d9e4f825c617c711f5e1da3059238722f08c1.tar.gz linux-3f4d9e4f825c617c711f5e1da3059238722f08c1.tar.bz2 linux-3f4d9e4f825c617c711f5e1da3059238722f08c1.zip |
Merge branch 'af_unix-fix-bunch-of-msg_oob-bugs-and-add-new-tests'
Kuniyuki Iwashima says:
====================
af_unix: Fix bunch of MSG_OOB bugs and add new tests.
This series rewrites the selftest for AF_UNIX MSG_OOB and fixes
bunch of bugs that AF_UNIX behaves differently compared to TCP.
Note that the test discovered few more bugs in TCP side, which
will be fixed in another series.
====================
Link: https://lore.kernel.org/r/20240625013645.45034-1-kuniyu@amazon.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 5e695a9a609c..142f56770b77 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2613,10 +2613,24 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, { struct unix_sock *u = unix_sk(sk); - if (!unix_skb_len(skb) && !(flags & MSG_PEEK)) { - skb_unlink(skb, &sk->sk_receive_queue); - consume_skb(skb); - skb = NULL; + if (!unix_skb_len(skb)) { + struct sk_buff *unlinked_skb = NULL; + + spin_lock(&sk->sk_receive_queue.lock); + + if (copied && (!u->oob_skb || skb == u->oob_skb)) { + skb = NULL; + } else if (flags & MSG_PEEK) { + skb = skb_peek_next(skb, &sk->sk_receive_queue); + } else { + unlinked_skb = skb; + skb = skb_peek_next(skb, &sk->sk_receive_queue); + __skb_unlink(unlinked_skb, &sk->sk_receive_queue); + } + + spin_unlock(&sk->sk_receive_queue.lock); + + consume_skb(unlinked_skb); } else { struct sk_buff *unlinked_skb = NULL; @@ -3093,12 +3107,23 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) #if IS_ENABLED(CONFIG_AF_UNIX_OOB) case SIOCATMARK: { + struct unix_sock *u = unix_sk(sk); struct sk_buff *skb; int answ = 0; + mutex_lock(&u->iolock); + skb = skb_peek(&sk->sk_receive_queue); - if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) - answ = 1; + if (skb) { + struct sk_buff *oob_skb = READ_ONCE(u->oob_skb); + + if (skb == oob_skb || + (!oob_skb && !unix_skb_len(skb))) + answ = 1; + } + + mutex_unlock(&u->iolock); + err = put_user(answ, (int __user *)arg); } break; |