mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	af_unix: Don't stop recv(MSG_DONTWAIT) if consumed OOB skb is at the head.
Let's say a socket send()s "hello" with MSG_OOB and "world" without flags,
  >>> from socket import *
  >>> c1, c2 = socketpair(AF_UNIX)
  >>> c1.send(b'hello', MSG_OOB)
  5
  >>> c1.send(b'world')
  5
and its peer recv()s "hell" and "o".
  >>> c2.recv(10)
  b'hell'
  >>> c2.recv(1, MSG_OOB)
  b'o'
Now the consumed OOB skb stays at the head of recvq to return a correct
value for ioctl(SIOCATMARK), which is broken now and fixed by a later
patch.
Then, if peer issues recv() with MSG_DONTWAIT, manage_oob() returns NULL,
so recv() ends up with -EAGAIN.
  >>> c2.setblocking(False)  # This causes -EAGAIN even with available data
  >>> c2.recv(5)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  BlockingIOError: [Errno 11] Resource temporarily unavailable
However, next recv() will return the following available data, "world".
  >>> c2.recv(5)
  b'world'
When the consumed OOB skb is at the head of the queue, we need to fetch
the next skb to fix the weird behaviour.
Note that the issue does not happen without MSG_DONTWAIT because we can
retry after manage_oob().
This patch also adds a test case that covers the issue.
Without fix:
  #  RUN           msg_oob.no_peek.ex_oob_break ...
  # msg_oob.c:134:ex_oob_break:AF_UNIX :Resource temporarily unavailable
  # msg_oob.c:135:ex_oob_break:Expected:ld
  # msg_oob.c:137:ex_oob_break:Expected ret[0] (-1) == expected_len (2)
  # ex_oob_break: Test terminated by assertion
  #          FAIL  msg_oob.no_peek.ex_oob_break
  not ok 8 msg_oob.no_peek.ex_oob_break
With fix:
  #  RUN           msg_oob.no_peek.ex_oob_break ...
  #            OK  msg_oob.no_peek.ex_oob_break
  ok 8 msg_oob.no_peek.ex_oob_break
Fixes: 314001f0bf ("af_unix: Add OOB support")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									b94038d841
								
							
						
					
					
						commit
						93c99f21db
					
				
					 2 changed files with 26 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -2614,12 +2614,23 @@ 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)) {
 | 
			
		||||
		if (!(flags & MSG_PEEK)) {
 | 
			
		||||
			skb_unlink(skb, &sk->sk_receive_queue);
 | 
			
		||||
			consume_skb(skb);
 | 
			
		||||
		struct sk_buff *unlinked_skb = NULL;
 | 
			
		||||
 | 
			
		||||
		spin_lock(&sk->sk_receive_queue.lock);
 | 
			
		||||
 | 
			
		||||
		if (copied) {
 | 
			
		||||
			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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		skb = NULL;
 | 
			
		||||
		spin_unlock(&sk->sk_receive_queue.lock);
 | 
			
		||||
 | 
			
		||||
		consume_skb(unlinked_skb);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct sk_buff *unlinked_skb = NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -238,4 +238,15 @@ TEST_F(msg_oob, oob_break_drop)
 | 
			
		|||
	recvpair("", -EINVAL, 1, MSG_OOB);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(msg_oob, ex_oob_break)
 | 
			
		||||
{
 | 
			
		||||
	sendpair("hello", 5, MSG_OOB);
 | 
			
		||||
	sendpair("wor", 3, MSG_OOB);
 | 
			
		||||
	sendpair("ld", 2, 0);
 | 
			
		||||
 | 
			
		||||
	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */
 | 
			
		||||
	recvpair("r", 1, 1, MSG_OOB);
 | 
			
		||||
	recvpair("ld", 2, 2, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_HARNESS_MAIN
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue