diff options
author | Jason Wang <jasowang@redhat.com> | 2013-12-09 05:25:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-10 22:06:49 -0500 |
commit | 730054da3868c35809fd31a4018044ab10b0e215 (patch) | |
tree | 7b83e6854b19f4204e8785977f97ac3ff51df03a | |
parent | 923347bb83c67c3a572b04decb5875c3adb0d306 (diff) |
macvtap: signal truncated packets
macvtap_put_user() never return a value grater than iov length, this in fact
bypasses the truncated checking in macvtap_recvmsg(). Fix this by always
returning the size of packet plus the possible vlan header to let the truncated
checking work.
Cc: Vlad Yasevich <vyasevich@gmail.com>
Cc: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/macvtap.c | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 957cc5c3653d..7544a0c686b4 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -767,10 +767,14 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
767 | const struct sk_buff *skb, | 767 | const struct sk_buff *skb, |
768 | const struct iovec *iv, int len) | 768 | const struct iovec *iv, int len) |
769 | { | 769 | { |
770 | int ret; | 770 | int ret, off; |
771 | int vnet_hdr_len = 0; | 771 | int vnet_hdr_len = 0; |
772 | int vlan_offset = 0; | 772 | int vlan_offset = 0; |
773 | int copied; | 773 | int copied; |
774 | struct { | ||
775 | __be16 h_vlan_proto; | ||
776 | __be16 h_vlan_TCI; | ||
777 | } veth; | ||
774 | 778 | ||
775 | if (q->flags & IFF_VNET_HDR) { | 779 | if (q->flags & IFF_VNET_HDR) { |
776 | struct virtio_net_hdr vnet_hdr; | 780 | struct virtio_net_hdr vnet_hdr; |
@@ -785,16 +789,13 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
785 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) | 789 | if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) |
786 | return -EFAULT; | 790 | return -EFAULT; |
787 | } | 791 | } |
788 | copied = vnet_hdr_len; | 792 | off = copied = vnet_hdr_len; |
789 | 793 | ||
790 | if (!vlan_tx_tag_present(skb)) | 794 | if (!vlan_tx_tag_present(skb)) |
791 | len = min_t(int, skb->len, len); | 795 | len = min_t(int, skb->len, len); |
792 | else { | 796 | else { |
793 | int copy; | 797 | int copy; |
794 | struct { | 798 | |
795 | __be16 h_vlan_proto; | ||
796 | __be16 h_vlan_TCI; | ||
797 | } veth; | ||
798 | veth.h_vlan_proto = skb->vlan_proto; | 799 | veth.h_vlan_proto = skb->vlan_proto; |
799 | veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); | 800 | veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); |
800 | 801 | ||
@@ -802,22 +803,22 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, | |||
802 | len = min_t(int, skb->len + VLAN_HLEN, len); | 803 | len = min_t(int, skb->len + VLAN_HLEN, len); |
803 | 804 | ||
804 | copy = min_t(int, vlan_offset, len); | 805 | copy = min_t(int, vlan_offset, len); |
805 | ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); | 806 | ret = skb_copy_datagram_const_iovec(skb, 0, iv, off, copy); |
806 | len -= copy; | 807 | len -= copy; |
807 | copied += copy; | 808 | off += copy; |
808 | if (ret || !len) | 809 | if (ret || !len) |
809 | goto done; | 810 | goto done; |
810 | 811 | ||
811 | copy = min_t(int, sizeof(veth), len); | 812 | copy = min_t(int, sizeof(veth), len); |
812 | ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); | 813 | ret = memcpy_toiovecend(iv, (void *)&veth, off, copy); |
813 | len -= copy; | 814 | len -= copy; |
814 | copied += copy; | 815 | off += copy; |
815 | if (ret || !len) | 816 | if (ret || !len) |
816 | goto done; | 817 | goto done; |
817 | } | 818 | } |
818 | 819 | ||
819 | ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); | 820 | ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, off, len); |
820 | copied += len; | 821 | copied += skb->len + (vlan_offset ? sizeof(veth) : 0); |
821 | 822 | ||
822 | done: | 823 | done: |
823 | return ret ? ret : copied; | 824 | return ret ? ret : copied; |
@@ -875,7 +876,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
875 | } | 876 | } |
876 | 877 | ||
877 | ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK); | 878 | ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK); |
878 | ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */ | 879 | ret = min_t(ssize_t, ret, len); |
879 | if (ret > 0) | 880 | if (ret > 0) |
880 | iocb->ki_pos = ret; | 881 | iocb->ki_pos = ret; |
881 | out: | 882 | out: |