diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-24 12:10:46 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-09 16:28:21 -0500 |
commit | 19e3c66b52caf20a9a1119dc847b6abae4c03f4f (patch) | |
tree | b27bdfce9a7e37c2ea1eee2a69b107112c26779a /net/ipv6 | |
parent | b61e9dcc5e77d534fa770a02877fd45f51d4e7f4 (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.c | 112 |
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 | ||
675 | static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg) | 675 | struct raw6_frag_vec { |
676 | struct msghdr *msg; | ||
677 | int hlen; | ||
678 | char c[4]; | ||
679 | }; | ||
680 | |||
681 | static 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++) { | 702 | static 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 | ||
736 | static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 733 | static 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 | ||