diff options
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 90 |
1 files changed, 86 insertions, 4 deletions
diff --git a/net/compat.c b/net/compat.c index 01bf95d0832e..c823f6f290cb 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -548,6 +548,9 @@ struct compat_group_filter { | |||
548 | __attribute__ ((aligned(4))); | 548 | __attribute__ ((aligned(4))); |
549 | } __attribute__ ((packed)); | 549 | } __attribute__ ((packed)); |
550 | 550 | ||
551 | #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \ | ||
552 | sizeof(struct __kernel_sockaddr_storage)) | ||
553 | |||
551 | 554 | ||
552 | int compat_mc_setsockopt(struct sock *sock, int level, int optname, | 555 | int compat_mc_setsockopt(struct sock *sock, int level, int optname, |
553 | char __user *optval, int optlen, | 556 | char __user *optval, int optlen, |
@@ -582,7 +585,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, | |||
582 | case MCAST_UNBLOCK_SOURCE: | 585 | case MCAST_UNBLOCK_SOURCE: |
583 | { | 586 | { |
584 | struct compat_group_source_req __user *gsr32 = (void *)optval; | 587 | struct compat_group_source_req __user *gsr32 = (void *)optval; |
585 | struct group_source_req *kgsr = compat_alloc_user_space( | 588 | struct group_source_req __user *kgsr = compat_alloc_user_space( |
586 | sizeof(struct group_source_req)); | 589 | sizeof(struct group_source_req)); |
587 | u32 interface; | 590 | u32 interface; |
588 | 591 | ||
@@ -603,10 +606,10 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, | |||
603 | case MCAST_MSFILTER: | 606 | case MCAST_MSFILTER: |
604 | { | 607 | { |
605 | struct compat_group_filter __user *gf32 = (void *)optval; | 608 | struct compat_group_filter __user *gf32 = (void *)optval; |
606 | struct group_filter *kgf; | 609 | struct group_filter __user *kgf; |
607 | u32 interface, fmode, numsrc; | 610 | u32 interface, fmode, numsrc; |
608 | 611 | ||
609 | if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) || | 612 | if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || |
610 | __get_user(interface, &gf32->gf_interface) || | 613 | __get_user(interface, &gf32->gf_interface) || |
611 | __get_user(fmode, &gf32->gf_fmode) || | 614 | __get_user(fmode, &gf32->gf_fmode) || |
612 | __get_user(numsrc, &gf32->gf_numsrc)) | 615 | __get_user(numsrc, &gf32->gf_numsrc)) |
@@ -622,7 +625,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, | |||
622 | __put_user(numsrc, &kgf->gf_numsrc) || | 625 | __put_user(numsrc, &kgf->gf_numsrc) || |
623 | copy_in_user(&kgf->gf_group, &gf32->gf_group, | 626 | copy_in_user(&kgf->gf_group, &gf32->gf_group, |
624 | sizeof(kgf->gf_group)) || | 627 | sizeof(kgf->gf_group)) || |
625 | (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist, | 628 | (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist, |
626 | numsrc * sizeof(kgf->gf_slist[0])))) | 629 | numsrc * sizeof(kgf->gf_slist[0])))) |
627 | return -EFAULT; | 630 | return -EFAULT; |
628 | koptval = (char __user *)kgf; | 631 | koptval = (char __user *)kgf; |
@@ -637,6 +640,85 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, | |||
637 | 640 | ||
638 | EXPORT_SYMBOL(compat_mc_setsockopt); | 641 | EXPORT_SYMBOL(compat_mc_setsockopt); |
639 | 642 | ||
643 | int compat_mc_getsockopt(struct sock *sock, int level, int optname, | ||
644 | char __user *optval, int __user *optlen, | ||
645 | int (*getsockopt)(struct sock *,int,int,char __user *,int __user *)) | ||
646 | { | ||
647 | struct compat_group_filter __user *gf32 = (void *)optval; | ||
648 | struct group_filter __user *kgf; | ||
649 | int __user *koptlen; | ||
650 | u32 interface, fmode, numsrc; | ||
651 | int klen, ulen, err; | ||
652 | |||
653 | if (optname != MCAST_MSFILTER) | ||
654 | return getsockopt(sock, level, optname, optval, optlen); | ||
655 | |||
656 | koptlen = compat_alloc_user_space(sizeof(*koptlen)); | ||
657 | if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) || | ||
658 | __get_user(ulen, optlen)) | ||
659 | return -EFAULT; | ||
660 | |||
661 | /* adjust len for pad */ | ||
662 | klen = ulen + sizeof(*kgf) - sizeof(*gf32); | ||
663 | |||
664 | if (klen < GROUP_FILTER_SIZE(0)) | ||
665 | return -EINVAL; | ||
666 | |||
667 | if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) || | ||
668 | __put_user(klen, koptlen)) | ||
669 | return -EFAULT; | ||
670 | |||
671 | /* have to allow space for previous compat_alloc_user_space, too */ | ||
672 | kgf = compat_alloc_user_space(klen+sizeof(*optlen)); | ||
673 | |||
674 | if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || | ||
675 | __get_user(interface, &gf32->gf_interface) || | ||
676 | __get_user(fmode, &gf32->gf_fmode) || | ||
677 | __get_user(numsrc, &gf32->gf_numsrc) || | ||
678 | __put_user(interface, &kgf->gf_interface) || | ||
679 | __put_user(fmode, &kgf->gf_fmode) || | ||
680 | __put_user(numsrc, &kgf->gf_numsrc) || | ||
681 | copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group))) | ||
682 | return -EFAULT; | ||
683 | |||
684 | err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen); | ||
685 | if (err) | ||
686 | return err; | ||
687 | |||
688 | if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) || | ||
689 | __get_user(klen, koptlen)) | ||
690 | return -EFAULT; | ||
691 | |||
692 | ulen = klen - (sizeof(*kgf)-sizeof(*gf32)); | ||
693 | |||
694 | if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) || | ||
695 | __put_user(ulen, optlen)) | ||
696 | return -EFAULT; | ||
697 | |||
698 | if (!access_ok(VERIFY_READ, kgf, klen) || | ||
699 | !access_ok(VERIFY_WRITE, gf32, ulen) || | ||
700 | __get_user(interface, &kgf->gf_interface) || | ||
701 | __get_user(fmode, &kgf->gf_fmode) || | ||
702 | __get_user(numsrc, &kgf->gf_numsrc) || | ||
703 | __put_user(interface, &gf32->gf_interface) || | ||
704 | __put_user(fmode, &gf32->gf_fmode) || | ||
705 | __put_user(numsrc, &gf32->gf_numsrc)) | ||
706 | return -EFAULT; | ||
707 | if (numsrc) { | ||
708 | int copylen; | ||
709 | |||
710 | klen -= GROUP_FILTER_SIZE(0); | ||
711 | copylen = numsrc * sizeof(gf32->gf_slist[0]); | ||
712 | if (copylen > klen) | ||
713 | copylen = klen; | ||
714 | if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen)) | ||
715 | return -EFAULT; | ||
716 | } | ||
717 | return err; | ||
718 | } | ||
719 | |||
720 | EXPORT_SYMBOL(compat_mc_getsockopt); | ||
721 | |||
640 | 722 | ||
641 | /* Argument list sizes for compat_sys_socketcall */ | 723 | /* Argument list sizes for compat_sys_socketcall */ |
642 | #define AL(x) ((x) * sizeof(u32)) | 724 | #define AL(x) ((x) * sizeof(u32)) |