dccp ccid-3: TFRC reverse-lookup Bug-Fix
[pandora-kernel.git] / net / compat.c
index 01bf95d..c823f6f 100644 (file)
@@ -548,6 +548,9 @@ struct compat_group_filter {
                __attribute__ ((aligned(4)));
 } __attribute__ ((packed));
 
+#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
+                       sizeof(struct __kernel_sockaddr_storage))
+
 
 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
        char __user *optval, int optlen,
@@ -582,7 +585,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
        case MCAST_UNBLOCK_SOURCE:
        {
                struct compat_group_source_req __user *gsr32 = (void *)optval;
-               struct group_source_req *kgsr = compat_alloc_user_space(
+               struct group_source_req __user *kgsr = compat_alloc_user_space(
                        sizeof(struct group_source_req));
                u32 interface;
 
@@ -603,10 +606,10 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
        case MCAST_MSFILTER:
        {
                struct compat_group_filter __user *gf32 = (void *)optval;
-               struct group_filter *kgf;
+               struct group_filter __user *kgf;
                u32 interface, fmode, numsrc;
 
-               if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+               if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
                    __get_user(interface, &gf32->gf_interface) ||
                    __get_user(fmode, &gf32->gf_fmode) ||
                    __get_user(numsrc, &gf32->gf_numsrc))
@@ -622,7 +625,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
                    __put_user(numsrc, &kgf->gf_numsrc) ||
                    copy_in_user(&kgf->gf_group, &gf32->gf_group,
                                sizeof(kgf->gf_group)) ||
-                   (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist,
+                   (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
                                numsrc * sizeof(kgf->gf_slist[0]))))
                        return -EFAULT;
                koptval = (char __user *)kgf;
@@ -637,6 +640,85 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
 
 EXPORT_SYMBOL(compat_mc_setsockopt);
 
+int compat_mc_getsockopt(struct sock *sock, int level, int optname,
+       char __user *optval, int __user *optlen,
+       int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
+{
+       struct compat_group_filter __user *gf32 = (void *)optval;
+       struct group_filter __user *kgf;
+       int __user      *koptlen;
+       u32 interface, fmode, numsrc;
+       int klen, ulen, err;
+
+       if (optname != MCAST_MSFILTER)
+               return getsockopt(sock, level, optname, optval, optlen);
+
+       koptlen = compat_alloc_user_space(sizeof(*koptlen));
+       if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
+           __get_user(ulen, optlen))
+               return -EFAULT;
+
+       /* adjust len for pad */
+       klen = ulen + sizeof(*kgf) - sizeof(*gf32);
+
+       if (klen < GROUP_FILTER_SIZE(0))
+               return -EINVAL;
+
+       if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
+           __put_user(klen, koptlen))
+               return -EFAULT;
+
+       /* have to allow space for previous compat_alloc_user_space, too */
+       kgf = compat_alloc_user_space(klen+sizeof(*optlen));
+
+       if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
+           __get_user(interface, &gf32->gf_interface) ||
+           __get_user(fmode, &gf32->gf_fmode) ||
+           __get_user(numsrc, &gf32->gf_numsrc) ||
+           __put_user(interface, &kgf->gf_interface) ||
+           __put_user(fmode, &kgf->gf_fmode) ||
+           __put_user(numsrc, &kgf->gf_numsrc) ||
+           copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
+               return -EFAULT;
+
+       err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
+       if (err)
+               return err;
+
+       if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
+           __get_user(klen, koptlen))
+               return -EFAULT;
+
+       ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
+
+       if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
+           __put_user(ulen, optlen))
+               return -EFAULT;
+
+       if (!access_ok(VERIFY_READ, kgf, klen) ||
+           !access_ok(VERIFY_WRITE, gf32, ulen) ||
+           __get_user(interface, &kgf->gf_interface) ||
+           __get_user(fmode, &kgf->gf_fmode) ||
+           __get_user(numsrc, &kgf->gf_numsrc) ||
+           __put_user(interface, &gf32->gf_interface) ||
+           __put_user(fmode, &gf32->gf_fmode) ||
+           __put_user(numsrc, &gf32->gf_numsrc))
+               return -EFAULT;
+       if (numsrc) {
+               int copylen;
+
+               klen -= GROUP_FILTER_SIZE(0);
+               copylen = numsrc * sizeof(gf32->gf_slist[0]);
+               if (copylen > klen)
+                       copylen = klen;
+               if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
+                       return -EFAULT;
+       }
+       return err;
+}
+
+EXPORT_SYMBOL(compat_mc_getsockopt);
+
 
 /* Argument list sizes for compat_sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))