aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-11-24 12:10:46 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-12-09 16:28:21 -0500
commit19e3c66b52caf20a9a1119dc847b6abae4c03f4f (patch)
treeb27bdfce9a7e37c2ea1eee2a69b107112c26779a /net/ipv6
parentb61e9dcc5e77d534fa770a02877fd45f51d4e7f4 (diff)
ipv6 equivalent of "ipv4: Avoid reading user iov twice after raw_probe_proto_opt"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/raw.c112
1 files changed, 56 insertions, 56 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 8baa53e17a30..942f67b91274 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -672,65 +672,62 @@ error:
672 return err; 672 return err;
673} 673}
674 674
675static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg) 675struct raw6_frag_vec {
676 struct msghdr *msg;
677 int hlen;
678 char c[4];
679};
680
681static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
676{ 682{
677 struct iovec *iov; 683 int err = 0;
678 u8 __user *type = NULL; 684 switch (fl6->flowi6_proto) {
679 u8 __user *code = NULL; 685 case IPPROTO_ICMPV6:
680 u8 len = 0; 686 rfv->hlen = 2;
681 int probed = 0; 687 err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
682 int i; 688 if (!err) {
683 689 fl6->fl6_icmp_type = rfv->c[0];
684 if (!msg->msg_iov) 690 fl6->fl6_icmp_code = rfv->c[1];
685 return 0; 691 }
692 break;
693 case IPPROTO_MH:
694 rfv->hlen = 4;
695 err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
696 if (!err)
697 fl6->fl6_mh_type = rfv->c[2];
698 }
699 return err;
700}
686 701
687 for (i = 0; i < msg->msg_iovlen; i++) { 702static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
688 iov = &msg->msg_iov[i]; 703 struct sk_buff *skb)
689 if (!iov) 704{
690 continue; 705 struct raw6_frag_vec *rfv = from;
691 706
692 switch (fl6->flowi6_proto) { 707 if (offset < rfv->hlen) {
693 case IPPROTO_ICMPV6: 708 int copy = min(rfv->hlen - offset, len);
694 /* check if one-byte field is readable or not. */
695 if (iov->iov_base && iov->iov_len < 1)
696 break;
697
698 if (!type) {
699 type = iov->iov_base;
700 /* check if code field is readable or not. */
701 if (iov->iov_len > 1)
702 code = type + 1;
703 } else if (!code)
704 code = iov->iov_base;
705
706 if (type && code) {
707 if (get_user(fl6->fl6_icmp_type, type) ||
708 get_user(fl6->fl6_icmp_code, code))
709 return -EFAULT;
710 probed = 1;
711 }
712 break;
713 case IPPROTO_MH:
714 if (iov->iov_base && iov->iov_len < 1)
715 break;
716 /* check if type field is readable or not. */
717 if (iov->iov_len > 2 - len) {
718 u8 __user *p = iov->iov_base;
719 if (get_user(fl6->fl6_mh_type, &p[2 - len]))
720 return -EFAULT;
721 probed = 1;
722 } else
723 len += iov->iov_len;
724 709
725 break; 710 if (skb->ip_summed == CHECKSUM_PARTIAL)
726 default: 711 memcpy(to, rfv->c + offset, copy);
727 probed = 1; 712 else
728 break; 713 skb->csum = csum_block_add(
729 } 714 skb->csum,
730 if (probed) 715 csum_partial_copy_nocheck(rfv->c + offset,
731 break; 716 to, copy, 0),
717 odd);
718
719 odd = 0;
720 offset += copy;
721 to += copy;
722 len -= copy;
723
724 if (!len)
725 return 0;
732 } 726 }
733 return 0; 727
728 offset -= rfv->hlen;
729
730 return ip_generic_getfrag(rfv->msg->msg_iov, to, offset, len, odd, skb);
734} 731}
735 732
736static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, 733static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -745,6 +742,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
745 struct ipv6_txoptions *opt = NULL; 742 struct ipv6_txoptions *opt = NULL;
746 struct ip6_flowlabel *flowlabel = NULL; 743 struct ip6_flowlabel *flowlabel = NULL;
747 struct dst_entry *dst = NULL; 744 struct dst_entry *dst = NULL;
745 struct raw6_frag_vec rfv;
748 struct flowi6 fl6; 746 struct flowi6 fl6;
749 int addr_len = msg->msg_namelen; 747 int addr_len = msg->msg_namelen;
750 int hlimit = -1; 748 int hlimit = -1;
@@ -848,7 +846,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
848 opt = ipv6_fixup_options(&opt_space, opt); 846 opt = ipv6_fixup_options(&opt_space, opt);
849 847
850 fl6.flowi6_proto = proto; 848 fl6.flowi6_proto = proto;
851 err = rawv6_probe_proto_opt(&fl6, msg); 849 rfv.msg = msg;
850 rfv.hlen = 0;
851 err = rawv6_probe_proto_opt(&rfv, &fl6);
852 if (err) 852 if (err)
853 goto out; 853 goto out;
854 854
@@ -889,7 +889,7 @@ back_from_confirm:
889 err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags); 889 err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
890 else { 890 else {
891 lock_sock(sk); 891 lock_sock(sk);
892 err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, 892 err = ip6_append_data(sk, raw6_getfrag, &rfv,
893 len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst, 893 len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
894 msg->msg_flags, dontfrag); 894 msg->msg_flags, dontfrag);
895 895