diff options
| author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2024-07-05 10:35:14 +0200 | 
|---|---|---|
| committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2024-07-05 10:47:28 +0200 | 
| commit | 86634fa4e6aeff2e190616c304156899beb4d76b (patch) | |
| tree | d63fd0480e4ad11b9bdf6b653a63464429a63360 /net/unix/af_unix.c | |
| parent | 27aec396c48c6407a7586a35d79ac3fe387f2054 (diff) | |
| parent | 22a40d14b572deb80c0648557f4bd502d7e83826 (diff) | |
Merge v6.10-rc6 into drm-next
The exynos-next pull is based on a newer -rc than drm-next. hence
backmerge first to make sure the unrelated conflicts we accumulated
don't end up randomly in the exynos merge pull, but are separated out.
Conflicts are all benign: Adjacent changes in amdgpu and fbdev-dma
code, and cherry-pick conflict in xe.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 55 | 
1 files changed, 40 insertions, 15 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 80846279de9f..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; @@ -2625,18 +2639,18 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,  		if (skb == u->oob_skb) {  			if (copied) {  				skb = NULL; -			} else if (sock_flag(sk, SOCK_URGINLINE)) { -				if (!(flags & MSG_PEEK)) { +			} else if (!(flags & MSG_PEEK)) { +				if (sock_flag(sk, SOCK_URGINLINE)) {  					WRITE_ONCE(u->oob_skb, NULL);  					consume_skb(skb); +				} else { +					__skb_unlink(skb, &sk->sk_receive_queue); +					WRITE_ONCE(u->oob_skb, NULL); +					unlinked_skb = skb; +					skb = skb_peek(&sk->sk_receive_queue);  				} -			} else if (flags & MSG_PEEK) { -				skb = NULL; -			} else { -				__skb_unlink(skb, &sk->sk_receive_queue); -				WRITE_ONCE(u->oob_skb, NULL); -				unlinked_skb = skb; -				skb = skb_peek(&sk->sk_receive_queue); +			} else if (!sock_flag(sk, SOCK_URGINLINE)) { +				skb = skb_peek_next(skb, &sk->sk_receive_queue);  			}  		} @@ -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;  | 
