aboutsummaryrefslogtreecommitdiffstats
path: root/net/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/compat.c')
-rw-r--r--net/compat.c90
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
552int compat_mc_setsockopt(struct sock *sock, int level, int optname, 555int 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
638EXPORT_SYMBOL(compat_mc_setsockopt); 641EXPORT_SYMBOL(compat_mc_setsockopt);
639 642
643int 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
720EXPORT_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))