aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-12-09 05:25:17 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-10 22:06:49 -0500
commit730054da3868c35809fd31a4018044ab10b0e215 (patch)
tree7b83e6854b19f4204e8785977f97ac3ff51df03a
parent923347bb83c67c3a572b04decb5875c3adb0d306 (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.c27
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
822done: 823done:
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;
881out: 882out: