diff options
| -rw-r--r-- | include/net/compat.h | 3 | ||||
| -rw-r--r-- | net/compat.c | 79 | ||||
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 9 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 4 |
4 files changed, 94 insertions, 1 deletions
diff --git a/include/net/compat.h b/include/net/compat.h index 05fa5d0254ab..164cb682e220 100644 --- a/include/net/compat.h +++ b/include/net/compat.h | |||
| @@ -42,5 +42,8 @@ extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsi | |||
| 42 | 42 | ||
| 43 | extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int, | 43 | extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int, |
| 44 | int (*)(struct sock *, int, int, char __user *, int)); | 44 | int (*)(struct sock *, int, int, char __user *, int)); |
| 45 | extern int compat_mc_getsockopt(struct sock *, int, int, char __user *, | ||
| 46 | int __user *, int (*)(struct sock *, int, int, char __user *, | ||
| 47 | int __user *)); | ||
| 45 | 48 | ||
| 46 | #endif /* NET_COMPAT_H */ | 49 | #endif /* NET_COMPAT_H */ |
diff --git a/net/compat.c b/net/compat.c index 8146f654391c..c823f6f290cb 100644 --- a/net/compat.c +++ b/net/compat.c | |||
| @@ -640,6 +640,85 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, | |||
| 640 | 640 | ||
| 641 | EXPORT_SYMBOL(compat_mc_setsockopt); | 641 | EXPORT_SYMBOL(compat_mc_setsockopt); |
| 642 | 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 | |||
| 643 | 722 | ||
| 644 | /* Argument list sizes for compat_sys_socketcall */ | 723 | /* Argument list sizes for compat_sys_socketcall */ |
| 645 | #define AL(x) ((x) * sizeof(u32)) | 724 | #define AL(x) ((x) * sizeof(u32)) |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4d8d95404f45..e0514e82308e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -1186,7 +1186,14 @@ int ip_getsockopt(struct sock *sk, int level, | |||
| 1186 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, | 1186 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, |
| 1187 | char __user *optval, int __user *optlen) | 1187 | char __user *optval, int __user *optlen) |
| 1188 | { | 1188 | { |
| 1189 | int err = do_ip_getsockopt(sk, level, optname, optval, optlen); | 1189 | int err; |
| 1190 | |||
| 1191 | if (optname == MCAST_MSFILTER) | ||
| 1192 | return compat_mc_getsockopt(sk, level, optname, optval, optlen, | ||
| 1193 | ip_getsockopt); | ||
| 1194 | |||
| 1195 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
| 1196 | |||
| 1190 | #ifdef CONFIG_NETFILTER | 1197 | #ifdef CONFIG_NETFILTER |
| 1191 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | 1198 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
| 1192 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS && | 1199 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS && |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index db6fdc1498aa..b4a26f2505f8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -1089,6 +1089,10 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1089 | if(level != SOL_IPV6) | 1089 | if(level != SOL_IPV6) |
| 1090 | return -ENOPROTOOPT; | 1090 | return -ENOPROTOOPT; |
| 1091 | 1091 | ||
| 1092 | if (optname == MCAST_MSFILTER) | ||
| 1093 | return compat_mc_getsockopt(sk, level, optname, optval, optlen, | ||
| 1094 | ipv6_getsockopt); | ||
| 1095 | |||
| 1092 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | 1096 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); |
| 1093 | #ifdef CONFIG_NETFILTER | 1097 | #ifdef CONFIG_NETFILTER |
| 1094 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | 1098 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
