162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2000 VA Linux Co 662306a36Sopenharmony_ci * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> 762306a36Sopenharmony_ci * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> 862306a36Sopenharmony_ci * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 962306a36Sopenharmony_ci * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 1062306a36Sopenharmony_ci * Copyright (C) 2000 Hewlett-Packard Co. 1162306a36Sopenharmony_ci * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> 1262306a36Sopenharmony_ci * Copyright (C) 2000,2001 Andi Kleen, SuSE Labs 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/gfp.h> 1762306a36Sopenharmony_ci#include <linux/fs.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/file.h> 2062306a36Sopenharmony_ci#include <linux/icmpv6.h> 2162306a36Sopenharmony_ci#include <linux/socket.h> 2262306a36Sopenharmony_ci#include <linux/syscalls.h> 2362306a36Sopenharmony_ci#include <linux/filter.h> 2462306a36Sopenharmony_ci#include <linux/compat.h> 2562306a36Sopenharmony_ci#include <linux/security.h> 2662306a36Sopenharmony_ci#include <linux/audit.h> 2762306a36Sopenharmony_ci#include <linux/export.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <net/scm.h> 3062306a36Sopenharmony_ci#include <net/sock.h> 3162306a36Sopenharmony_ci#include <net/ip.h> 3262306a36Sopenharmony_ci#include <net/ipv6.h> 3362306a36Sopenharmony_ci#include <linux/uaccess.h> 3462306a36Sopenharmony_ci#include <net/compat.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint __get_compat_msghdr(struct msghdr *kmsg, 3762306a36Sopenharmony_ci struct compat_msghdr *msg, 3862306a36Sopenharmony_ci struct sockaddr __user **save_addr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci ssize_t err; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci kmsg->msg_flags = msg->msg_flags; 4362306a36Sopenharmony_ci kmsg->msg_namelen = msg->msg_namelen; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (!msg->msg_name) 4662306a36Sopenharmony_ci kmsg->msg_namelen = 0; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (kmsg->msg_namelen < 0) 4962306a36Sopenharmony_ci return -EINVAL; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) 5262306a36Sopenharmony_ci kmsg->msg_namelen = sizeof(struct sockaddr_storage); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci kmsg->msg_control_is_user = true; 5562306a36Sopenharmony_ci kmsg->msg_get_inq = 0; 5662306a36Sopenharmony_ci kmsg->msg_control_user = compat_ptr(msg->msg_control); 5762306a36Sopenharmony_ci kmsg->msg_controllen = msg->msg_controllen; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (save_addr) 6062306a36Sopenharmony_ci *save_addr = compat_ptr(msg->msg_name); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (msg->msg_name && kmsg->msg_namelen) { 6362306a36Sopenharmony_ci if (!save_addr) { 6462306a36Sopenharmony_ci err = move_addr_to_kernel(compat_ptr(msg->msg_name), 6562306a36Sopenharmony_ci kmsg->msg_namelen, 6662306a36Sopenharmony_ci kmsg->msg_name); 6762306a36Sopenharmony_ci if (err < 0) 6862306a36Sopenharmony_ci return err; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } else { 7162306a36Sopenharmony_ci kmsg->msg_name = NULL; 7262306a36Sopenharmony_ci kmsg->msg_namelen = 0; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (msg->msg_iovlen > UIO_MAXIOV) 7662306a36Sopenharmony_ci return -EMSGSIZE; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci kmsg->msg_iocb = NULL; 7962306a36Sopenharmony_ci kmsg->msg_ubuf = NULL; 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciint get_compat_msghdr(struct msghdr *kmsg, 8462306a36Sopenharmony_ci struct compat_msghdr __user *umsg, 8562306a36Sopenharmony_ci struct sockaddr __user **save_addr, 8662306a36Sopenharmony_ci struct iovec **iov) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct compat_msghdr msg; 8962306a36Sopenharmony_ci ssize_t err; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (copy_from_user(&msg, umsg, sizeof(*umsg))) 9262306a36Sopenharmony_ci return -EFAULT; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci err = __get_compat_msghdr(kmsg, &msg, save_addr); 9562306a36Sopenharmony_ci if (err) 9662306a36Sopenharmony_ci return err; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci err = import_iovec(save_addr ? ITER_DEST : ITER_SOURCE, 9962306a36Sopenharmony_ci compat_ptr(msg.msg_iov), msg.msg_iovlen, 10062306a36Sopenharmony_ci UIO_FASTIOV, iov, &kmsg->msg_iter); 10162306a36Sopenharmony_ci return err < 0 ? err : 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Bleech... */ 10562306a36Sopenharmony_ci#define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32)) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define CMSG_COMPAT_DATA(cmsg) \ 10862306a36Sopenharmony_ci ((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr))) 10962306a36Sopenharmony_ci#define CMSG_COMPAT_SPACE(len) \ 11062306a36Sopenharmony_ci (sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len)) 11162306a36Sopenharmony_ci#define CMSG_COMPAT_LEN(len) \ 11262306a36Sopenharmony_ci (sizeof(struct compat_cmsghdr) + (len)) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define CMSG_COMPAT_FIRSTHDR(msg) \ 11562306a36Sopenharmony_ci (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \ 11662306a36Sopenharmony_ci (struct compat_cmsghdr __user *)((msg)->msg_control_user) : \ 11762306a36Sopenharmony_ci (struct compat_cmsghdr __user *)NULL) 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \ 12062306a36Sopenharmony_ci ((ucmlen) >= sizeof(struct compat_cmsghdr) && \ 12162306a36Sopenharmony_ci (ucmlen) <= (unsigned long) \ 12262306a36Sopenharmony_ci ((mhdr)->msg_controllen - \ 12362306a36Sopenharmony_ci ((char __user *)(ucmsg) - (char __user *)(mhdr)->msg_control_user))) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg, 12662306a36Sopenharmony_ci struct compat_cmsghdr __user *cmsg, int cmsg_len) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len); 12962306a36Sopenharmony_ci if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control_user) > 13062306a36Sopenharmony_ci msg->msg_controllen) 13162306a36Sopenharmony_ci return NULL; 13262306a36Sopenharmony_ci return (struct compat_cmsghdr __user *)ptr; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* There is a lot of hair here because the alignment rules (and 13662306a36Sopenharmony_ci * thus placement) of cmsg headers and length are different for 13762306a36Sopenharmony_ci * 32-bit apps. -DaveM 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ciint cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, 14062306a36Sopenharmony_ci unsigned char *stackbuf, int stackbuf_size) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct compat_cmsghdr __user *ucmsg; 14362306a36Sopenharmony_ci struct cmsghdr *kcmsg, *kcmsg_base; 14462306a36Sopenharmony_ci compat_size_t ucmlen; 14562306a36Sopenharmony_ci __kernel_size_t kcmlen, tmp; 14662306a36Sopenharmony_ci int err = -EFAULT; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct compat_cmsghdr) != 14962306a36Sopenharmony_ci CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci kcmlen = 0; 15262306a36Sopenharmony_ci kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; 15362306a36Sopenharmony_ci ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); 15462306a36Sopenharmony_ci while (ucmsg != NULL) { 15562306a36Sopenharmony_ci if (get_user(ucmlen, &ucmsg->cmsg_len)) 15662306a36Sopenharmony_ci return -EFAULT; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Catch bogons. */ 15962306a36Sopenharmony_ci if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); 16362306a36Sopenharmony_ci tmp = CMSG_ALIGN(tmp); 16462306a36Sopenharmony_ci kcmlen += tmp; 16562306a36Sopenharmony_ci ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci if (kcmlen == 0) 16862306a36Sopenharmony_ci return -EINVAL; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* The kcmlen holds the 64-bit version of the control length. 17162306a36Sopenharmony_ci * It may not be modified as we do not stick it into the kmsg 17262306a36Sopenharmony_ci * until we have successfully copied over all of the data 17362306a36Sopenharmony_ci * from the user. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if (kcmlen > stackbuf_size) 17662306a36Sopenharmony_ci kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); 17762306a36Sopenharmony_ci if (kcmsg == NULL) 17862306a36Sopenharmony_ci return -ENOMEM; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Now copy them over neatly. */ 18162306a36Sopenharmony_ci memset(kcmsg, 0, kcmlen); 18262306a36Sopenharmony_ci ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); 18362306a36Sopenharmony_ci while (ucmsg != NULL) { 18462306a36Sopenharmony_ci struct compat_cmsghdr cmsg; 18562306a36Sopenharmony_ci if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg))) 18662306a36Sopenharmony_ci goto Efault; 18762306a36Sopenharmony_ci if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg)) 18862306a36Sopenharmony_ci goto Einval; 18962306a36Sopenharmony_ci tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); 19062306a36Sopenharmony_ci if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) 19162306a36Sopenharmony_ci goto Einval; 19262306a36Sopenharmony_ci kcmsg->cmsg_len = tmp; 19362306a36Sopenharmony_ci kcmsg->cmsg_level = cmsg.cmsg_level; 19462306a36Sopenharmony_ci kcmsg->cmsg_type = cmsg.cmsg_type; 19562306a36Sopenharmony_ci tmp = CMSG_ALIGN(tmp); 19662306a36Sopenharmony_ci if (copy_from_user(CMSG_DATA(kcmsg), 19762306a36Sopenharmony_ci CMSG_COMPAT_DATA(ucmsg), 19862306a36Sopenharmony_ci (cmsg.cmsg_len - sizeof(*ucmsg)))) 19962306a36Sopenharmony_ci goto Efault; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Advance. */ 20262306a36Sopenharmony_ci kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); 20362306a36Sopenharmony_ci ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, cmsg.cmsg_len); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * check the length of messages copied in is the same as the 20862306a36Sopenharmony_ci * what we get from the first loop 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci if ((char *)kcmsg - (char *)kcmsg_base != kcmlen) 21162306a36Sopenharmony_ci goto Einval; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Ok, looks like we made it. Hook it up and return success. */ 21462306a36Sopenharmony_ci kmsg->msg_control_is_user = false; 21562306a36Sopenharmony_ci kmsg->msg_control = kcmsg_base; 21662306a36Sopenharmony_ci kmsg->msg_controllen = kcmlen; 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciEinval: 22062306a36Sopenharmony_ci err = -EINVAL; 22162306a36Sopenharmony_ciEfault: 22262306a36Sopenharmony_ci if (kcmsg_base != (struct cmsghdr *)stackbuf) 22362306a36Sopenharmony_ci sock_kfree_s(sk, kcmsg_base, kcmlen); 22462306a36Sopenharmony_ci return err; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control_user; 23062306a36Sopenharmony_ci struct compat_cmsghdr cmhdr; 23162306a36Sopenharmony_ci struct old_timeval32 ctv; 23262306a36Sopenharmony_ci struct old_timespec32 cts[3]; 23362306a36Sopenharmony_ci int cmlen; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { 23662306a36Sopenharmony_ci kmsg->msg_flags |= MSG_CTRUNC; 23762306a36Sopenharmony_ci return 0; /* XXX: return error? check spec. */ 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!COMPAT_USE_64BIT_TIME) { 24162306a36Sopenharmony_ci if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) { 24262306a36Sopenharmony_ci struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data; 24362306a36Sopenharmony_ci ctv.tv_sec = tv->tv_sec; 24462306a36Sopenharmony_ci ctv.tv_usec = tv->tv_usec; 24562306a36Sopenharmony_ci data = &ctv; 24662306a36Sopenharmony_ci len = sizeof(ctv); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci if (level == SOL_SOCKET && 24962306a36Sopenharmony_ci (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) { 25062306a36Sopenharmony_ci int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3; 25162306a36Sopenharmony_ci int i; 25262306a36Sopenharmony_ci struct __kernel_old_timespec *ts = data; 25362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 25462306a36Sopenharmony_ci cts[i].tv_sec = ts[i].tv_sec; 25562306a36Sopenharmony_ci cts[i].tv_nsec = ts[i].tv_nsec; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci data = &cts; 25862306a36Sopenharmony_ci len = sizeof(cts[0]) * count; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci cmlen = CMSG_COMPAT_LEN(len); 26362306a36Sopenharmony_ci if (kmsg->msg_controllen < cmlen) { 26462306a36Sopenharmony_ci kmsg->msg_flags |= MSG_CTRUNC; 26562306a36Sopenharmony_ci cmlen = kmsg->msg_controllen; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci cmhdr.cmsg_level = level; 26862306a36Sopenharmony_ci cmhdr.cmsg_type = type; 26962306a36Sopenharmony_ci cmhdr.cmsg_len = cmlen; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) 27262306a36Sopenharmony_ci return -EFAULT; 27362306a36Sopenharmony_ci if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) 27462306a36Sopenharmony_ci return -EFAULT; 27562306a36Sopenharmony_ci cmlen = CMSG_COMPAT_SPACE(len); 27662306a36Sopenharmony_ci if (kmsg->msg_controllen < cmlen) 27762306a36Sopenharmony_ci cmlen = kmsg->msg_controllen; 27862306a36Sopenharmony_ci kmsg->msg_control_user += cmlen; 27962306a36Sopenharmony_ci kmsg->msg_controllen -= cmlen; 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int scm_max_fds_compat(struct msghdr *msg) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci if (msg->msg_controllen <= sizeof(struct compat_cmsghdr)) 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_civoid scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct compat_cmsghdr __user *cm = 29362306a36Sopenharmony_ci (struct compat_cmsghdr __user *)msg->msg_control_user; 29462306a36Sopenharmony_ci unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0; 29562306a36Sopenharmony_ci int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count); 29662306a36Sopenharmony_ci int __user *cmsg_data = CMSG_COMPAT_DATA(cm); 29762306a36Sopenharmony_ci int err = 0, i; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci for (i = 0; i < fdmax; i++) { 30062306a36Sopenharmony_ci err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags); 30162306a36Sopenharmony_ci if (err < 0) 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (i > 0) { 30662306a36Sopenharmony_ci int cmlen = CMSG_COMPAT_LEN(i * sizeof(int)); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = put_user(SOL_SOCKET, &cm->cmsg_level); 30962306a36Sopenharmony_ci if (!err) 31062306a36Sopenharmony_ci err = put_user(SCM_RIGHTS, &cm->cmsg_type); 31162306a36Sopenharmony_ci if (!err) 31262306a36Sopenharmony_ci err = put_user(cmlen, &cm->cmsg_len); 31362306a36Sopenharmony_ci if (!err) { 31462306a36Sopenharmony_ci cmlen = CMSG_COMPAT_SPACE(i * sizeof(int)); 31562306a36Sopenharmony_ci if (msg->msg_controllen < cmlen) 31662306a36Sopenharmony_ci cmlen = msg->msg_controllen; 31762306a36Sopenharmony_ci msg->msg_control_user += cmlen; 31862306a36Sopenharmony_ci msg->msg_controllen -= cmlen; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (i < scm->fp->count || (scm->fp->count && fdmax <= 0)) 32362306a36Sopenharmony_ci msg->msg_flags |= MSG_CTRUNC; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * All of the files that fit in the message have had their usage counts 32762306a36Sopenharmony_ci * incremented, so we just free the list. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci __scm_destroy(scm); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* Argument list sizes for compat_sys_socketcall */ 33362306a36Sopenharmony_ci#define AL(x) ((x) * sizeof(u32)) 33462306a36Sopenharmony_cistatic unsigned char nas[21] = { 33562306a36Sopenharmony_ci AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 33662306a36Sopenharmony_ci AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 33762306a36Sopenharmony_ci AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 33862306a36Sopenharmony_ci AL(4), AL(5), AL(4) 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci#undef AL 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic inline long __compat_sys_sendmsg(int fd, 34362306a36Sopenharmony_ci struct compat_msghdr __user *msg, 34462306a36Sopenharmony_ci unsigned int flags) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, 34762306a36Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, 35162306a36Sopenharmony_ci unsigned int, flags) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci return __compat_sys_sendmsg(fd, msg, flags); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic inline long __compat_sys_sendmmsg(int fd, 35762306a36Sopenharmony_ci struct compat_mmsghdr __user *mmsg, 35862306a36Sopenharmony_ci unsigned int vlen, unsigned int flags) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 36162306a36Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, 36562306a36Sopenharmony_ci unsigned int, vlen, unsigned int, flags) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci return __compat_sys_sendmmsg(fd, mmsg, vlen, flags); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic inline long __compat_sys_recvmsg(int fd, 37162306a36Sopenharmony_ci struct compat_msghdr __user *msg, 37262306a36Sopenharmony_ci unsigned int flags) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, 37562306a36Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, 37962306a36Sopenharmony_ci unsigned int, flags) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci return __compat_sys_recvmsg(fd, msg, flags); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic inline long __compat_sys_recvfrom(int fd, void __user *buf, 38562306a36Sopenharmony_ci compat_size_t len, unsigned int flags, 38662306a36Sopenharmony_ci struct sockaddr __user *addr, 38762306a36Sopenharmony_ci int __user *addrlen) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, 39062306a36Sopenharmony_ci addrlen); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len, 39962306a36Sopenharmony_ci unsigned int, flags, struct sockaddr __user *, addr, 40062306a36Sopenharmony_ci int __user *, addrlen) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg, 40662306a36Sopenharmony_ci unsigned int, vlen, unsigned int, flags, 40762306a36Sopenharmony_ci struct __kernel_timespec __user *, timeout) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 41062306a36Sopenharmony_ci flags | MSG_CMSG_COMPAT, timeout, NULL); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_32BIT_TIME 41462306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg, 41562306a36Sopenharmony_ci unsigned int, vlen, unsigned int, flags, 41662306a36Sopenharmony_ci struct old_timespec32 __user *, timeout) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 41962306a36Sopenharmony_ci flags | MSG_CMSG_COMPAT, NULL, timeout); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci#endif 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci u32 a[AUDITSC_ARGS]; 42662306a36Sopenharmony_ci unsigned int len; 42762306a36Sopenharmony_ci u32 a0, a1; 42862306a36Sopenharmony_ci int ret; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (call < SYS_SOCKET || call > SYS_SENDMMSG) 43162306a36Sopenharmony_ci return -EINVAL; 43262306a36Sopenharmony_ci len = nas[call]; 43362306a36Sopenharmony_ci if (len > sizeof(a)) 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (copy_from_user(a, args, len)) 43762306a36Sopenharmony_ci return -EFAULT; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ret = audit_socketcall_compat(len / sizeof(a[0]), a); 44062306a36Sopenharmony_ci if (ret) 44162306a36Sopenharmony_ci return ret; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci a0 = a[0]; 44462306a36Sopenharmony_ci a1 = a[1]; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switch (call) { 44762306a36Sopenharmony_ci case SYS_SOCKET: 44862306a36Sopenharmony_ci ret = __sys_socket(a0, a1, a[2]); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case SYS_BIND: 45162306a36Sopenharmony_ci ret = __sys_bind(a0, compat_ptr(a1), a[2]); 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci case SYS_CONNECT: 45462306a36Sopenharmony_ci ret = __sys_connect(a0, compat_ptr(a1), a[2]); 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci case SYS_LISTEN: 45762306a36Sopenharmony_ci ret = __sys_listen(a0, a1); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case SYS_ACCEPT: 46062306a36Sopenharmony_ci ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case SYS_GETSOCKNAME: 46362306a36Sopenharmony_ci ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2])); 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci case SYS_GETPEERNAME: 46662306a36Sopenharmony_ci ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2])); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case SYS_SOCKETPAIR: 46962306a36Sopenharmony_ci ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3])); 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case SYS_SEND: 47262306a36Sopenharmony_ci ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0); 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case SYS_SENDTO: 47562306a36Sopenharmony_ci ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], 47662306a36Sopenharmony_ci compat_ptr(a[4]), a[5]); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case SYS_RECV: 47962306a36Sopenharmony_ci ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], 48062306a36Sopenharmony_ci NULL, NULL); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case SYS_RECVFROM: 48362306a36Sopenharmony_ci ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], 48462306a36Sopenharmony_ci compat_ptr(a[4]), 48562306a36Sopenharmony_ci compat_ptr(a[5])); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case SYS_SHUTDOWN: 48862306a36Sopenharmony_ci ret = __sys_shutdown(a0, a1); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case SYS_SETSOCKOPT: 49162306a36Sopenharmony_ci ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]); 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case SYS_GETSOCKOPT: 49462306a36Sopenharmony_ci ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]), 49562306a36Sopenharmony_ci compat_ptr(a[4])); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case SYS_SENDMSG: 49862306a36Sopenharmony_ci ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci case SYS_SENDMMSG: 50162306a36Sopenharmony_ci ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]); 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case SYS_RECVMSG: 50462306a36Sopenharmony_ci ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci case SYS_RECVMMSG: 50762306a36Sopenharmony_ci ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2], 50862306a36Sopenharmony_ci a[3] | MSG_CMSG_COMPAT, NULL, 50962306a36Sopenharmony_ci compat_ptr(a[4])); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci case SYS_ACCEPT4: 51262306a36Sopenharmony_ci ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci default: 51562306a36Sopenharmony_ci ret = -EINVAL; 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci return ret; 51962306a36Sopenharmony_ci} 520