diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-10-09 00:43:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-13 06:16:54 -0400 |
commit | 85584672012ee0c3b7b8e033a1ecf7c11878e45f (patch) | |
tree | f35b38f084453e2d7260d4a7a8d13f2a01641664 /net/ipv4 | |
parent | 9652041da18a1a1d9a0b7ebd9eef16bd712be38a (diff) |
udp: Fix udp_poll() and ioctl()
udp_poll() can in some circumstances drop frames with incorrect checksums.
Problem is we now have to lock the socket while dropping frames, or risk
sk_forward corruption.
This bug is present since commit 95766fff6b9a78d1
([UDP]: Add memory accounting.)
While we are at it, we can correct ioctl(SIOCINQ) to also drop bad frames.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/udp.c | 73 |
1 files changed, 43 insertions, 30 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6ec6a8a4a224..d0d436d6216c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -841,6 +841,42 @@ out: | |||
841 | return ret; | 841 | return ret; |
842 | } | 842 | } |
843 | 843 | ||
844 | |||
845 | /** | ||
846 | * first_packet_length - return length of first packet in receive queue | ||
847 | * @sk: socket | ||
848 | * | ||
849 | * Drops all bad checksum frames, until a valid one is found. | ||
850 | * Returns the length of found skb, or 0 if none is found. | ||
851 | */ | ||
852 | static unsigned int first_packet_length(struct sock *sk) | ||
853 | { | ||
854 | struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue; | ||
855 | struct sk_buff *skb; | ||
856 | unsigned int res; | ||
857 | |||
858 | __skb_queue_head_init(&list_kill); | ||
859 | |||
860 | spin_lock_bh(&rcvq->lock); | ||
861 | while ((skb = skb_peek(rcvq)) != NULL && | ||
862 | udp_lib_checksum_complete(skb)) { | ||
863 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, | ||
864 | IS_UDPLITE(sk)); | ||
865 | __skb_unlink(skb, rcvq); | ||
866 | __skb_queue_tail(&list_kill, skb); | ||
867 | } | ||
868 | res = skb ? skb->len : 0; | ||
869 | spin_unlock_bh(&rcvq->lock); | ||
870 | |||
871 | if (!skb_queue_empty(&list_kill)) { | ||
872 | lock_sock(sk); | ||
873 | __skb_queue_purge(&list_kill); | ||
874 | sk_mem_reclaim_partial(sk); | ||
875 | release_sock(sk); | ||
876 | } | ||
877 | return res; | ||
878 | } | ||
879 | |||
844 | /* | 880 | /* |
845 | * IOCTL requests applicable to the UDP protocol | 881 | * IOCTL requests applicable to the UDP protocol |
846 | */ | 882 | */ |
@@ -857,21 +893,16 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
857 | 893 | ||
858 | case SIOCINQ: | 894 | case SIOCINQ: |
859 | { | 895 | { |
860 | struct sk_buff *skb; | 896 | unsigned int amount = first_packet_length(sk); |
861 | unsigned long amount; | ||
862 | 897 | ||
863 | amount = 0; | 898 | if (amount) |
864 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
865 | skb = skb_peek(&sk->sk_receive_queue); | ||
866 | if (skb != NULL) { | ||
867 | /* | 899 | /* |
868 | * We will only return the amount | 900 | * We will only return the amount |
869 | * of this packet since that is all | 901 | * of this packet since that is all |
870 | * that will be read. | 902 | * that will be read. |
871 | */ | 903 | */ |
872 | amount = skb->len - sizeof(struct udphdr); | 904 | amount -= sizeof(struct udphdr); |
873 | } | 905 | |
874 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
875 | return put_user(amount, (int __user *)arg); | 906 | return put_user(amount, (int __user *)arg); |
876 | } | 907 | } |
877 | 908 | ||
@@ -1540,29 +1571,11 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1540 | { | 1571 | { |
1541 | unsigned int mask = datagram_poll(file, sock, wait); | 1572 | unsigned int mask = datagram_poll(file, sock, wait); |
1542 | struct sock *sk = sock->sk; | 1573 | struct sock *sk = sock->sk; |
1543 | int is_lite = IS_UDPLITE(sk); | ||
1544 | 1574 | ||
1545 | /* Check for false positives due to checksum errors */ | 1575 | /* Check for false positives due to checksum errors */ |
1546 | if ((mask & POLLRDNORM) && | 1576 | if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && |
1547 | !(file->f_flags & O_NONBLOCK) && | 1577 | !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk)) |
1548 | !(sk->sk_shutdown & RCV_SHUTDOWN)) { | 1578 | mask &= ~(POLLIN | POLLRDNORM); |
1549 | struct sk_buff_head *rcvq = &sk->sk_receive_queue; | ||
1550 | struct sk_buff *skb; | ||
1551 | |||
1552 | spin_lock_bh(&rcvq->lock); | ||
1553 | while ((skb = skb_peek(rcvq)) != NULL && | ||
1554 | udp_lib_checksum_complete(skb)) { | ||
1555 | UDP_INC_STATS_BH(sock_net(sk), | ||
1556 | UDP_MIB_INERRORS, is_lite); | ||
1557 | __skb_unlink(skb, rcvq); | ||
1558 | kfree_skb(skb); | ||
1559 | } | ||
1560 | spin_unlock_bh(&rcvq->lock); | ||
1561 | |||
1562 | /* nothing to see, move along */ | ||
1563 | if (skb == NULL) | ||
1564 | mask &= ~(POLLIN | POLLRDNORM); | ||
1565 | } | ||
1566 | 1579 | ||
1567 | return mask; | 1580 | return mask; |
1568 | 1581 | ||