Root/net/compat.c

1/*
2 * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
3 *
4 * Copyright (C) 2000 VA Linux Co
5 * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
6 * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
7 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
9 * Copyright (C) 2000 Hewlett-Packard Co.
10 * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
11 * Copyright (C) 2000,2001 Andi Kleen, SuSE Labs
12 */
13
14#include <linux/kernel.h>
15#include <linux/gfp.h>
16#include <linux/fs.h>
17#include <linux/types.h>
18#include <linux/file.h>
19#include <linux/icmpv6.h>
20#include <linux/socket.h>
21#include <linux/syscalls.h>
22#include <linux/filter.h>
23#include <linux/compat.h>
24#include <linux/security.h>
25#include <linux/export.h>
26
27#include <net/scm.h>
28#include <net/sock.h>
29#include <net/ip.h>
30#include <net/ipv6.h>
31#include <asm/uaccess.h>
32#include <net/compat.h>
33
34static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
35                      struct compat_iovec __user *uiov32,
36                      int niov)
37{
38    int tot_len = 0;
39
40    while (niov > 0) {
41        compat_uptr_t buf;
42        compat_size_t len;
43
44        if (get_user(len, &uiov32->iov_len) ||
45            get_user(buf, &uiov32->iov_base))
46            return -EFAULT;
47
48        if (len > INT_MAX - tot_len)
49            len = INT_MAX - tot_len;
50
51        tot_len += len;
52        kiov->iov_base = compat_ptr(buf);
53        kiov->iov_len = (__kernel_size_t) len;
54        uiov32++;
55        kiov++;
56        niov--;
57    }
58    return tot_len;
59}
60
61int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
62{
63    compat_uptr_t tmp1, tmp2, tmp3;
64
65    if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
66        __get_user(tmp1, &umsg->msg_name) ||
67        __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
68        __get_user(tmp2, &umsg->msg_iov) ||
69        __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) ||
70        __get_user(tmp3, &umsg->msg_control) ||
71        __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
72        __get_user(kmsg->msg_flags, &umsg->msg_flags))
73        return -EFAULT;
74    kmsg->msg_name = compat_ptr(tmp1);
75    kmsg->msg_iov = compat_ptr(tmp2);
76    kmsg->msg_control = compat_ptr(tmp3);
77    return 0;
78}
79
80/* I've named the args so it is easy to tell whose space the pointers are in. */
81int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
82           struct sockaddr_storage *kern_address, int mode)
83{
84    int tot_len;
85
86    if (kern_msg->msg_namelen) {
87        if (mode == VERIFY_READ) {
88            int err = move_addr_to_kernel(kern_msg->msg_name,
89                              kern_msg->msg_namelen,
90                              kern_address);
91            if (err < 0)
92                return err;
93        }
94        kern_msg->msg_name = kern_address;
95    } else
96        kern_msg->msg_name = NULL;
97
98    tot_len = iov_from_user_compat_to_kern(kern_iov,
99                      (struct compat_iovec __user *)kern_msg->msg_iov,
100                      kern_msg->msg_iovlen);
101    if (tot_len >= 0)
102        kern_msg->msg_iov = kern_iov;
103
104    return tot_len;
105}
106
107/* Bleech... */
108#define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32))
109
110#define CMSG_COMPAT_DATA(cmsg) \
111    ((void __user *)((char __user *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
112#define CMSG_COMPAT_SPACE(len) \
113    (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
114#define CMSG_COMPAT_LEN(len) \
115    (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
116
117#define CMSG_COMPAT_FIRSTHDR(msg) \
118    (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
119     (struct compat_cmsghdr __user *)((msg)->msg_control) : \
120     (struct compat_cmsghdr __user *)NULL)
121
122#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
123    ((ucmlen) >= sizeof(struct compat_cmsghdr) && \
124     (ucmlen) <= (unsigned long) \
125     ((mhdr)->msg_controllen - \
126      ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
127
128static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
129        struct compat_cmsghdr __user *cmsg, int cmsg_len)
130{
131    char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
132    if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
133            msg->msg_controllen)
134        return NULL;
135    return (struct compat_cmsghdr __user *)ptr;
136}
137
138/* There is a lot of hair here because the alignment rules (and
139 * thus placement) of cmsg headers and length are different for
140 * 32-bit apps. -DaveM
141 */
142int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
143                   unsigned char *stackbuf, int stackbuf_size)
144{
145    struct compat_cmsghdr __user *ucmsg;
146    struct cmsghdr *kcmsg, *kcmsg_base;
147    compat_size_t ucmlen;
148    __kernel_size_t kcmlen, tmp;
149    int err = -EFAULT;
150
151    kcmlen = 0;
152    kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
153    ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
154    while (ucmsg != NULL) {
155        if (get_user(ucmlen, &ucmsg->cmsg_len))
156            return -EFAULT;
157
158        /* Catch bogons. */
159        if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
160            return -EINVAL;
161
162        tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
163               CMSG_ALIGN(sizeof(struct cmsghdr)));
164        tmp = CMSG_ALIGN(tmp);
165        kcmlen += tmp;
166        ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
167    }
168    if (kcmlen == 0)
169        return -EINVAL;
170
171    /* The kcmlen holds the 64-bit version of the control length.
172     * It may not be modified as we do not stick it into the kmsg
173     * until we have successfully copied over all of the data
174     * from the user.
175     */
176    if (kcmlen > stackbuf_size)
177        kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
178    if (kcmsg == NULL)
179        return -ENOBUFS;
180
181    /* Now copy them over neatly. */
182    memset(kcmsg, 0, kcmlen);
183    ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
184    while (ucmsg != NULL) {
185        if (__get_user(ucmlen, &ucmsg->cmsg_len))
186            goto Efault;
187        if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
188            goto Einval;
189        tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
190               CMSG_ALIGN(sizeof(struct cmsghdr)));
191        if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
192            goto Einval;
193        kcmsg->cmsg_len = tmp;
194        tmp = CMSG_ALIGN(tmp);
195        if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
196            __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
197            copy_from_user(CMSG_DATA(kcmsg),
198                   CMSG_COMPAT_DATA(ucmsg),
199                   (ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg)))))
200            goto Efault;
201
202        /* Advance. */
203        kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
204        ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
205    }
206
207    /* Ok, looks like we made it. Hook it up and return success. */
208    kmsg->msg_control = kcmsg_base;
209    kmsg->msg_controllen = kcmlen;
210    return 0;
211
212Einval:
213    err = -EINVAL;
214Efault:
215    if (kcmsg_base != (struct cmsghdr *)stackbuf)
216        sock_kfree_s(sk, kcmsg_base, kcmlen);
217    return err;
218}
219
220int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
221{
222    struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
223    struct compat_cmsghdr cmhdr;
224    struct compat_timeval ctv;
225    struct compat_timespec cts[3];
226    int cmlen;
227
228    if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
229        kmsg->msg_flags |= MSG_CTRUNC;
230        return 0; /* XXX: return error? check spec. */
231    }
232
233    if (!COMPAT_USE_64BIT_TIME) {
234        if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
235            struct timeval *tv = (struct timeval *)data;
236            ctv.tv_sec = tv->tv_sec;
237            ctv.tv_usec = tv->tv_usec;
238            data = &ctv;
239            len = sizeof(ctv);
240        }
241        if (level == SOL_SOCKET &&
242            (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
243            int count = type == SCM_TIMESTAMPNS ? 1 : 3;
244            int i;
245            struct timespec *ts = (struct timespec *)data;
246            for (i = 0; i < count; i++) {
247                cts[i].tv_sec = ts[i].tv_sec;
248                cts[i].tv_nsec = ts[i].tv_nsec;
249            }
250            data = &cts;
251            len = sizeof(cts[0]) * count;
252        }
253    }
254
255    cmlen = CMSG_COMPAT_LEN(len);
256    if (kmsg->msg_controllen < cmlen) {
257        kmsg->msg_flags |= MSG_CTRUNC;
258        cmlen = kmsg->msg_controllen;
259    }
260    cmhdr.cmsg_level = level;
261    cmhdr.cmsg_type = type;
262    cmhdr.cmsg_len = cmlen;
263
264    if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
265        return -EFAULT;
266    if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
267        return -EFAULT;
268    cmlen = CMSG_COMPAT_SPACE(len);
269    if (kmsg->msg_controllen < cmlen)
270        cmlen = kmsg->msg_controllen;
271    kmsg->msg_control += cmlen;
272    kmsg->msg_controllen -= cmlen;
273    return 0;
274}
275
276void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
277{
278    struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
279    int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
280    int fdnum = scm->fp->count;
281    struct file **fp = scm->fp->fp;
282    int __user *cmfptr;
283    int err = 0, i;
284
285    if (fdnum < fdmax)
286        fdmax = fdnum;
287
288    for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) {
289        int new_fd;
290        err = security_file_receive(fp[i]);
291        if (err)
292            break;
293        err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
294                      ? O_CLOEXEC : 0);
295        if (err < 0)
296            break;
297        new_fd = err;
298        err = put_user(new_fd, cmfptr);
299        if (err) {
300            put_unused_fd(new_fd);
301            break;
302        }
303        /* Bump the usage count and install the file. */
304        fd_install(new_fd, get_file(fp[i]));
305    }
306
307    if (i > 0) {
308        int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
309        err = put_user(SOL_SOCKET, &cm->cmsg_level);
310        if (!err)
311            err = put_user(SCM_RIGHTS, &cm->cmsg_type);
312        if (!err)
313            err = put_user(cmlen, &cm->cmsg_len);
314        if (!err) {
315            cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
316            kmsg->msg_control += cmlen;
317            kmsg->msg_controllen -= cmlen;
318        }
319    }
320    if (i < fdnum)
321        kmsg->msg_flags |= MSG_CTRUNC;
322
323    /*
324     * All of the files that fit in the message have had their
325     * usage counts incremented, so we just free the list.
326     */
327    __scm_destroy(scm);
328}
329
330static int do_set_attach_filter(struct socket *sock, int level, int optname,
331                char __user *optval, unsigned int optlen)
332{
333    struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
334    struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
335    compat_uptr_t ptr;
336    u16 len;
337
338    if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
339        !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
340        __get_user(len, &fprog32->len) ||
341        __get_user(ptr, &fprog32->filter) ||
342        __put_user(len, &kfprog->len) ||
343        __put_user(compat_ptr(ptr), &kfprog->filter))
344        return -EFAULT;
345
346    return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
347                  sizeof(struct sock_fprog));
348}
349
350static int do_set_sock_timeout(struct socket *sock, int level,
351        int optname, char __user *optval, unsigned int optlen)
352{
353    struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
354    struct timeval ktime;
355    mm_segment_t old_fs;
356    int err;
357
358    if (optlen < sizeof(*up))
359        return -EINVAL;
360    if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
361        __get_user(ktime.tv_sec, &up->tv_sec) ||
362        __get_user(ktime.tv_usec, &up->tv_usec))
363        return -EFAULT;
364    old_fs = get_fs();
365    set_fs(KERNEL_DS);
366    err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
367    set_fs(old_fs);
368
369    return err;
370}
371
372static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
373                char __user *optval, unsigned int optlen)
374{
375    if (optname == SO_ATTACH_FILTER)
376        return do_set_attach_filter(sock, level, optname,
377                        optval, optlen);
378    if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
379        return do_set_sock_timeout(sock, level, optname, optval, optlen);
380
381    return sock_setsockopt(sock, level, optname, optval, optlen);
382}
383
384asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
385                char __user *optval, unsigned int optlen)
386{
387    int err;
388    struct socket *sock = sockfd_lookup(fd, &err);
389
390    if (sock) {
391        err = security_socket_setsockopt(sock, level, optname);
392        if (err) {
393            sockfd_put(sock);
394            return err;
395        }
396
397        if (level == SOL_SOCKET)
398            err = compat_sock_setsockopt(sock, level,
399                    optname, optval, optlen);
400        else if (sock->ops->compat_setsockopt)
401            err = sock->ops->compat_setsockopt(sock, level,
402                    optname, optval, optlen);
403        else
404            err = sock->ops->setsockopt(sock, level,
405                    optname, optval, optlen);
406        sockfd_put(sock);
407    }
408    return err;
409}
410
411static int do_get_sock_timeout(struct socket *sock, int level, int optname,
412        char __user *optval, int __user *optlen)
413{
414    struct compat_timeval __user *up;
415    struct timeval ktime;
416    mm_segment_t old_fs;
417    int len, err;
418
419    up = (struct compat_timeval __user *) optval;
420    if (get_user(len, optlen))
421        return -EFAULT;
422    if (len < sizeof(*up))
423        return -EINVAL;
424    len = sizeof(ktime);
425    old_fs = get_fs();
426    set_fs(KERNEL_DS);
427    err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
428    set_fs(old_fs);
429
430    if (!err) {
431        if (put_user(sizeof(*up), optlen) ||
432            !access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
433            __put_user(ktime.tv_sec, &up->tv_sec) ||
434            __put_user(ktime.tv_usec, &up->tv_usec))
435            err = -EFAULT;
436    }
437    return err;
438}
439
440static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
441                char __user *optval, int __user *optlen)
442{
443    if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
444        return do_get_sock_timeout(sock, level, optname, optval, optlen);
445    return sock_getsockopt(sock, level, optname, optval, optlen);
446}
447
448int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
449{
450    struct compat_timeval __user *ctv;
451    int err;
452    struct timeval tv;
453
454    if (COMPAT_USE_64BIT_TIME)
455        return sock_get_timestamp(sk, userstamp);
456
457    ctv = (struct compat_timeval __user *) userstamp;
458    err = -ENOENT;
459    if (!sock_flag(sk, SOCK_TIMESTAMP))
460        sock_enable_timestamp(sk, SOCK_TIMESTAMP);
461    tv = ktime_to_timeval(sk->sk_stamp);
462    if (tv.tv_sec == -1)
463        return err;
464    if (tv.tv_sec == 0) {
465        sk->sk_stamp = ktime_get_real();
466        tv = ktime_to_timeval(sk->sk_stamp);
467    }
468    err = 0;
469    if (put_user(tv.tv_sec, &ctv->tv_sec) ||
470            put_user(tv.tv_usec, &ctv->tv_usec))
471        err = -EFAULT;
472    return err;
473}
474EXPORT_SYMBOL(compat_sock_get_timestamp);
475
476int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
477{
478    struct compat_timespec __user *ctv;
479    int err;
480    struct timespec ts;
481
482    if (COMPAT_USE_64BIT_TIME)
483        return sock_get_timestampns (sk, userstamp);
484
485    ctv = (struct compat_timespec __user *) userstamp;
486    err = -ENOENT;
487    if (!sock_flag(sk, SOCK_TIMESTAMP))
488        sock_enable_timestamp(sk, SOCK_TIMESTAMP);
489    ts = ktime_to_timespec(sk->sk_stamp);
490    if (ts.tv_sec == -1)
491        return err;
492    if (ts.tv_sec == 0) {
493        sk->sk_stamp = ktime_get_real();
494        ts = ktime_to_timespec(sk->sk_stamp);
495    }
496    err = 0;
497    if (put_user(ts.tv_sec, &ctv->tv_sec) ||
498            put_user(ts.tv_nsec, &ctv->tv_nsec))
499        err = -EFAULT;
500    return err;
501}
502EXPORT_SYMBOL(compat_sock_get_timestampns);
503
504asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
505                char __user *optval, int __user *optlen)
506{
507    int err;
508    struct socket *sock = sockfd_lookup(fd, &err);
509
510    if (sock) {
511        err = security_socket_getsockopt(sock, level, optname);
512        if (err) {
513            sockfd_put(sock);
514            return err;
515        }
516
517        if (level == SOL_SOCKET)
518            err = compat_sock_getsockopt(sock, level,
519                    optname, optval, optlen);
520        else if (sock->ops->compat_getsockopt)
521            err = sock->ops->compat_getsockopt(sock, level,
522                    optname, optval, optlen);
523        else
524            err = sock->ops->getsockopt(sock, level,
525                    optname, optval, optlen);
526        sockfd_put(sock);
527    }
528    return err;
529}
530
531struct compat_group_req {
532    __u32 gr_interface;
533    struct __kernel_sockaddr_storage gr_group
534        __attribute__ ((aligned(4)));
535} __packed;
536
537struct compat_group_source_req {
538    __u32 gsr_interface;
539    struct __kernel_sockaddr_storage gsr_group
540        __attribute__ ((aligned(4)));
541    struct __kernel_sockaddr_storage gsr_source
542        __attribute__ ((aligned(4)));
543} __packed;
544
545struct compat_group_filter {
546    __u32 gf_interface;
547    struct __kernel_sockaddr_storage gf_group
548        __attribute__ ((aligned(4)));
549    __u32 gf_fmode;
550    __u32 gf_numsrc;
551    struct __kernel_sockaddr_storage gf_slist[1]
552        __attribute__ ((aligned(4)));
553} __packed;
554
555#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
556            sizeof(struct __kernel_sockaddr_storage))
557
558
559int compat_mc_setsockopt(struct sock *sock, int level, int optname,
560    char __user *optval, unsigned int optlen,
561    int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
562{
563    char __user *koptval = optval;
564    int koptlen = optlen;
565
566    switch (optname) {
567    case MCAST_JOIN_GROUP:
568    case MCAST_LEAVE_GROUP:
569    {
570        struct compat_group_req __user *gr32 = (void *)optval;
571        struct group_req __user *kgr =
572            compat_alloc_user_space(sizeof(struct group_req));
573        u32 interface;
574
575        if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) ||
576            !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) ||
577            __get_user(interface, &gr32->gr_interface) ||
578            __put_user(interface, &kgr->gr_interface) ||
579            copy_in_user(&kgr->gr_group, &gr32->gr_group,
580                sizeof(kgr->gr_group)))
581            return -EFAULT;
582        koptval = (char __user *)kgr;
583        koptlen = sizeof(struct group_req);
584        break;
585    }
586    case MCAST_JOIN_SOURCE_GROUP:
587    case MCAST_LEAVE_SOURCE_GROUP:
588    case MCAST_BLOCK_SOURCE:
589    case MCAST_UNBLOCK_SOURCE:
590    {
591        struct compat_group_source_req __user *gsr32 = (void *)optval;
592        struct group_source_req __user *kgsr = compat_alloc_user_space(
593            sizeof(struct group_source_req));
594        u32 interface;
595
596        if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) ||
597            !access_ok(VERIFY_WRITE, kgsr,
598            sizeof(struct group_source_req)) ||
599            __get_user(interface, &gsr32->gsr_interface) ||
600            __put_user(interface, &kgsr->gsr_interface) ||
601            copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
602                sizeof(kgsr->gsr_group)) ||
603            copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
604                sizeof(kgsr->gsr_source)))
605            return -EFAULT;
606        koptval = (char __user *)kgsr;
607        koptlen = sizeof(struct group_source_req);
608        break;
609    }
610    case MCAST_MSFILTER:
611    {
612        struct compat_group_filter __user *gf32 = (void *)optval;
613        struct group_filter __user *kgf;
614        u32 interface, fmode, numsrc;
615
616        if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
617            __get_user(interface, &gf32->gf_interface) ||
618            __get_user(fmode, &gf32->gf_fmode) ||
619            __get_user(numsrc, &gf32->gf_numsrc))
620            return -EFAULT;
621        koptlen = optlen + sizeof(struct group_filter) -
622                sizeof(struct compat_group_filter);
623        if (koptlen < GROUP_FILTER_SIZE(numsrc))
624            return -EINVAL;
625        kgf = compat_alloc_user_space(koptlen);
626        if (!access_ok(VERIFY_WRITE, kgf, koptlen) ||
627            __put_user(interface, &kgf->gf_interface) ||
628            __put_user(fmode, &kgf->gf_fmode) ||
629            __put_user(numsrc, &kgf->gf_numsrc) ||
630            copy_in_user(&kgf->gf_group, &gf32->gf_group,
631                sizeof(kgf->gf_group)) ||
632            (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
633                numsrc * sizeof(kgf->gf_slist[0]))))
634            return -EFAULT;
635        koptval = (char __user *)kgf;
636        break;
637    }
638
639    default:
640        break;
641    }
642    return setsockopt(sock, level, optname, koptval, koptlen);
643}
644EXPORT_SYMBOL(compat_mc_setsockopt);
645
646int compat_mc_getsockopt(struct sock *sock, int level, int optname,
647    char __user *optval, int __user *optlen,
648    int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
649{
650    struct compat_group_filter __user *gf32 = (void *)optval;
651    struct group_filter __user *kgf;
652    int __user *koptlen;
653    u32 interface, fmode, numsrc;
654    int klen, ulen, err;
655
656    if (optname != MCAST_MSFILTER)
657        return getsockopt(sock, level, optname, optval, optlen);
658
659    koptlen = compat_alloc_user_space(sizeof(*koptlen));
660    if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
661        __get_user(ulen, optlen))
662        return -EFAULT;
663
664    /* adjust len for pad */
665    klen = ulen + sizeof(*kgf) - sizeof(*gf32);
666
667    if (klen < GROUP_FILTER_SIZE(0))
668        return -EINVAL;
669
670    if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
671        __put_user(klen, koptlen))
672        return -EFAULT;
673
674    /* have to allow space for previous compat_alloc_user_space, too */
675    kgf = compat_alloc_user_space(klen+sizeof(*optlen));
676
677    if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
678        __get_user(interface, &gf32->gf_interface) ||
679        __get_user(fmode, &gf32->gf_fmode) ||
680        __get_user(numsrc, &gf32->gf_numsrc) ||
681        __put_user(interface, &kgf->gf_interface) ||
682        __put_user(fmode, &kgf->gf_fmode) ||
683        __put_user(numsrc, &kgf->gf_numsrc) ||
684        copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
685        return -EFAULT;
686
687    err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
688    if (err)
689        return err;
690
691    if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
692        __get_user(klen, koptlen))
693        return -EFAULT;
694
695    ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
696
697    if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
698        __put_user(ulen, optlen))
699        return -EFAULT;
700
701    if (!access_ok(VERIFY_READ, kgf, klen) ||
702        !access_ok(VERIFY_WRITE, gf32, ulen) ||
703        __get_user(interface, &kgf->gf_interface) ||
704        __get_user(fmode, &kgf->gf_fmode) ||
705        __get_user(numsrc, &kgf->gf_numsrc) ||
706        __put_user(interface, &gf32->gf_interface) ||
707        __put_user(fmode, &gf32->gf_fmode) ||
708        __put_user(numsrc, &gf32->gf_numsrc))
709        return -EFAULT;
710    if (numsrc) {
711        int copylen;
712
713        klen -= GROUP_FILTER_SIZE(0);
714        copylen = numsrc * sizeof(gf32->gf_slist[0]);
715        if (copylen > klen)
716            copylen = klen;
717        if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
718            return -EFAULT;
719    }
720    return err;
721}
722EXPORT_SYMBOL(compat_mc_getsockopt);
723
724
725/* Argument list sizes for compat_sys_socketcall */
726#define AL(x) ((x) * sizeof(u32))
727static unsigned char nas[21] = {
728    AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
729    AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
730    AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
731    AL(4), AL(5), AL(4)
732};
733#undef AL
734
735asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
736{
737    return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
738}
739
740asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
741                    unsigned int vlen, unsigned int flags)
742{
743    return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
744                  flags | MSG_CMSG_COMPAT);
745}
746
747asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
748{
749    return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
750}
751
752asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
753{
754    return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
755}
756
757asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
758                    unsigned int flags, struct sockaddr __user *addr,
759                    int __user *addrlen)
760{
761    return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
762}
763
764asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
765                    unsigned int vlen, unsigned int flags,
766                    struct compat_timespec __user *timeout)
767{
768    int datagrams;
769    struct timespec ktspec;
770
771    if (COMPAT_USE_64BIT_TIME)
772        return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
773                      flags | MSG_CMSG_COMPAT,
774                      (struct timespec *) timeout);
775
776    if (timeout == NULL)
777        return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
778                      flags | MSG_CMSG_COMPAT, NULL);
779
780    if (get_compat_timespec(&ktspec, timeout))
781        return -EFAULT;
782
783    datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
784                   flags | MSG_CMSG_COMPAT, &ktspec);
785    if (datagrams > 0 && put_compat_timespec(&ktspec, timeout))
786        datagrams = -EFAULT;
787
788    return datagrams;
789}
790
791asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
792{
793    int ret;
794    u32 a[6];
795    u32 a0, a1;
796
797    if (call < SYS_SOCKET || call > SYS_SENDMMSG)
798        return -EINVAL;
799    if (copy_from_user(a, args, nas[call]))
800        return -EFAULT;
801    a0 = a[0];
802    a1 = a[1];
803
804    switch (call) {
805    case SYS_SOCKET:
806        ret = sys_socket(a0, a1, a[2]);
807        break;
808    case SYS_BIND:
809        ret = sys_bind(a0, compat_ptr(a1), a[2]);
810        break;
811    case SYS_CONNECT:
812        ret = sys_connect(a0, compat_ptr(a1), a[2]);
813        break;
814    case SYS_LISTEN:
815        ret = sys_listen(a0, a1);
816        break;
817    case SYS_ACCEPT:
818        ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
819        break;
820    case SYS_GETSOCKNAME:
821        ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
822        break;
823    case SYS_GETPEERNAME:
824        ret = sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
825        break;
826    case SYS_SOCKETPAIR:
827        ret = sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
828        break;
829    case SYS_SEND:
830        ret = sys_send(a0, compat_ptr(a1), a[2], a[3]);
831        break;
832    case SYS_SENDTO:
833        ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
834        break;
835    case SYS_RECV:
836        ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
837        break;
838    case SYS_RECVFROM:
839        ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
840                      compat_ptr(a[4]), compat_ptr(a[5]));
841        break;
842    case SYS_SHUTDOWN:
843        ret = sys_shutdown(a0, a1);
844        break;
845    case SYS_SETSOCKOPT:
846        ret = compat_sys_setsockopt(a0, a1, a[2],
847                compat_ptr(a[3]), a[4]);
848        break;
849    case SYS_GETSOCKOPT:
850        ret = compat_sys_getsockopt(a0, a1, a[2],
851                compat_ptr(a[3]), compat_ptr(a[4]));
852        break;
853    case SYS_SENDMSG:
854        ret = compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
855        break;
856    case SYS_SENDMMSG:
857        ret = compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
858        break;
859    case SYS_RECVMSG:
860        ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
861        break;
862    case SYS_RECVMMSG:
863        ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
864                      compat_ptr(a[4]));
865        break;
866    case SYS_ACCEPT4:
867        ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
868        break;
869    default:
870        ret = -EINVAL;
871        break;
872    }
873    return ret;
874}
875

Archive Download this file



interactive