8fd61b3
From 9f30f83eb6347afa6b1d1df1065608c2b4485e2b Mon Sep 17 00:00:00 2001
8fd61b3
From: Eric Dumazet <edumazet@google.com>
8fd61b3
Date: Tue, 23 Aug 2016 13:59:33 -0700
8fd61b3
Subject: [PATCH] udp: fix poll() issue with zero sized packets
8fd61b3
8fd61b3
Laura tracked poll() [and friends] regression caused by commit
8fd61b3
e6afc8ace6dd ("udp: remove headers from UDP packets before queueing")
8fd61b3
8fd61b3
udp_poll() needs to know if there is a valid packet in receive queue,
8fd61b3
even if its payload length is 0.
8fd61b3
8fd61b3
Change first_packet_length() to return an signed int, and use -1
8fd61b3
as the indication of an empty queue.
8fd61b3
8fd61b3
Fixes: e6afc8ace6dd ("udp: remove headers from UDP packets before queueing")
8fd61b3
Reported-by: Laura Abbott <labbott@redhat.com>
8fd61b3
Signed-off-by: Eric Dumazet <edumazet@google.com>
8fd61b3
Tested-by: Laura Abbott <labbott@redhat.com>
8fd61b3
---
8fd61b3
 net/ipv4/udp.c | 12 ++++++------
8fd61b3
 1 file changed, 6 insertions(+), 6 deletions(-)
8fd61b3
8fd61b3
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
8fd61b3
index e61f7cd..00d18c5 100644
8fd61b3
--- a/net/ipv4/udp.c
8fd61b3
+++ b/net/ipv4/udp.c
8fd61b3
@@ -1182,13 +1182,13 @@ out:
8fd61b3
  *	@sk: socket
8fd61b3
  *
8fd61b3
  *	Drops all bad checksum frames, until a valid one is found.
8fd61b3
- *	Returns the length of found skb, or 0 if none is found.
8fd61b3
+ *	Returns the length of found skb, or -1 if none is found.
8fd61b3
  */
8fd61b3
-static unsigned int first_packet_length(struct sock *sk)
8fd61b3
+static int first_packet_length(struct sock *sk)
8fd61b3
 {
8fd61b3
 	struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue;
8fd61b3
 	struct sk_buff *skb;
8fd61b3
-	unsigned int res;
8fd61b3
+	int res;
8fd61b3
 
8fd61b3
 	__skb_queue_head_init(&list_kill);
8fd61b3
 
8fd61b3
@@ -1203,7 +1203,7 @@ static unsigned int first_packet_length(struct sock *sk)
8fd61b3
 		__skb_unlink(skb, rcvq);
8fd61b3
 		__skb_queue_tail(&list_kill, skb);
8fd61b3
 	}
8fd61b3
-	res = skb ? skb->len : 0;
8fd61b3
+	res = skb ? skb->len : -1;
8fd61b3
 	spin_unlock_bh(&rcvq->lock);
8fd61b3
 
8fd61b3
 	if (!skb_queue_empty(&list_kill)) {
8fd61b3
@@ -1232,7 +1232,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
8fd61b3
 
8fd61b3
 	case SIOCINQ:
8fd61b3
 	{
8fd61b3
-		unsigned int amount = first_packet_length(sk);
8fd61b3
+		int amount = max_t(int, 0, first_packet_length(sk));
8fd61b3
 
8fd61b3
 		return put_user(amount, (int __user *)arg);
8fd61b3
 	}
8fd61b3
@@ -2184,7 +2184,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
8fd61b3
 
8fd61b3
 	/* Check for false positives due to checksum errors */
8fd61b3
 	if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) &&
8fd61b3
-	    !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk))
8fd61b3
+	    !(sk->sk_shutdown & RCV_SHUTDOWN) && first_packet_length(sk) == -1)
8fd61b3
 		mask &= ~(POLLIN | POLLRDNORM);
8fd61b3
 
8fd61b3
 	return mask;
8fd61b3
-- 
8fd61b3
2.7.4
8fd61b3