mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	af_unix: Stop recv(MSG_PEEK) at consumed OOB skb.
After consuming OOB data, recv() reading the preceding data must break at
the OOB skb regardless of MSG_PEEK.
Currently, MSG_PEEK does not stop recv() for AF_UNIX, and the behaviour is
not compliant with TCP.
  >>> from socket import *
  >>> c1, c2 = socketpair(AF_UNIX)
  >>> c1.send(b'hello', MSG_OOB)
  5
  >>> c1.send(b'world')
  5
  >>> c2.recv(1, MSG_OOB)
  b'o'
  >>> c2.recv(9, MSG_PEEK)  # This should return b'hell'
  b'hellworld'              # even with enough buffer.
Let's fix it by returning NULL for consumed skb and unlinking it only if
MSG_PEEK is not specified.
This patch also adds test cases that add recv(MSG_PEEK) before each recv().
Without fix:
  #  RUN           msg_oob.peek.oob_ahead_break ...
  # msg_oob.c:134:oob_ahead_break:AF_UNIX :hellworld
  # msg_oob.c:135:oob_ahead_break:Expected:hell
  # msg_oob.c:137:oob_ahead_break:Expected ret[0] (9) == expected_len (4)
  # oob_ahead_break: Test terminated by assertion
  #          FAIL  msg_oob.peek.oob_ahead_break
  not ok 13 msg_oob.peek.oob_ahead_break
With fix:
  #  RUN           msg_oob.peek.oob_ahead_break ...
  #            OK  msg_oob.peek.oob_ahead_break
  ok 13 msg_oob.peek.oob_ahead_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
							
								
									d098d77232
								
							
						
					
					
						commit
						b94038d841
					
				
					 2 changed files with 29 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -2613,9 +2613,12 @@ 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);
 | 
			
		||||
	if (!unix_skb_len(skb)) {
 | 
			
		||||
		if (!(flags & MSG_PEEK)) {
 | 
			
		||||
			skb_unlink(skb, &sk->sk_receive_queue);
 | 
			
		||||
			consume_skb(skb);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		skb = NULL;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct sk_buff *unlinked_skb = NULL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,21 @@ FIXTURE(msg_oob)
 | 
			
		|||
				 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FIXTURE_VARIANT(msg_oob)
 | 
			
		||||
{
 | 
			
		||||
	bool peek;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FIXTURE_VARIANT_ADD(msg_oob, no_peek)
 | 
			
		||||
{
 | 
			
		||||
	.peek = false,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FIXTURE_VARIANT_ADD(msg_oob, peek)
 | 
			
		||||
{
 | 
			
		||||
	.peek = true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void create_unix_socketpair(struct __test_metadata *_metadata,
 | 
			
		||||
				   FIXTURE_DATA(msg_oob) *self)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -156,8 +171,14 @@ static void __recvpair(struct __test_metadata *_metadata,
 | 
			
		|||
	__sendpair(_metadata, self, buf, len, flags)
 | 
			
		||||
 | 
			
		||||
#define recvpair(expected_buf, expected_len, buf_len, flags)		\
 | 
			
		||||
	__recvpair(_metadata, self,					\
 | 
			
		||||
		   expected_buf, expected_len, buf_len, flags)
 | 
			
		||||
	do {								\
 | 
			
		||||
		if (variant->peek)					\
 | 
			
		||||
			__recvpair(_metadata, self,			\
 | 
			
		||||
				   expected_buf, expected_len,		\
 | 
			
		||||
				   buf_len, (flags) | MSG_PEEK);	\
 | 
			
		||||
		__recvpair(_metadata, self,				\
 | 
			
		||||
			   expected_buf, expected_len, buf_len, flags);	\
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
TEST_F(msg_oob, non_oob)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue