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)) |
