Back to home page

LXR

 
 

    


0001 /*
0002  * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
0003  *
0004  * Copyright (C) 2000       VA Linux Co
0005  * Copyright (C) 2000       Don Dugger <n0ano@valinux.com>
0006  * Copyright (C) 1999       Arun Sharma <arun.sharma@intel.com>
0007  * Copyright (C) 1997,1998  Jakub Jelinek (jj@sunsite.mff.cuni.cz)
0008  * Copyright (C) 1997       David S. Miller (davem@caip.rutgers.edu)
0009  * Copyright (C) 2000       Hewlett-Packard Co.
0010  * Copyright (C) 2000       David Mosberger-Tang <davidm@hpl.hp.com>
0011  * Copyright (C) 2000,2001  Andi Kleen, SuSE Labs
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/gfp.h>
0016 #include <linux/fs.h>
0017 #include <linux/types.h>
0018 #include <linux/file.h>
0019 #include <linux/icmpv6.h>
0020 #include <linux/socket.h>
0021 #include <linux/syscalls.h>
0022 #include <linux/filter.h>
0023 #include <linux/compat.h>
0024 #include <linux/security.h>
0025 #include <linux/export.h>
0026 
0027 #include <net/scm.h>
0028 #include <net/sock.h>
0029 #include <net/ip.h>
0030 #include <net/ipv6.h>
0031 #include <linux/uaccess.h>
0032 #include <net/compat.h>
0033 
0034 int get_compat_msghdr(struct msghdr *kmsg,
0035               struct compat_msghdr __user *umsg,
0036               struct sockaddr __user **save_addr,
0037               struct iovec **iov)
0038 {
0039     compat_uptr_t uaddr, uiov, tmp3;
0040     compat_size_t nr_segs;
0041     ssize_t err;
0042 
0043     if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
0044         __get_user(uaddr, &umsg->msg_name) ||
0045         __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
0046         __get_user(uiov, &umsg->msg_iov) ||
0047         __get_user(nr_segs, &umsg->msg_iovlen) ||
0048         __get_user(tmp3, &umsg->msg_control) ||
0049         __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
0050         __get_user(kmsg->msg_flags, &umsg->msg_flags))
0051         return -EFAULT;
0052 
0053     if (!uaddr)
0054         kmsg->msg_namelen = 0;
0055 
0056     if (kmsg->msg_namelen < 0)
0057         return -EINVAL;
0058 
0059     if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
0060         kmsg->msg_namelen = sizeof(struct sockaddr_storage);
0061     kmsg->msg_control = compat_ptr(tmp3);
0062 
0063     if (save_addr)
0064         *save_addr = compat_ptr(uaddr);
0065 
0066     if (uaddr && kmsg->msg_namelen) {
0067         if (!save_addr) {
0068             err = move_addr_to_kernel(compat_ptr(uaddr),
0069                           kmsg->msg_namelen,
0070                           kmsg->msg_name);
0071             if (err < 0)
0072                 return err;
0073         }
0074     } else {
0075         kmsg->msg_name = NULL;
0076         kmsg->msg_namelen = 0;
0077     }
0078 
0079     if (nr_segs > UIO_MAXIOV)
0080         return -EMSGSIZE;
0081 
0082     kmsg->msg_iocb = NULL;
0083 
0084     return compat_import_iovec(save_addr ? READ : WRITE,
0085                    compat_ptr(uiov), nr_segs,
0086                    UIO_FASTIOV, iov, &kmsg->msg_iter);
0087 }
0088 
0089 /* Bleech... */
0090 #define CMSG_COMPAT_ALIGN(len)  ALIGN((len), sizeof(s32))
0091 
0092 #define CMSG_COMPAT_DATA(cmsg)              \
0093     ((void __user *)((char __user *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
0094 #define CMSG_COMPAT_SPACE(len)              \
0095     (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
0096 #define CMSG_COMPAT_LEN(len)                \
0097     (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
0098 
0099 #define CMSG_COMPAT_FIRSTHDR(msg)           \
0100     (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
0101      (struct compat_cmsghdr __user *)((msg)->msg_control) :     \
0102      (struct compat_cmsghdr __user *)NULL)
0103 
0104 #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
0105     ((ucmlen) >= sizeof(struct compat_cmsghdr) && \
0106      (ucmlen) <= (unsigned long) \
0107      ((mhdr)->msg_controllen - \
0108       ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
0109 
0110 static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
0111         struct compat_cmsghdr __user *cmsg, int cmsg_len)
0112 {
0113     char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
0114     if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
0115             msg->msg_controllen)
0116         return NULL;
0117     return (struct compat_cmsghdr __user *)ptr;
0118 }
0119 
0120 /* There is a lot of hair here because the alignment rules (and
0121  * thus placement) of cmsg headers and length are different for
0122  * 32-bit apps.  -DaveM
0123  */
0124 int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
0125                    unsigned char *stackbuf, int stackbuf_size)
0126 {
0127     struct compat_cmsghdr __user *ucmsg;
0128     struct cmsghdr *kcmsg, *kcmsg_base;
0129     compat_size_t ucmlen;
0130     __kernel_size_t kcmlen, tmp;
0131     int err = -EFAULT;
0132 
0133     kcmlen = 0;
0134     kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
0135     ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
0136     while (ucmsg != NULL) {
0137         if (get_user(ucmlen, &ucmsg->cmsg_len))
0138             return -EFAULT;
0139 
0140         /* Catch bogons. */
0141         if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
0142             return -EINVAL;
0143 
0144         tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
0145                CMSG_ALIGN(sizeof(struct cmsghdr)));
0146         tmp = CMSG_ALIGN(tmp);
0147         kcmlen += tmp;
0148         ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
0149     }
0150     if (kcmlen == 0)
0151         return -EINVAL;
0152 
0153     /* The kcmlen holds the 64-bit version of the control length.
0154      * It may not be modified as we do not stick it into the kmsg
0155      * until we have successfully copied over all of the data
0156      * from the user.
0157      */
0158     if (kcmlen > stackbuf_size)
0159         kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
0160     if (kcmsg == NULL)
0161         return -ENOBUFS;
0162 
0163     /* Now copy them over neatly. */
0164     memset(kcmsg, 0, kcmlen);
0165     ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
0166     while (ucmsg != NULL) {
0167         if (__get_user(ucmlen, &ucmsg->cmsg_len))
0168             goto Efault;
0169         if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
0170             goto Einval;
0171         tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
0172                CMSG_ALIGN(sizeof(struct cmsghdr)));
0173         if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
0174             goto Einval;
0175         kcmsg->cmsg_len = tmp;
0176         tmp = CMSG_ALIGN(tmp);
0177         if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
0178             __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
0179             copy_from_user(CMSG_DATA(kcmsg),
0180                    CMSG_COMPAT_DATA(ucmsg),
0181                    (ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg)))))
0182             goto Efault;
0183 
0184         /* Advance. */
0185         kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
0186         ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
0187     }
0188 
0189     /* Ok, looks like we made it.  Hook it up and return success. */
0190     kmsg->msg_control = kcmsg_base;
0191     kmsg->msg_controllen = kcmlen;
0192     return 0;
0193 
0194 Einval:
0195     err = -EINVAL;
0196 Efault:
0197     if (kcmsg_base != (struct cmsghdr *)stackbuf)
0198         sock_kfree_s(sk, kcmsg_base, kcmlen);
0199     return err;
0200 }
0201 
0202 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
0203 {
0204     struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
0205     struct compat_cmsghdr cmhdr;
0206     struct compat_timeval ctv;
0207     struct compat_timespec cts[3];
0208     int cmlen;
0209 
0210     if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
0211         kmsg->msg_flags |= MSG_CTRUNC;
0212         return 0; /* XXX: return error? check spec. */
0213     }
0214 
0215     if (!COMPAT_USE_64BIT_TIME) {
0216         if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
0217             struct timeval *tv = (struct timeval *)data;
0218             ctv.tv_sec = tv->tv_sec;
0219             ctv.tv_usec = tv->tv_usec;
0220             data = &ctv;
0221             len = sizeof(ctv);
0222         }
0223         if (level == SOL_SOCKET &&
0224             (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
0225             int count = type == SCM_TIMESTAMPNS ? 1 : 3;
0226             int i;
0227             struct timespec *ts = (struct timespec *)data;
0228             for (i = 0; i < count; i++) {
0229                 cts[i].tv_sec = ts[i].tv_sec;
0230                 cts[i].tv_nsec = ts[i].tv_nsec;
0231             }
0232             data = &cts;
0233             len = sizeof(cts[0]) * count;
0234         }
0235     }
0236 
0237     cmlen = CMSG_COMPAT_LEN(len);
0238     if (kmsg->msg_controllen < cmlen) {
0239         kmsg->msg_flags |= MSG_CTRUNC;
0240         cmlen = kmsg->msg_controllen;
0241     }
0242     cmhdr.cmsg_level = level;
0243     cmhdr.cmsg_type = type;
0244     cmhdr.cmsg_len = cmlen;
0245 
0246     if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
0247         return -EFAULT;
0248     if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
0249         return -EFAULT;
0250     cmlen = CMSG_COMPAT_SPACE(len);
0251     if (kmsg->msg_controllen < cmlen)
0252         cmlen = kmsg->msg_controllen;
0253     kmsg->msg_control += cmlen;
0254     kmsg->msg_controllen -= cmlen;
0255     return 0;
0256 }
0257 
0258 void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
0259 {
0260     struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
0261     int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
0262     int fdnum = scm->fp->count;
0263     struct file **fp = scm->fp->fp;
0264     int __user *cmfptr;
0265     int err = 0, i;
0266 
0267     if (fdnum < fdmax)
0268         fdmax = fdnum;
0269 
0270     for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) {
0271         int new_fd;
0272         err = security_file_receive(fp[i]);
0273         if (err)
0274             break;
0275         err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
0276                       ? O_CLOEXEC : 0);
0277         if (err < 0)
0278             break;
0279         new_fd = err;
0280         err = put_user(new_fd, cmfptr);
0281         if (err) {
0282             put_unused_fd(new_fd);
0283             break;
0284         }
0285         /* Bump the usage count and install the file. */
0286         fd_install(new_fd, get_file(fp[i]));
0287     }
0288 
0289     if (i > 0) {
0290         int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
0291         err = put_user(SOL_SOCKET, &cm->cmsg_level);
0292         if (!err)
0293             err = put_user(SCM_RIGHTS, &cm->cmsg_type);
0294         if (!err)
0295             err = put_user(cmlen, &cm->cmsg_len);
0296         if (!err) {
0297             cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
0298             kmsg->msg_control += cmlen;
0299             kmsg->msg_controllen -= cmlen;
0300         }
0301     }
0302     if (i < fdnum)
0303         kmsg->msg_flags |= MSG_CTRUNC;
0304 
0305     /*
0306      * All of the files that fit in the message have had their
0307      * usage counts incremented, so we just free the list.
0308      */
0309     __scm_destroy(scm);
0310 }
0311 
0312 /* allocate a 64-bit sock_fprog on the user stack for duration of syscall. */
0313 struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval)
0314 {
0315     struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
0316     struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
0317     compat_uptr_t ptr;
0318     u16 len;
0319 
0320     if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
0321         !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
0322         __get_user(len, &fprog32->len) ||
0323         __get_user(ptr, &fprog32->filter) ||
0324         __put_user(len, &kfprog->len) ||
0325         __put_user(compat_ptr(ptr), &kfprog->filter))
0326         return NULL;
0327 
0328     return kfprog;
0329 }
0330 EXPORT_SYMBOL_GPL(get_compat_bpf_fprog);
0331 
0332 static int do_set_attach_filter(struct socket *sock, int level, int optname,
0333                 char __user *optval, unsigned int optlen)
0334 {
0335     struct sock_fprog __user *kfprog;
0336 
0337     kfprog = get_compat_bpf_fprog(optval);
0338     if (!kfprog)
0339         return -EFAULT;
0340 
0341     return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
0342                   sizeof(struct sock_fprog));
0343 }
0344 
0345 static int do_set_sock_timeout(struct socket *sock, int level,
0346         int optname, char __user *optval, unsigned int optlen)
0347 {
0348     struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
0349     struct timeval ktime;
0350     mm_segment_t old_fs;
0351     int err;
0352 
0353     if (optlen < sizeof(*up))
0354         return -EINVAL;
0355     if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
0356         __get_user(ktime.tv_sec, &up->tv_sec) ||
0357         __get_user(ktime.tv_usec, &up->tv_usec))
0358         return -EFAULT;
0359     old_fs = get_fs();
0360     set_fs(KERNEL_DS);
0361     err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
0362     set_fs(old_fs);
0363 
0364     return err;
0365 }
0366 
0367 static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
0368                 char __user *optval, unsigned int optlen)
0369 {
0370     if (optname == SO_ATTACH_FILTER ||
0371         optname == SO_ATTACH_REUSEPORT_CBPF)
0372         return do_set_attach_filter(sock, level, optname,
0373                         optval, optlen);
0374     if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
0375         return do_set_sock_timeout(sock, level, optname, optval, optlen);
0376 
0377     return sock_setsockopt(sock, level, optname, optval, optlen);
0378 }
0379 
0380 COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
0381                char __user *, optval, unsigned int, optlen)
0382 {
0383     int err;
0384     struct socket *sock = sockfd_lookup(fd, &err);
0385 
0386     if (sock) {
0387         err = security_socket_setsockopt(sock, level, optname);
0388         if (err) {
0389             sockfd_put(sock);
0390             return err;
0391         }
0392 
0393         if (level == SOL_SOCKET)
0394             err = compat_sock_setsockopt(sock, level,
0395                     optname, optval, optlen);
0396         else if (sock->ops->compat_setsockopt)
0397             err = sock->ops->compat_setsockopt(sock, level,
0398                     optname, optval, optlen);
0399         else
0400             err = sock->ops->setsockopt(sock, level,
0401                     optname, optval, optlen);
0402         sockfd_put(sock);
0403     }
0404     return err;
0405 }
0406 
0407 static int do_get_sock_timeout(struct socket *sock, int level, int optname,
0408         char __user *optval, int __user *optlen)
0409 {
0410     struct compat_timeval __user *up;
0411     struct timeval ktime;
0412     mm_segment_t old_fs;
0413     int len, err;
0414 
0415     up = (struct compat_timeval __user *) optval;
0416     if (get_user(len, optlen))
0417         return -EFAULT;
0418     if (len < sizeof(*up))
0419         return -EINVAL;
0420     len = sizeof(ktime);
0421     old_fs = get_fs();
0422     set_fs(KERNEL_DS);
0423     err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
0424     set_fs(old_fs);
0425 
0426     if (!err) {
0427         if (put_user(sizeof(*up), optlen) ||
0428             !access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
0429             __put_user(ktime.tv_sec, &up->tv_sec) ||
0430             __put_user(ktime.tv_usec, &up->tv_usec))
0431             err = -EFAULT;
0432     }
0433     return err;
0434 }
0435 
0436 static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
0437                 char __user *optval, int __user *optlen)
0438 {
0439     if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
0440         return do_get_sock_timeout(sock, level, optname, optval, optlen);
0441     return sock_getsockopt(sock, level, optname, optval, optlen);
0442 }
0443 
0444 int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
0445 {
0446     struct compat_timeval __user *ctv;
0447     int err;
0448     struct timeval tv;
0449 
0450     if (COMPAT_USE_64BIT_TIME)
0451         return sock_get_timestamp(sk, userstamp);
0452 
0453     ctv = (struct compat_timeval __user *) userstamp;
0454     err = -ENOENT;
0455     if (!sock_flag(sk, SOCK_TIMESTAMP))
0456         sock_enable_timestamp(sk, SOCK_TIMESTAMP);
0457     tv = ktime_to_timeval(sk->sk_stamp);
0458     if (tv.tv_sec == -1)
0459         return err;
0460     if (tv.tv_sec == 0) {
0461         sk->sk_stamp = ktime_get_real();
0462         tv = ktime_to_timeval(sk->sk_stamp);
0463     }
0464     err = 0;
0465     if (put_user(tv.tv_sec, &ctv->tv_sec) ||
0466             put_user(tv.tv_usec, &ctv->tv_usec))
0467         err = -EFAULT;
0468     return err;
0469 }
0470 EXPORT_SYMBOL(compat_sock_get_timestamp);
0471 
0472 int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
0473 {
0474     struct compat_timespec __user *ctv;
0475     int err;
0476     struct timespec ts;
0477 
0478     if (COMPAT_USE_64BIT_TIME)
0479         return sock_get_timestampns (sk, userstamp);
0480 
0481     ctv = (struct compat_timespec __user *) userstamp;
0482     err = -ENOENT;
0483     if (!sock_flag(sk, SOCK_TIMESTAMP))
0484         sock_enable_timestamp(sk, SOCK_TIMESTAMP);
0485     ts = ktime_to_timespec(sk->sk_stamp);
0486     if (ts.tv_sec == -1)
0487         return err;
0488     if (ts.tv_sec == 0) {
0489         sk->sk_stamp = ktime_get_real();
0490         ts = ktime_to_timespec(sk->sk_stamp);
0491     }
0492     err = 0;
0493     if (put_user(ts.tv_sec, &ctv->tv_sec) ||
0494             put_user(ts.tv_nsec, &ctv->tv_nsec))
0495         err = -EFAULT;
0496     return err;
0497 }
0498 EXPORT_SYMBOL(compat_sock_get_timestampns);
0499 
0500 COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
0501                char __user *, optval, int __user *, optlen)
0502 {
0503     int err;
0504     struct socket *sock = sockfd_lookup(fd, &err);
0505 
0506     if (sock) {
0507         err = security_socket_getsockopt(sock, level, optname);
0508         if (err) {
0509             sockfd_put(sock);
0510             return err;
0511         }
0512 
0513         if (level == SOL_SOCKET)
0514             err = compat_sock_getsockopt(sock, level,
0515                     optname, optval, optlen);
0516         else if (sock->ops->compat_getsockopt)
0517             err = sock->ops->compat_getsockopt(sock, level,
0518                     optname, optval, optlen);
0519         else
0520             err = sock->ops->getsockopt(sock, level,
0521                     optname, optval, optlen);
0522         sockfd_put(sock);
0523     }
0524     return err;
0525 }
0526 
0527 struct compat_group_req {
0528     __u32                gr_interface;
0529     struct __kernel_sockaddr_storage gr_group
0530         __aligned(4);
0531 } __packed;
0532 
0533 struct compat_group_source_req {
0534     __u32                gsr_interface;
0535     struct __kernel_sockaddr_storage gsr_group
0536         __aligned(4);
0537     struct __kernel_sockaddr_storage gsr_source
0538         __aligned(4);
0539 } __packed;
0540 
0541 struct compat_group_filter {
0542     __u32                gf_interface;
0543     struct __kernel_sockaddr_storage gf_group
0544         __aligned(4);
0545     __u32                gf_fmode;
0546     __u32                gf_numsrc;
0547     struct __kernel_sockaddr_storage gf_slist[1]
0548         __aligned(4);
0549 } __packed;
0550 
0551 #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
0552             sizeof(struct __kernel_sockaddr_storage))
0553 
0554 
0555 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
0556     char __user *optval, unsigned int optlen,
0557     int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
0558 {
0559     char __user *koptval = optval;
0560     int     koptlen = optlen;
0561 
0562     switch (optname) {
0563     case MCAST_JOIN_GROUP:
0564     case MCAST_LEAVE_GROUP:
0565     {
0566         struct compat_group_req __user *gr32 = (void *)optval;
0567         struct group_req __user *kgr =
0568             compat_alloc_user_space(sizeof(struct group_req));
0569         u32 interface;
0570 
0571         if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) ||
0572             !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) ||
0573             __get_user(interface, &gr32->gr_interface) ||
0574             __put_user(interface, &kgr->gr_interface) ||
0575             copy_in_user(&kgr->gr_group, &gr32->gr_group,
0576                 sizeof(kgr->gr_group)))
0577             return -EFAULT;
0578         koptval = (char __user *)kgr;
0579         koptlen = sizeof(struct group_req);
0580         break;
0581     }
0582     case MCAST_JOIN_SOURCE_GROUP:
0583     case MCAST_LEAVE_SOURCE_GROUP:
0584     case MCAST_BLOCK_SOURCE:
0585     case MCAST_UNBLOCK_SOURCE:
0586     {
0587         struct compat_group_source_req __user *gsr32 = (void *)optval;
0588         struct group_source_req __user *kgsr = compat_alloc_user_space(
0589             sizeof(struct group_source_req));
0590         u32 interface;
0591 
0592         if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) ||
0593             !access_ok(VERIFY_WRITE, kgsr,
0594             sizeof(struct group_source_req)) ||
0595             __get_user(interface, &gsr32->gsr_interface) ||
0596             __put_user(interface, &kgsr->gsr_interface) ||
0597             copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
0598                 sizeof(kgsr->gsr_group)) ||
0599             copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
0600                 sizeof(kgsr->gsr_source)))
0601             return -EFAULT;
0602         koptval = (char __user *)kgsr;
0603         koptlen = sizeof(struct group_source_req);
0604         break;
0605     }
0606     case MCAST_MSFILTER:
0607     {
0608         struct compat_group_filter __user *gf32 = (void *)optval;
0609         struct group_filter __user *kgf;
0610         u32 interface, fmode, numsrc;
0611 
0612         if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
0613             __get_user(interface, &gf32->gf_interface) ||
0614             __get_user(fmode, &gf32->gf_fmode) ||
0615             __get_user(numsrc, &gf32->gf_numsrc))
0616             return -EFAULT;
0617         koptlen = optlen + sizeof(struct group_filter) -
0618                 sizeof(struct compat_group_filter);
0619         if (koptlen < GROUP_FILTER_SIZE(numsrc))
0620             return -EINVAL;
0621         kgf = compat_alloc_user_space(koptlen);
0622         if (!access_ok(VERIFY_WRITE, kgf, koptlen) ||
0623             __put_user(interface, &kgf->gf_interface) ||
0624             __put_user(fmode, &kgf->gf_fmode) ||
0625             __put_user(numsrc, &kgf->gf_numsrc) ||
0626             copy_in_user(&kgf->gf_group, &gf32->gf_group,
0627                 sizeof(kgf->gf_group)) ||
0628             (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
0629                 numsrc * sizeof(kgf->gf_slist[0]))))
0630             return -EFAULT;
0631         koptval = (char __user *)kgf;
0632         break;
0633     }
0634 
0635     default:
0636         break;
0637     }
0638     return setsockopt(sock, level, optname, koptval, koptlen);
0639 }
0640 EXPORT_SYMBOL(compat_mc_setsockopt);
0641 
0642 int compat_mc_getsockopt(struct sock *sock, int level, int optname,
0643     char __user *optval, int __user *optlen,
0644     int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
0645 {
0646     struct compat_group_filter __user *gf32 = (void *)optval;
0647     struct group_filter __user *kgf;
0648     int __user  *koptlen;
0649     u32 interface, fmode, numsrc;
0650     int klen, ulen, err;
0651 
0652     if (optname != MCAST_MSFILTER)
0653         return getsockopt(sock, level, optname, optval, optlen);
0654 
0655     koptlen = compat_alloc_user_space(sizeof(*koptlen));
0656     if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
0657         __get_user(ulen, optlen))
0658         return -EFAULT;
0659 
0660     /* adjust len for pad */
0661     klen = ulen + sizeof(*kgf) - sizeof(*gf32);
0662 
0663     if (klen < GROUP_FILTER_SIZE(0))
0664         return -EINVAL;
0665 
0666     if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
0667         __put_user(klen, koptlen))
0668         return -EFAULT;
0669 
0670     /* have to allow space for previous compat_alloc_user_space, too */
0671     kgf = compat_alloc_user_space(klen+sizeof(*optlen));
0672 
0673     if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
0674         __get_user(interface, &gf32->gf_interface) ||
0675         __get_user(fmode, &gf32->gf_fmode) ||
0676         __get_user(numsrc, &gf32->gf_numsrc) ||
0677         __put_user(interface, &kgf->gf_interface) ||
0678         __put_user(fmode, &kgf->gf_fmode) ||
0679         __put_user(numsrc, &kgf->gf_numsrc) ||
0680         copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
0681         return -EFAULT;
0682 
0683     err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
0684     if (err)
0685         return err;
0686 
0687     if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
0688         __get_user(klen, koptlen))
0689         return -EFAULT;
0690 
0691     ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
0692 
0693     if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
0694         __put_user(ulen, optlen))
0695         return -EFAULT;
0696 
0697     if (!access_ok(VERIFY_READ, kgf, klen) ||
0698         !access_ok(VERIFY_WRITE, gf32, ulen) ||
0699         __get_user(interface, &kgf->gf_interface) ||
0700         __get_user(fmode, &kgf->gf_fmode) ||
0701         __get_user(numsrc, &kgf->gf_numsrc) ||
0702         __put_user(interface, &gf32->gf_interface) ||
0703         __put_user(fmode, &gf32->gf_fmode) ||
0704         __put_user(numsrc, &gf32->gf_numsrc))
0705         return -EFAULT;
0706     if (numsrc) {
0707         int copylen;
0708 
0709         klen -= GROUP_FILTER_SIZE(0);
0710         copylen = numsrc * sizeof(gf32->gf_slist[0]);
0711         if (copylen > klen)
0712             copylen = klen;
0713         if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
0714             return -EFAULT;
0715     }
0716     return err;
0717 }
0718 EXPORT_SYMBOL(compat_mc_getsockopt);
0719 
0720 
0721 /* Argument list sizes for compat_sys_socketcall */
0722 #define AL(x) ((x) * sizeof(u32))
0723 static unsigned char nas[21] = {
0724     AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
0725     AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
0726     AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
0727     AL(4), AL(5), AL(4)
0728 };
0729 #undef AL
0730 
0731 COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
0732 {
0733     return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
0734 }
0735 
0736 COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
0737                unsigned int, vlen, unsigned int, flags)
0738 {
0739     return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
0740                   flags | MSG_CMSG_COMPAT);
0741 }
0742 
0743 COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
0744 {
0745     return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
0746 }
0747 
0748 COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
0749 {
0750     return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
0751 }
0752 
0753 COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
0754                unsigned int, flags, struct sockaddr __user *, addr,
0755                int __user *, addrlen)
0756 {
0757     return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
0758 }
0759 
0760 COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
0761                unsigned int, vlen, unsigned int, flags,
0762                struct compat_timespec __user *, timeout)
0763 {
0764     int datagrams;
0765     struct timespec ktspec;
0766 
0767     if (timeout == NULL)
0768         return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
0769                       flags | MSG_CMSG_COMPAT, NULL);
0770 
0771     if (compat_get_timespec(&ktspec, timeout))
0772         return -EFAULT;
0773 
0774     datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
0775                    flags | MSG_CMSG_COMPAT, &ktspec);
0776     if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
0777         datagrams = -EFAULT;
0778 
0779     return datagrams;
0780 }
0781 
0782 COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
0783 {
0784     int ret;
0785     u32 a[6];
0786     u32 a0, a1;
0787 
0788     if (call < SYS_SOCKET || call > SYS_SENDMMSG)
0789         return -EINVAL;
0790     if (copy_from_user(a, args, nas[call]))
0791         return -EFAULT;
0792     a0 = a[0];
0793     a1 = a[1];
0794 
0795     switch (call) {
0796     case SYS_SOCKET:
0797         ret = sys_socket(a0, a1, a[2]);
0798         break;
0799     case SYS_BIND:
0800         ret = sys_bind(a0, compat_ptr(a1), a[2]);
0801         break;
0802     case SYS_CONNECT:
0803         ret = sys_connect(a0, compat_ptr(a1), a[2]);
0804         break;
0805     case SYS_LISTEN:
0806         ret = sys_listen(a0, a1);
0807         break;
0808     case SYS_ACCEPT:
0809         ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
0810         break;
0811     case SYS_GETSOCKNAME:
0812         ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
0813         break;
0814     case SYS_GETPEERNAME:
0815         ret = sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
0816         break;
0817     case SYS_SOCKETPAIR:
0818         ret = sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
0819         break;
0820     case SYS_SEND:
0821         ret = sys_send(a0, compat_ptr(a1), a[2], a[3]);
0822         break;
0823     case SYS_SENDTO:
0824         ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
0825         break;
0826     case SYS_RECV:
0827         ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
0828         break;
0829     case SYS_RECVFROM:
0830         ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
0831                       compat_ptr(a[4]), compat_ptr(a[5]));
0832         break;
0833     case SYS_SHUTDOWN:
0834         ret = sys_shutdown(a0, a1);
0835         break;
0836     case SYS_SETSOCKOPT:
0837         ret = compat_sys_setsockopt(a0, a1, a[2],
0838                 compat_ptr(a[3]), a[4]);
0839         break;
0840     case SYS_GETSOCKOPT:
0841         ret = compat_sys_getsockopt(a0, a1, a[2],
0842                 compat_ptr(a[3]), compat_ptr(a[4]));
0843         break;
0844     case SYS_SENDMSG:
0845         ret = compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
0846         break;
0847     case SYS_SENDMMSG:
0848         ret = compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
0849         break;
0850     case SYS_RECVMSG:
0851         ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
0852         break;
0853     case SYS_RECVMMSG:
0854         ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
0855                       compat_ptr(a[4]));
0856         break;
0857     case SYS_ACCEPT4:
0858         ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
0859         break;
0860     default:
0861         ret = -EINVAL;
0862         break;
0863     }
0864     return ret;
0865 }