1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2000 VA Linux Co
61da177e4SLinus Torvalds * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
71da177e4SLinus Torvalds * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
81da177e4SLinus Torvalds * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
91da177e4SLinus Torvalds * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
101da177e4SLinus Torvalds * Copyright (C) 2000 Hewlett-Packard Co.
111da177e4SLinus Torvalds * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
121da177e4SLinus Torvalds * Copyright (C) 2000,2001 Andi Kleen, SuSE Labs
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds #include <linux/kernel.h>
165a0e3ad6STejun Heo #include <linux/gfp.h>
171da177e4SLinus Torvalds #include <linux/fs.h>
181da177e4SLinus Torvalds #include <linux/types.h>
191da177e4SLinus Torvalds #include <linux/file.h>
201da177e4SLinus Torvalds #include <linux/icmpv6.h>
211da177e4SLinus Torvalds #include <linux/socket.h>
221da177e4SLinus Torvalds #include <linux/syscalls.h>
231da177e4SLinus Torvalds #include <linux/filter.h>
241da177e4SLinus Torvalds #include <linux/compat.h>
251da177e4SLinus Torvalds #include <linux/security.h>
2662bc306eSRichard Guy Briggs #include <linux/audit.h>
27bc3b2d7fSPaul Gortmaker #include <linux/export.h>
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds #include <net/scm.h>
301da177e4SLinus Torvalds #include <net/sock.h>
31dae50295SDavid L Stevens #include <net/ip.h>
32dae50295SDavid L Stevens #include <net/ipv6.h>
337c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
341da177e4SLinus Torvalds #include <net/compat.h>
351da177e4SLinus Torvalds
__get_compat_msghdr(struct msghdr * kmsg,struct compat_msghdr * msg,struct sockaddr __user ** save_addr)360a384abfSJens Axboe int __get_compat_msghdr(struct msghdr *kmsg,
3772c531f8SDylan Yudaken struct compat_msghdr *msg,
3872c531f8SDylan Yudaken struct sockaddr __user **save_addr)
391da177e4SLinus Torvalds {
4008adb7daSAl Viro ssize_t err;
411da177e4SLinus Torvalds
4272c531f8SDylan Yudaken kmsg->msg_flags = msg->msg_flags;
4372c531f8SDylan Yudaken kmsg->msg_namelen = msg->msg_namelen;
4491edd096SCatalin Marinas
4572c531f8SDylan Yudaken if (!msg->msg_name)
4691edd096SCatalin Marinas kmsg->msg_namelen = 0;
4791edd096SCatalin Marinas
4891edd096SCatalin Marinas if (kmsg->msg_namelen < 0)
4991edd096SCatalin Marinas return -EINVAL;
5091edd096SCatalin Marinas
511661bf36SDan Carpenter if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
52db31c55aSDan Carpenter kmsg->msg_namelen = sizeof(struct sockaddr_storage);
535da028a8SAl Viro
541f466e1fSChristoph Hellwig kmsg->msg_control_is_user = true;
55d547c1b7STetsuo Handa kmsg->msg_get_inq = 0;
5672c531f8SDylan Yudaken kmsg->msg_control_user = compat_ptr(msg->msg_control);
5772c531f8SDylan Yudaken kmsg->msg_controllen = msg->msg_controllen;
581da177e4SLinus Torvalds
5908adb7daSAl Viro if (save_addr)
6072c531f8SDylan Yudaken *save_addr = compat_ptr(msg->msg_name);
611da177e4SLinus Torvalds
6272c531f8SDylan Yudaken if (msg->msg_name && kmsg->msg_namelen) {
6308adb7daSAl Viro if (!save_addr) {
6472c531f8SDylan Yudaken err = move_addr_to_kernel(compat_ptr(msg->msg_name),
6508adb7daSAl Viro kmsg->msg_namelen,
6608adb7daSAl Viro kmsg->msg_name);
671da177e4SLinus Torvalds if (err < 0)
681da177e4SLinus Torvalds return err;
691da177e4SLinus Torvalds }
7040eea803SAndrey Ryabinin } else {
7108adb7daSAl Viro kmsg->msg_name = NULL;
7208adb7daSAl Viro kmsg->msg_namelen = 0;
7340eea803SAndrey Ryabinin }
741da177e4SLinus Torvalds
7572c531f8SDylan Yudaken if (msg->msg_iovlen > UIO_MAXIOV)
7608449320SAl Viro return -EMSGSIZE;
771da177e4SLinus Torvalds
780345f931Stadeusz.struk@intel.com kmsg->msg_iocb = NULL;
797c701d92SPavel Begunkov kmsg->msg_ubuf = NULL;
800a384abfSJens Axboe return 0;
810a384abfSJens Axboe }
820345f931Stadeusz.struk@intel.com
get_compat_msghdr(struct msghdr * kmsg,struct compat_msghdr __user * umsg,struct sockaddr __user ** save_addr,struct iovec ** iov)830a384abfSJens Axboe int get_compat_msghdr(struct msghdr *kmsg,
840a384abfSJens Axboe struct compat_msghdr __user *umsg,
850a384abfSJens Axboe struct sockaddr __user **save_addr,
860a384abfSJens Axboe struct iovec **iov)
870a384abfSJens Axboe {
8872c531f8SDylan Yudaken struct compat_msghdr msg;
890a384abfSJens Axboe ssize_t err;
900a384abfSJens Axboe
9172c531f8SDylan Yudaken if (copy_from_user(&msg, umsg, sizeof(*umsg)))
9272c531f8SDylan Yudaken return -EFAULT;
9372c531f8SDylan Yudaken
944f6a94d3SJens Axboe err = __get_compat_msghdr(kmsg, &msg, save_addr);
950a384abfSJens Axboe if (err)
960a384abfSJens Axboe return err;
970a384abfSJens Axboe
98de4eda9dSAl Viro err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE,
99de4eda9dSAl Viro compat_ptr(msg.msg_iov), msg.msg_iovlen,
10089cd35c5SChristoph Hellwig UIO_FASTIOV, iov, &kmsg->msg_iter);
10187e5e6daSJens Axboe return err < 0 ? err : 0;
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds /* Bleech... */
1051da177e4SLinus Torvalds #define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32))
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds #define CMSG_COMPAT_DATA(cmsg) \
1081ff8cebfSyuan linyu ((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr)))
1091da177e4SLinus Torvalds #define CMSG_COMPAT_SPACE(len) \
1101ff8cebfSyuan linyu (sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len))
1111da177e4SLinus Torvalds #define CMSG_COMPAT_LEN(len) \
1121ff8cebfSyuan linyu (sizeof(struct compat_cmsghdr) + (len))
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds #define CMSG_COMPAT_FIRSTHDR(msg) \
1151da177e4SLinus Torvalds (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
116c39ef213SKevin Brodsky (struct compat_cmsghdr __user *)((msg)->msg_control_user) : \
1171da177e4SLinus Torvalds (struct compat_cmsghdr __user *)NULL)
1181da177e4SLinus Torvalds
1191da177e4SLinus Torvalds #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
1201da177e4SLinus Torvalds ((ucmlen) >= sizeof(struct compat_cmsghdr) && \
1211da177e4SLinus Torvalds (ucmlen) <= (unsigned long) \
1221da177e4SLinus Torvalds ((mhdr)->msg_controllen - \
1231f466e1fSChristoph Hellwig ((char __user *)(ucmsg) - (char __user *)(mhdr)->msg_control_user)))
1241da177e4SLinus Torvalds
cmsg_compat_nxthdr(struct msghdr * msg,struct compat_cmsghdr __user * cmsg,int cmsg_len)1251da177e4SLinus Torvalds static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
1261da177e4SLinus Torvalds struct compat_cmsghdr __user *cmsg, int cmsg_len)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
129c39ef213SKevin Brodsky if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control_user) >
1301da177e4SLinus Torvalds msg->msg_controllen)
1311da177e4SLinus Torvalds return NULL;
1321da177e4SLinus Torvalds return (struct compat_cmsghdr __user *)ptr;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds /* There is a lot of hair here because the alignment rules (and
1361da177e4SLinus Torvalds * thus placement) of cmsg headers and length are different for
1371da177e4SLinus Torvalds * 32-bit apps. -DaveM
1381da177e4SLinus Torvalds */
cmsghdr_from_user_compat_to_kern(struct msghdr * kmsg,struct sock * sk,unsigned char * stackbuf,int stackbuf_size)1398920e8f9SAl Viro int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
1401da177e4SLinus Torvalds unsigned char *stackbuf, int stackbuf_size)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds struct compat_cmsghdr __user *ucmsg;
1431da177e4SLinus Torvalds struct cmsghdr *kcmsg, *kcmsg_base;
1441da177e4SLinus Torvalds compat_size_t ucmlen;
1451da177e4SLinus Torvalds __kernel_size_t kcmlen, tmp;
1468920e8f9SAl Viro int err = -EFAULT;
1471da177e4SLinus Torvalds
148ac4340fcSDavid S. Miller BUILD_BUG_ON(sizeof(struct compat_cmsghdr) !=
149ac4340fcSDavid S. Miller CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)));
150ac4340fcSDavid S. Miller
1511da177e4SLinus Torvalds kcmlen = 0;
1521da177e4SLinus Torvalds kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
1531da177e4SLinus Torvalds ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
1541da177e4SLinus Torvalds while (ucmsg != NULL) {
1551da177e4SLinus Torvalds if (get_user(ucmlen, &ucmsg->cmsg_len))
1561da177e4SLinus Torvalds return -EFAULT;
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds /* Catch bogons. */
1591da177e4SLinus Torvalds if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
1601da177e4SLinus Torvalds return -EINVAL;
1611da177e4SLinus Torvalds
1621ff8cebfSyuan linyu tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
1638920e8f9SAl Viro tmp = CMSG_ALIGN(tmp);
1641da177e4SLinus Torvalds kcmlen += tmp;
1651da177e4SLinus Torvalds ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds if (kcmlen == 0)
1681da177e4SLinus Torvalds return -EINVAL;
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds /* The kcmlen holds the 64-bit version of the control length.
1711da177e4SLinus Torvalds * It may not be modified as we do not stick it into the kmsg
1721da177e4SLinus Torvalds * until we have successfully copied over all of the data
1731da177e4SLinus Torvalds * from the user.
1741da177e4SLinus Torvalds */
1751da177e4SLinus Torvalds if (kcmlen > stackbuf_size)
1768920e8f9SAl Viro kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
1771da177e4SLinus Torvalds if (kcmsg == NULL)
17849251cd0SZheng Yongjun return -ENOMEM;
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds /* Now copy them over neatly. */
1811da177e4SLinus Torvalds memset(kcmsg, 0, kcmlen);
1821da177e4SLinus Torvalds ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
1831da177e4SLinus Torvalds while (ucmsg != NULL) {
184547ce4cfSAl Viro struct compat_cmsghdr cmsg;
185547ce4cfSAl Viro if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg)))
1868920e8f9SAl Viro goto Efault;
187547ce4cfSAl Viro if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg))
1888920e8f9SAl Viro goto Einval;
189547ce4cfSAl Viro tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
1908920e8f9SAl Viro if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
1918920e8f9SAl Viro goto Einval;
1921da177e4SLinus Torvalds kcmsg->cmsg_len = tmp;
193547ce4cfSAl Viro kcmsg->cmsg_level = cmsg.cmsg_level;
194547ce4cfSAl Viro kcmsg->cmsg_type = cmsg.cmsg_type;
1958920e8f9SAl Viro tmp = CMSG_ALIGN(tmp);
196547ce4cfSAl Viro if (copy_from_user(CMSG_DATA(kcmsg),
1971da177e4SLinus Torvalds CMSG_COMPAT_DATA(ucmsg),
198547ce4cfSAl Viro (cmsg.cmsg_len - sizeof(*ucmsg))))
1998920e8f9SAl Viro goto Efault;
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds /* Advance. */
2028920e8f9SAl Viro kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
203181964e6SAl Viro ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, cmsg.cmsg_len);
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds
206c2a64bb9SMeng Xu /*
207c2a64bb9SMeng Xu * check the length of messages copied in is the same as the
208c2a64bb9SMeng Xu * what we get from the first loop
209c2a64bb9SMeng Xu */
210c2a64bb9SMeng Xu if ((char *)kcmsg - (char *)kcmsg_base != kcmlen)
211c2a64bb9SMeng Xu goto Einval;
212c2a64bb9SMeng Xu
2131da177e4SLinus Torvalds /* Ok, looks like we made it. Hook it up and return success. */
214*60daf8d4SKevin Brodsky kmsg->msg_control_is_user = false;
2151da177e4SLinus Torvalds kmsg->msg_control = kcmsg_base;
2161da177e4SLinus Torvalds kmsg->msg_controllen = kcmlen;
2171da177e4SLinus Torvalds return 0;
2181da177e4SLinus Torvalds
2198920e8f9SAl Viro Einval:
2208920e8f9SAl Viro err = -EINVAL;
2218920e8f9SAl Viro Efault:
2221da177e4SLinus Torvalds if (kcmsg_base != (struct cmsghdr *)stackbuf)
2238920e8f9SAl Viro sock_kfree_s(sk, kcmsg_base, kcmlen);
2248920e8f9SAl Viro return err;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds
put_cmsg_compat(struct msghdr * kmsg,int level,int type,int len,void * data)2271da177e4SLinus Torvalds int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
2281da177e4SLinus Torvalds {
229c39ef213SKevin Brodsky struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control_user;
2301da177e4SLinus Torvalds struct compat_cmsghdr cmhdr;
23113c6ee2aSDeepa Dinamani struct old_timeval32 ctv;
23213c6ee2aSDeepa Dinamani struct old_timespec32 cts[3];
2331da177e4SLinus Torvalds int cmlen;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
2361da177e4SLinus Torvalds kmsg->msg_flags |= MSG_CTRUNC;
2371da177e4SLinus Torvalds return 0; /* XXX: return error? check spec. */
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds
240ee4fa23cSH. J. Lu if (!COMPAT_USE_64BIT_TIME) {
2417f1bc6e9SDeepa Dinamani if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) {
24213c6ee2aSDeepa Dinamani struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data;
2431da177e4SLinus Torvalds ctv.tv_sec = tv->tv_sec;
2441da177e4SLinus Torvalds ctv.tv_usec = tv->tv_usec;
2451da177e4SLinus Torvalds data = &ctv;
24692f37fd2SEric Dumazet len = sizeof(ctv);
24792f37fd2SEric Dumazet }
24820d49473SPatrick Ohly if (level == SOL_SOCKET &&
2497f1bc6e9SDeepa Dinamani (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) {
2507f1bc6e9SDeepa Dinamani int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3;
25120d49473SPatrick Ohly int i;
252df1b4ba9SArnd Bergmann struct __kernel_old_timespec *ts = data;
25320d49473SPatrick Ohly for (i = 0; i < count; i++) {
25420d49473SPatrick Ohly cts[i].tv_sec = ts[i].tv_sec;
25520d49473SPatrick Ohly cts[i].tv_nsec = ts[i].tv_nsec;
25620d49473SPatrick Ohly }
25792f37fd2SEric Dumazet data = &cts;
25820d49473SPatrick Ohly len = sizeof(cts[0]) * count;
2591da177e4SLinus Torvalds }
260ee4fa23cSH. J. Lu }
2611da177e4SLinus Torvalds
2621da177e4SLinus Torvalds cmlen = CMSG_COMPAT_LEN(len);
2631da177e4SLinus Torvalds if (kmsg->msg_controllen < cmlen) {
2641da177e4SLinus Torvalds kmsg->msg_flags |= MSG_CTRUNC;
2651da177e4SLinus Torvalds cmlen = kmsg->msg_controllen;
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds cmhdr.cmsg_level = level;
2681da177e4SLinus Torvalds cmhdr.cmsg_type = type;
2691da177e4SLinus Torvalds cmhdr.cmsg_len = cmlen;
2701da177e4SLinus Torvalds
2711da177e4SLinus Torvalds if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
2721da177e4SLinus Torvalds return -EFAULT;
2731da177e4SLinus Torvalds if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
2741da177e4SLinus Torvalds return -EFAULT;
2751da177e4SLinus Torvalds cmlen = CMSG_COMPAT_SPACE(len);
2761ac70e7aSWei Yongjun if (kmsg->msg_controllen < cmlen)
2771ac70e7aSWei Yongjun cmlen = kmsg->msg_controllen;
278c39ef213SKevin Brodsky kmsg->msg_control_user += cmlen;
2791da177e4SLinus Torvalds kmsg->msg_controllen -= cmlen;
2801da177e4SLinus Torvalds return 0;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds
scm_max_fds_compat(struct msghdr * msg)283c0029de5SKees Cook static int scm_max_fds_compat(struct msghdr *msg)
2841da177e4SLinus Torvalds {
285c0029de5SKees Cook if (msg->msg_controllen <= sizeof(struct compat_cmsghdr))
286c0029de5SKees Cook return 0;
287c0029de5SKees Cook return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
288c0029de5SKees Cook }
289c0029de5SKees Cook
scm_detach_fds_compat(struct msghdr * msg,struct scm_cookie * scm)290c0029de5SKees Cook void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
291c0029de5SKees Cook {
292c0029de5SKees Cook struct compat_cmsghdr __user *cm =
293c39ef213SKevin Brodsky (struct compat_cmsghdr __user *)msg->msg_control_user;
294c0029de5SKees Cook unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
295c0029de5SKees Cook int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
29616b89f69SKees Cook int __user *cmsg_data = CMSG_COMPAT_DATA(cm);
2971da177e4SLinus Torvalds int err = 0, i;
2981da177e4SLinus Torvalds
299c0029de5SKees Cook for (i = 0; i < fdmax; i++) {
30066590610SKees Cook err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
3011da177e4SLinus Torvalds if (err < 0)
3021da177e4SLinus Torvalds break;
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds if (i > 0) {
3061da177e4SLinus Torvalds int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
307c0029de5SKees Cook
3081da177e4SLinus Torvalds err = put_user(SOL_SOCKET, &cm->cmsg_level);
3091da177e4SLinus Torvalds if (!err)
3101da177e4SLinus Torvalds err = put_user(SCM_RIGHTS, &cm->cmsg_type);
3111da177e4SLinus Torvalds if (!err)
3121da177e4SLinus Torvalds err = put_user(cmlen, &cm->cmsg_len);
3131da177e4SLinus Torvalds if (!err) {
3141da177e4SLinus Torvalds cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
315c0029de5SKees Cook if (msg->msg_controllen < cmlen)
316c0029de5SKees Cook cmlen = msg->msg_controllen;
317c39ef213SKevin Brodsky msg->msg_control_user += cmlen;
318c0029de5SKees Cook msg->msg_controllen -= cmlen;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds }
321c0029de5SKees Cook
322c0029de5SKees Cook if (i < scm->fp->count || (scm->fp->count && fdmax <= 0))
323c0029de5SKees Cook msg->msg_flags |= MSG_CTRUNC;
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds /*
326c0029de5SKees Cook * All of the files that fit in the message have had their usage counts
327c0029de5SKees Cook * incremented, so we just free the list.
3281da177e4SLinus Torvalds */
3291da177e4SLinus Torvalds __scm_destroy(scm);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds
3321da177e4SLinus Torvalds /* Argument list sizes for compat_sys_socketcall */
3331da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(u32))
334228e548eSAnton Blanchard static unsigned char nas[21] = {
335c6d409cfSEric Dumazet AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
3361da177e4SLinus Torvalds AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
337aaca0bdcSUlrich Drepper AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
338228e548eSAnton Blanchard AL(4), AL(5), AL(4)
339c6d409cfSEric Dumazet };
3401da177e4SLinus Torvalds #undef AL
3411da177e4SLinus Torvalds
__compat_sys_sendmsg(int fd,struct compat_msghdr __user * msg,unsigned int flags)3426df35465SDominik Brodowski static inline long __compat_sys_sendmsg(int fd,
3436df35465SDominik Brodowski struct compat_msghdr __user *msg,
3446df35465SDominik Brodowski unsigned int flags)
3451da177e4SLinus Torvalds {
346e1834a32SDominik Brodowski return __sys_sendmsg(fd, (struct user_msghdr __user *)msg,
347e1834a32SDominik Brodowski flags | MSG_CMSG_COMPAT, false);
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds
COMPAT_SYSCALL_DEFINE3(sendmsg,int,fd,struct compat_msghdr __user *,msg,unsigned int,flags)3506df35465SDominik Brodowski COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg,
3516df35465SDominik Brodowski unsigned int, flags)
3526df35465SDominik Brodowski {
3536df35465SDominik Brodowski return __compat_sys_sendmsg(fd, msg, flags);
3546df35465SDominik Brodowski }
3556df35465SDominik Brodowski
__compat_sys_sendmmsg(int fd,struct compat_mmsghdr __user * mmsg,unsigned int vlen,unsigned int flags)3566df35465SDominik Brodowski static inline long __compat_sys_sendmmsg(int fd,
3576df35465SDominik Brodowski struct compat_mmsghdr __user *mmsg,
3586df35465SDominik Brodowski unsigned int vlen, unsigned int flags)
3596df35465SDominik Brodowski {
3606df35465SDominik Brodowski return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
3616df35465SDominik Brodowski flags | MSG_CMSG_COMPAT, false);
3626df35465SDominik Brodowski }
3636df35465SDominik Brodowski
COMPAT_SYSCALL_DEFINE4(sendmmsg,int,fd,struct compat_mmsghdr __user *,mmsg,unsigned int,vlen,unsigned int,flags)364361d93c4SHeiko Carstens COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
365361d93c4SHeiko Carstens unsigned int, vlen, unsigned int, flags)
366228e548eSAnton Blanchard {
3676df35465SDominik Brodowski return __compat_sys_sendmmsg(fd, mmsg, vlen, flags);
368228e548eSAnton Blanchard }
369228e548eSAnton Blanchard
__compat_sys_recvmsg(int fd,struct compat_msghdr __user * msg,unsigned int flags)3706df35465SDominik Brodowski static inline long __compat_sys_recvmsg(int fd,
3716df35465SDominik Brodowski struct compat_msghdr __user *msg,
3726df35465SDominik Brodowski unsigned int flags)
3731da177e4SLinus Torvalds {
374e1834a32SDominik Brodowski return __sys_recvmsg(fd, (struct user_msghdr __user *)msg,
375e1834a32SDominik Brodowski flags | MSG_CMSG_COMPAT, false);
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds
COMPAT_SYSCALL_DEFINE3(recvmsg,int,fd,struct compat_msghdr __user *,msg,unsigned int,flags)3786df35465SDominik Brodowski COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg,
3796df35465SDominik Brodowski unsigned int, flags)
3806df35465SDominik Brodowski {
3816df35465SDominik Brodowski return __compat_sys_recvmsg(fd, msg, flags);
3826df35465SDominik Brodowski }
3836df35465SDominik Brodowski
__compat_sys_recvfrom(int fd,void __user * buf,compat_size_t len,unsigned int flags,struct sockaddr __user * addr,int __user * addrlen)384fd4e82f5SDominik Brodowski static inline long __compat_sys_recvfrom(int fd, void __user *buf,
385fd4e82f5SDominik Brodowski compat_size_t len, unsigned int flags,
386fd4e82f5SDominik Brodowski struct sockaddr __user *addr,
387fd4e82f5SDominik Brodowski int __user *addrlen)
388fd4e82f5SDominik Brodowski {
389fd4e82f5SDominik Brodowski return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr,
390fd4e82f5SDominik Brodowski addrlen);
391fd4e82f5SDominik Brodowski }
392fd4e82f5SDominik Brodowski
COMPAT_SYSCALL_DEFINE4(recv,int,fd,void __user *,buf,compat_size_t,len,unsigned int,flags)3933a49a0f7SHeiko Carstens COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
3941dacc76dSJohannes Berg {
395fd4e82f5SDominik Brodowski return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL);
3961dacc76dSJohannes Berg }
3971dacc76dSJohannes Berg
COMPAT_SYSCALL_DEFINE6(recvfrom,int,fd,void __user *,buf,compat_size_t,len,unsigned int,flags,struct sockaddr __user *,addr,int __user *,addrlen)3983a49a0f7SHeiko Carstens COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
3993a49a0f7SHeiko Carstens unsigned int, flags, struct sockaddr __user *, addr,
4003a49a0f7SHeiko Carstens int __user *, addrlen)
4011dacc76dSJohannes Berg {
402fd4e82f5SDominik Brodowski return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
4031dacc76dSJohannes Berg }
4041dacc76dSJohannes Berg
COMPAT_SYSCALL_DEFINE5(recvmmsg_time64,int,fd,struct compat_mmsghdr __user *,mmsg,unsigned int,vlen,unsigned int,flags,struct __kernel_timespec __user *,timeout)405e11d4284SArnd Bergmann COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg,
406e11d4284SArnd Bergmann unsigned int, vlen, unsigned int, flags,
407e11d4284SArnd Bergmann struct __kernel_timespec __user *, timeout)
408a2e27255SArnaldo Carvalho de Melo {
4095b23136bSJean-Mickael Guerin return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
410e11d4284SArnd Bergmann flags | MSG_CMSG_COMPAT, timeout, NULL);
411a2e27255SArnaldo Carvalho de Melo }
412a2e27255SArnaldo Carvalho de Melo
413e11d4284SArnd Bergmann #ifdef CONFIG_COMPAT_32BIT_TIME
COMPAT_SYSCALL_DEFINE5(recvmmsg_time32,int,fd,struct compat_mmsghdr __user *,mmsg,unsigned int,vlen,unsigned int,flags,struct old_timespec32 __user *,timeout)4148dabe724SArnd Bergmann COMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg,
415157b334aSDominik Brodowski unsigned int, vlen, unsigned int, flags,
4169afc5eeeSArnd Bergmann struct old_timespec32 __user *, timeout)
417157b334aSDominik Brodowski {
418e11d4284SArnd Bergmann return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
419e11d4284SArnd Bergmann flags | MSG_CMSG_COMPAT, NULL, timeout);
420157b334aSDominik Brodowski }
421e11d4284SArnd Bergmann #endif
422157b334aSDominik Brodowski
COMPAT_SYSCALL_DEFINE2(socketcall,int,call,u32 __user *,args)423361d93c4SHeiko Carstens COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
4241da177e4SLinus Torvalds {
42562bc306eSRichard Guy Briggs u32 a[AUDITSC_ARGS];
42662bc306eSRichard Guy Briggs unsigned int len;
4271da177e4SLinus Torvalds u32 a0, a1;
42862bc306eSRichard Guy Briggs int ret;
4291da177e4SLinus Torvalds
430228e548eSAnton Blanchard if (call < SYS_SOCKET || call > SYS_SENDMMSG)
4311da177e4SLinus Torvalds return -EINVAL;
43262bc306eSRichard Guy Briggs len = nas[call];
43362bc306eSRichard Guy Briggs if (len > sizeof(a))
43462bc306eSRichard Guy Briggs return -EINVAL;
43562bc306eSRichard Guy Briggs
43662bc306eSRichard Guy Briggs if (copy_from_user(a, args, len))
4371da177e4SLinus Torvalds return -EFAULT;
43862bc306eSRichard Guy Briggs
43962bc306eSRichard Guy Briggs ret = audit_socketcall_compat(len / sizeof(a[0]), a);
44062bc306eSRichard Guy Briggs if (ret)
44162bc306eSRichard Guy Briggs return ret;
44262bc306eSRichard Guy Briggs
4431da177e4SLinus Torvalds a0 = a[0];
4441da177e4SLinus Torvalds a1 = a[1];
4451da177e4SLinus Torvalds
4461da177e4SLinus Torvalds switch (call) {
4471da177e4SLinus Torvalds case SYS_SOCKET:
4489d6a15c3SDominik Brodowski ret = __sys_socket(a0, a1, a[2]);
4491da177e4SLinus Torvalds break;
4501da177e4SLinus Torvalds case SYS_BIND:
451a87d35d8SDominik Brodowski ret = __sys_bind(a0, compat_ptr(a1), a[2]);
4521da177e4SLinus Torvalds break;
4531da177e4SLinus Torvalds case SYS_CONNECT:
4541387c2c2SDominik Brodowski ret = __sys_connect(a0, compat_ptr(a1), a[2]);
4551da177e4SLinus Torvalds break;
4561da177e4SLinus Torvalds case SYS_LISTEN:
45725e290eeSDominik Brodowski ret = __sys_listen(a0, a1);
4581da177e4SLinus Torvalds break;
4591da177e4SLinus Torvalds case SYS_ACCEPT:
4604541e805SDominik Brodowski ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
4611da177e4SLinus Torvalds break;
4621da177e4SLinus Torvalds case SYS_GETSOCKNAME:
4638882a107SDominik Brodowski ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
4641da177e4SLinus Torvalds break;
4651da177e4SLinus Torvalds case SYS_GETPEERNAME:
466b21c8f83SDominik Brodowski ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
4671da177e4SLinus Torvalds break;
4681da177e4SLinus Torvalds case SYS_SOCKETPAIR:
4696debc8d8SDominik Brodowski ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
4701da177e4SLinus Torvalds break;
4711da177e4SLinus Torvalds case SYS_SEND:
472f3bf896bSDominik Brodowski ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0);
4731da177e4SLinus Torvalds break;
4741da177e4SLinus Torvalds case SYS_SENDTO:
475211b634bSDominik Brodowski ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3],
476211b634bSDominik Brodowski compat_ptr(a[4]), a[5]);
4771da177e4SLinus Torvalds break;
4781da177e4SLinus Torvalds case SYS_RECV:
479fd4e82f5SDominik Brodowski ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
480fd4e82f5SDominik Brodowski NULL, NULL);
4811da177e4SLinus Torvalds break;
4821da177e4SLinus Torvalds case SYS_RECVFROM:
483fd4e82f5SDominik Brodowski ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
484fd4e82f5SDominik Brodowski compat_ptr(a[4]),
485fd4e82f5SDominik Brodowski compat_ptr(a[5]));
4861da177e4SLinus Torvalds break;
4871da177e4SLinus Torvalds case SYS_SHUTDOWN:
488005a1aeaSDominik Brodowski ret = __sys_shutdown(a0, a1);
4891da177e4SLinus Torvalds break;
4901da177e4SLinus Torvalds case SYS_SETSOCKOPT:
49155db9c0eSChristoph Hellwig ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]);
4921da177e4SLinus Torvalds break;
4931da177e4SLinus Torvalds case SYS_GETSOCKOPT:
49455db9c0eSChristoph Hellwig ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]),
4958770cf4aSDominik Brodowski compat_ptr(a[4]));
4961da177e4SLinus Torvalds break;
4971da177e4SLinus Torvalds case SYS_SENDMSG:
4986df35465SDominik Brodowski ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
4991da177e4SLinus Torvalds break;
500228e548eSAnton Blanchard case SYS_SENDMMSG:
5016df35465SDominik Brodowski ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
502228e548eSAnton Blanchard break;
5031da177e4SLinus Torvalds case SYS_RECVMSG:
5046df35465SDominik Brodowski ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
5051da177e4SLinus Torvalds break;
506a2e27255SArnaldo Carvalho de Melo case SYS_RECVMMSG:
507e11d4284SArnd Bergmann ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
508e11d4284SArnd Bergmann a[3] | MSG_CMSG_COMPAT, NULL,
509a2e27255SArnaldo Carvalho de Melo compat_ptr(a[4]));
510a2e27255SArnaldo Carvalho de Melo break;
511de11defeSUlrich Drepper case SYS_ACCEPT4:
5124541e805SDominik Brodowski ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
513aaca0bdcSUlrich Drepper break;
5141da177e4SLinus Torvalds default:
5151da177e4SLinus Torvalds ret = -EINVAL;
5161da177e4SLinus Torvalds break;
5171da177e4SLinus Torvalds }
5181da177e4SLinus Torvalds return ret;
5191da177e4SLinus Torvalds }
520