Merge tag 'net-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-block.git] / net / unix / af_unix.c
index d5f10783c251c5606a23effa750dcd4dcd16557f..e4af6616e1dff1da32772eddfdf645fb4c9fa45c 100644 (file)
@@ -2170,13 +2170,15 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
        maybe_add_creds(skb, sock, other);
        skb_get(skb);
 
+       scm_stat_add(other, skb);
+
+       spin_lock(&other->sk_receive_queue.lock);
        if (ousk->oob_skb)
                consume_skb(ousk->oob_skb);
-
        WRITE_ONCE(ousk->oob_skb, skb);
+       __skb_queue_tail(&other->sk_receive_queue, skb);
+       spin_unlock(&other->sk_receive_queue.lock);
 
-       scm_stat_add(other, skb);
-       skb_queue_tail(&other->sk_receive_queue, skb);
        sk_send_sigurg(other);
        unix_state_unlock(other);
        other->sk_data_ready(other);
@@ -2567,8 +2569,10 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
 
        mutex_lock(&u->iolock);
        unix_state_lock(sk);
+       spin_lock(&sk->sk_receive_queue.lock);
 
        if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb) {
+               spin_unlock(&sk->sk_receive_queue.lock);
                unix_state_unlock(sk);
                mutex_unlock(&u->iolock);
                return -EINVAL;
@@ -2580,6 +2584,8 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
                WRITE_ONCE(u->oob_skb, NULL);
        else
                skb_get(oob_skb);
+
+       spin_unlock(&sk->sk_receive_queue.lock);
        unix_state_unlock(sk);
 
        chunk = state->recv_actor(oob_skb, 0, chunk, state);
@@ -2608,6 +2614,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
                consume_skb(skb);
                skb = NULL;
        } else {
+               struct sk_buff *unlinked_skb = NULL;
+
+               spin_lock(&sk->sk_receive_queue.lock);
+
                if (skb == u->oob_skb) {
                        if (copied) {
                                skb = NULL;
@@ -2619,13 +2629,19 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
                        } else if (flags & MSG_PEEK) {
                                skb = NULL;
                        } else {
-                               skb_unlink(skb, &sk->sk_receive_queue);
+                               __skb_unlink(skb, &sk->sk_receive_queue);
                                WRITE_ONCE(u->oob_skb, NULL);
-                               if (!WARN_ON_ONCE(skb_unref(skb)))
-                                       kfree_skb(skb);
+                               unlinked_skb = skb;
                                skb = skb_peek(&sk->sk_receive_queue);
                        }
                }
+
+               spin_unlock(&sk->sk_receive_queue.lock);
+
+               if (unlinked_skb) {
+                       WARN_ON_ONCE(skb_unref(unlinked_skb));
+                       kfree_skb(unlinked_skb);
+               }
        }
        return skb;
 }