diff options
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d09329ca3267..d6dedc4aec77 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -604,7 +604,7 @@ error: | |||
604 | return err; | 604 | return err; |
605 | } | 605 | } |
606 | 606 | ||
607 | static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 607 | static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) |
608 | { | 608 | { |
609 | struct iovec *iov; | 609 | struct iovec *iov; |
610 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
@@ -616,7 +616,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
616 | int i; | 616 | int i; |
617 | 617 | ||
618 | if (!msg->msg_iov) | 618 | if (!msg->msg_iov) |
619 | return; | 619 | return 0; |
620 | 620 | ||
621 | for (i = 0; i < msg->msg_iovlen; i++) { | 621 | for (i = 0; i < msg->msg_iovlen; i++) { |
622 | iov = &msg->msg_iov[i]; | 622 | iov = &msg->msg_iov[i]; |
@@ -638,8 +638,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
638 | code = iov->iov_base; | 638 | code = iov->iov_base; |
639 | 639 | ||
640 | if (type && code) { | 640 | if (type && code) { |
641 | get_user(fl->fl_icmp_type, type); | 641 | if (get_user(fl->fl_icmp_type, type) || |
642 | get_user(fl->fl_icmp_code, code); | 642 | get_user(fl->fl_icmp_code, code)) |
643 | return -EFAULT; | ||
643 | probed = 1; | 644 | probed = 1; |
644 | } | 645 | } |
645 | break; | 646 | break; |
@@ -650,7 +651,8 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
650 | /* check if type field is readable or not. */ | 651 | /* check if type field is readable or not. */ |
651 | if (iov->iov_len > 2 - len) { | 652 | if (iov->iov_len > 2 - len) { |
652 | u8 __user *p = iov->iov_base; | 653 | u8 __user *p = iov->iov_base; |
653 | get_user(fl->fl_mh_type, &p[2 - len]); | 654 | if (get_user(fl->fl_mh_type, &p[2 - len])) |
655 | return -EFAULT; | ||
654 | probed = 1; | 656 | probed = 1; |
655 | } else | 657 | } else |
656 | len += iov->iov_len; | 658 | len += iov->iov_len; |
@@ -664,6 +666,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
664 | if (probed) | 666 | if (probed) |
665 | break; | 667 | break; |
666 | } | 668 | } |
669 | return 0; | ||
667 | } | 670 | } |
668 | 671 | ||
669 | static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 672 | static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, |
@@ -787,7 +790,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
787 | opt = ipv6_fixup_options(&opt_space, opt); | 790 | opt = ipv6_fixup_options(&opt_space, opt); |
788 | 791 | ||
789 | fl.proto = proto; | 792 | fl.proto = proto; |
790 | rawv6_probe_proto_opt(&fl, msg); | 793 | err = rawv6_probe_proto_opt(&fl, msg); |
794 | if (err) | ||
795 | goto out; | ||
791 | 796 | ||
792 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 797 | ipv6_addr_copy(&fl.fl6_dst, daddr); |
793 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 798 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |