18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2000 VA Linux Co 68c2ecf20Sopenharmony_ci * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 98c2ecf20Sopenharmony_ci * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 108c2ecf20Sopenharmony_ci * Copyright (C) 2000 Hewlett-Packard Co. 118c2ecf20Sopenharmony_ci * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> 128c2ecf20Sopenharmony_ci * Copyright (C) 2000,2001 Andi Kleen, SuSE Labs 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/gfp.h> 178c2ecf20Sopenharmony_ci#include <linux/fs.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/file.h> 208c2ecf20Sopenharmony_ci#include <linux/icmpv6.h> 218c2ecf20Sopenharmony_ci#include <linux/socket.h> 228c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 238c2ecf20Sopenharmony_ci#include <linux/filter.h> 248c2ecf20Sopenharmony_ci#include <linux/compat.h> 258c2ecf20Sopenharmony_ci#include <linux/security.h> 268c2ecf20Sopenharmony_ci#include <linux/audit.h> 278c2ecf20Sopenharmony_ci#include <linux/export.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <net/scm.h> 308c2ecf20Sopenharmony_ci#include <net/sock.h> 318c2ecf20Sopenharmony_ci#include <net/ip.h> 328c2ecf20Sopenharmony_ci#include <net/ipv6.h> 338c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 348c2ecf20Sopenharmony_ci#include <net/compat.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint __get_compat_msghdr(struct msghdr *kmsg, 378c2ecf20Sopenharmony_ci struct compat_msghdr __user *umsg, 388c2ecf20Sopenharmony_ci struct sockaddr __user **save_addr, 398c2ecf20Sopenharmony_ci compat_uptr_t *ptr, compat_size_t *len) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct compat_msghdr msg; 428c2ecf20Sopenharmony_ci ssize_t err; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (copy_from_user(&msg, umsg, sizeof(*umsg))) 458c2ecf20Sopenharmony_ci return -EFAULT; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci kmsg->msg_flags = msg.msg_flags; 488c2ecf20Sopenharmony_ci kmsg->msg_namelen = msg.msg_namelen; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!msg.msg_name) 518c2ecf20Sopenharmony_ci kmsg->msg_namelen = 0; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (kmsg->msg_namelen < 0) 548c2ecf20Sopenharmony_ci return -EINVAL; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) 578c2ecf20Sopenharmony_ci kmsg->msg_namelen = sizeof(struct sockaddr_storage); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci kmsg->msg_control_is_user = true; 608c2ecf20Sopenharmony_ci kmsg->msg_control_user = compat_ptr(msg.msg_control); 618c2ecf20Sopenharmony_ci kmsg->msg_controllen = msg.msg_controllen; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (save_addr) 648c2ecf20Sopenharmony_ci *save_addr = compat_ptr(msg.msg_name); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (msg.msg_name && kmsg->msg_namelen) { 678c2ecf20Sopenharmony_ci if (!save_addr) { 688c2ecf20Sopenharmony_ci err = move_addr_to_kernel(compat_ptr(msg.msg_name), 698c2ecf20Sopenharmony_ci kmsg->msg_namelen, 708c2ecf20Sopenharmony_ci kmsg->msg_name); 718c2ecf20Sopenharmony_ci if (err < 0) 728c2ecf20Sopenharmony_ci return err; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci kmsg->msg_name = NULL; 768c2ecf20Sopenharmony_ci kmsg->msg_namelen = 0; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (msg.msg_iovlen > UIO_MAXIOV) 808c2ecf20Sopenharmony_ci return -EMSGSIZE; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci kmsg->msg_iocb = NULL; 838c2ecf20Sopenharmony_ci *ptr = msg.msg_iov; 848c2ecf20Sopenharmony_ci *len = msg.msg_iovlen; 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciint get_compat_msghdr(struct msghdr *kmsg, 898c2ecf20Sopenharmony_ci struct compat_msghdr __user *umsg, 908c2ecf20Sopenharmony_ci struct sockaddr __user **save_addr, 918c2ecf20Sopenharmony_ci struct iovec **iov) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci compat_uptr_t ptr; 948c2ecf20Sopenharmony_ci compat_size_t len; 958c2ecf20Sopenharmony_ci ssize_t err; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len); 988c2ecf20Sopenharmony_ci if (err) 998c2ecf20Sopenharmony_ci return err; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len, 1028c2ecf20Sopenharmony_ci UIO_FASTIOV, iov, &kmsg->msg_iter); 1038c2ecf20Sopenharmony_ci return err < 0 ? err : 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Bleech... */ 1078c2ecf20Sopenharmony_ci#define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32)) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define CMSG_COMPAT_DATA(cmsg) \ 1108c2ecf20Sopenharmony_ci ((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr))) 1118c2ecf20Sopenharmony_ci#define CMSG_COMPAT_SPACE(len) \ 1128c2ecf20Sopenharmony_ci (sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len)) 1138c2ecf20Sopenharmony_ci#define CMSG_COMPAT_LEN(len) \ 1148c2ecf20Sopenharmony_ci (sizeof(struct compat_cmsghdr) + (len)) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define CMSG_COMPAT_FIRSTHDR(msg) \ 1178c2ecf20Sopenharmony_ci (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \ 1188c2ecf20Sopenharmony_ci (struct compat_cmsghdr __user *)((msg)->msg_control) : \ 1198c2ecf20Sopenharmony_ci (struct compat_cmsghdr __user *)NULL) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \ 1228c2ecf20Sopenharmony_ci ((ucmlen) >= sizeof(struct compat_cmsghdr) && \ 1238c2ecf20Sopenharmony_ci (ucmlen) <= (unsigned long) \ 1248c2ecf20Sopenharmony_ci ((mhdr)->msg_controllen - \ 1258c2ecf20Sopenharmony_ci ((char __user *)(ucmsg) - (char __user *)(mhdr)->msg_control_user))) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg, 1288c2ecf20Sopenharmony_ci struct compat_cmsghdr __user *cmsg, int cmsg_len) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len); 1318c2ecf20Sopenharmony_ci if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) > 1328c2ecf20Sopenharmony_ci msg->msg_controllen) 1338c2ecf20Sopenharmony_ci return NULL; 1348c2ecf20Sopenharmony_ci return (struct compat_cmsghdr __user *)ptr; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* There is a lot of hair here because the alignment rules (and 1388c2ecf20Sopenharmony_ci * thus placement) of cmsg headers and length are different for 1398c2ecf20Sopenharmony_ci * 32-bit apps. -DaveM 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ciint cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, 1428c2ecf20Sopenharmony_ci unsigned char *stackbuf, int stackbuf_size) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct compat_cmsghdr __user *ucmsg; 1458c2ecf20Sopenharmony_ci struct cmsghdr *kcmsg, *kcmsg_base; 1468c2ecf20Sopenharmony_ci compat_size_t ucmlen; 1478c2ecf20Sopenharmony_ci __kernel_size_t kcmlen, tmp; 1488c2ecf20Sopenharmony_ci int err = -EFAULT; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct compat_cmsghdr) != 1518c2ecf20Sopenharmony_ci CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci kcmlen = 0; 1548c2ecf20Sopenharmony_ci kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; 1558c2ecf20Sopenharmony_ci ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); 1568c2ecf20Sopenharmony_ci while (ucmsg != NULL) { 1578c2ecf20Sopenharmony_ci if (get_user(ucmlen, &ucmsg->cmsg_len)) 1588c2ecf20Sopenharmony_ci return -EFAULT; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Catch bogons. */ 1618c2ecf20Sopenharmony_ci if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) 1628c2ecf20Sopenharmony_ci return -EINVAL; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); 1658c2ecf20Sopenharmony_ci tmp = CMSG_ALIGN(tmp); 1668c2ecf20Sopenharmony_ci kcmlen += tmp; 1678c2ecf20Sopenharmony_ci ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (kcmlen == 0) 1708c2ecf20Sopenharmony_ci return -EINVAL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* The kcmlen holds the 64-bit version of the control length. 1738c2ecf20Sopenharmony_ci * It may not be modified as we do not stick it into the kmsg 1748c2ecf20Sopenharmony_ci * until we have successfully copied over all of the data 1758c2ecf20Sopenharmony_ci * from the user. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci if (kcmlen > stackbuf_size) 1788c2ecf20Sopenharmony_ci kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); 1798c2ecf20Sopenharmony_ci if (kcmsg == NULL) 1808c2ecf20Sopenharmony_ci return -ENOMEM; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Now copy them over neatly. */ 1838c2ecf20Sopenharmony_ci memset(kcmsg, 0, kcmlen); 1848c2ecf20Sopenharmony_ci ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); 1858c2ecf20Sopenharmony_ci while (ucmsg != NULL) { 1868c2ecf20Sopenharmony_ci struct compat_cmsghdr cmsg; 1878c2ecf20Sopenharmony_ci if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg))) 1888c2ecf20Sopenharmony_ci goto Efault; 1898c2ecf20Sopenharmony_ci if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg)) 1908c2ecf20Sopenharmony_ci goto Einval; 1918c2ecf20Sopenharmony_ci tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); 1928c2ecf20Sopenharmony_ci if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) 1938c2ecf20Sopenharmony_ci goto Einval; 1948c2ecf20Sopenharmony_ci kcmsg->cmsg_len = tmp; 1958c2ecf20Sopenharmony_ci kcmsg->cmsg_level = cmsg.cmsg_level; 1968c2ecf20Sopenharmony_ci kcmsg->cmsg_type = cmsg.cmsg_type; 1978c2ecf20Sopenharmony_ci tmp = CMSG_ALIGN(tmp); 1988c2ecf20Sopenharmony_ci if (copy_from_user(CMSG_DATA(kcmsg), 1998c2ecf20Sopenharmony_ci CMSG_COMPAT_DATA(ucmsg), 2008c2ecf20Sopenharmony_ci (cmsg.cmsg_len - sizeof(*ucmsg)))) 2018c2ecf20Sopenharmony_ci goto Efault; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Advance. */ 2048c2ecf20Sopenharmony_ci kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); 2058c2ecf20Sopenharmony_ci ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, cmsg.cmsg_len); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * check the length of messages copied in is the same as the 2108c2ecf20Sopenharmony_ci * what we get from the first loop 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci if ((char *)kcmsg - (char *)kcmsg_base != kcmlen) 2138c2ecf20Sopenharmony_ci goto Einval; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Ok, looks like we made it. Hook it up and return success. */ 2168c2ecf20Sopenharmony_ci kmsg->msg_control = kcmsg_base; 2178c2ecf20Sopenharmony_ci kmsg->msg_controllen = kcmlen; 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciEinval: 2218c2ecf20Sopenharmony_ci err = -EINVAL; 2228c2ecf20Sopenharmony_ciEfault: 2238c2ecf20Sopenharmony_ci if (kcmsg_base != (struct cmsghdr *)stackbuf) 2248c2ecf20Sopenharmony_ci sock_kfree_s(sk, kcmsg_base, kcmlen); 2258c2ecf20Sopenharmony_ci return err; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; 2318c2ecf20Sopenharmony_ci struct compat_cmsghdr cmhdr; 2328c2ecf20Sopenharmony_ci struct old_timeval32 ctv; 2338c2ecf20Sopenharmony_ci struct old_timespec32 cts[3]; 2348c2ecf20Sopenharmony_ci int cmlen; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { 2378c2ecf20Sopenharmony_ci kmsg->msg_flags |= MSG_CTRUNC; 2388c2ecf20Sopenharmony_ci return 0; /* XXX: return error? check spec. */ 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!COMPAT_USE_64BIT_TIME) { 2428c2ecf20Sopenharmony_ci if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) { 2438c2ecf20Sopenharmony_ci struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data; 2448c2ecf20Sopenharmony_ci ctv.tv_sec = tv->tv_sec; 2458c2ecf20Sopenharmony_ci ctv.tv_usec = tv->tv_usec; 2468c2ecf20Sopenharmony_ci data = &ctv; 2478c2ecf20Sopenharmony_ci len = sizeof(ctv); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci if (level == SOL_SOCKET && 2508c2ecf20Sopenharmony_ci (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) { 2518c2ecf20Sopenharmony_ci int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3; 2528c2ecf20Sopenharmony_ci int i; 2538c2ecf20Sopenharmony_ci struct __kernel_old_timespec *ts = data; 2548c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 2558c2ecf20Sopenharmony_ci cts[i].tv_sec = ts[i].tv_sec; 2568c2ecf20Sopenharmony_ci cts[i].tv_nsec = ts[i].tv_nsec; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci data = &cts; 2598c2ecf20Sopenharmony_ci len = sizeof(cts[0]) * count; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cmlen = CMSG_COMPAT_LEN(len); 2648c2ecf20Sopenharmony_ci if (kmsg->msg_controllen < cmlen) { 2658c2ecf20Sopenharmony_ci kmsg->msg_flags |= MSG_CTRUNC; 2668c2ecf20Sopenharmony_ci cmlen = kmsg->msg_controllen; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci cmhdr.cmsg_level = level; 2698c2ecf20Sopenharmony_ci cmhdr.cmsg_type = type; 2708c2ecf20Sopenharmony_ci cmhdr.cmsg_len = cmlen; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) 2738c2ecf20Sopenharmony_ci return -EFAULT; 2748c2ecf20Sopenharmony_ci if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) 2758c2ecf20Sopenharmony_ci return -EFAULT; 2768c2ecf20Sopenharmony_ci cmlen = CMSG_COMPAT_SPACE(len); 2778c2ecf20Sopenharmony_ci if (kmsg->msg_controllen < cmlen) 2788c2ecf20Sopenharmony_ci cmlen = kmsg->msg_controllen; 2798c2ecf20Sopenharmony_ci kmsg->msg_control += cmlen; 2808c2ecf20Sopenharmony_ci kmsg->msg_controllen -= cmlen; 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int scm_max_fds_compat(struct msghdr *msg) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci if (msg->msg_controllen <= sizeof(struct compat_cmsghdr)) 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_civoid scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct compat_cmsghdr __user *cm = 2948c2ecf20Sopenharmony_ci (struct compat_cmsghdr __user *)msg->msg_control; 2958c2ecf20Sopenharmony_ci unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0; 2968c2ecf20Sopenharmony_ci int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count); 2978c2ecf20Sopenharmony_ci int __user *cmsg_data = CMSG_COMPAT_DATA(cm); 2988c2ecf20Sopenharmony_ci int err = 0, i; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci for (i = 0; i < fdmax; i++) { 3018c2ecf20Sopenharmony_ci err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags); 3028c2ecf20Sopenharmony_ci if (err < 0) 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (i > 0) { 3078c2ecf20Sopenharmony_ci int cmlen = CMSG_COMPAT_LEN(i * sizeof(int)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci err = put_user(SOL_SOCKET, &cm->cmsg_level); 3108c2ecf20Sopenharmony_ci if (!err) 3118c2ecf20Sopenharmony_ci err = put_user(SCM_RIGHTS, &cm->cmsg_type); 3128c2ecf20Sopenharmony_ci if (!err) 3138c2ecf20Sopenharmony_ci err = put_user(cmlen, &cm->cmsg_len); 3148c2ecf20Sopenharmony_ci if (!err) { 3158c2ecf20Sopenharmony_ci cmlen = CMSG_COMPAT_SPACE(i * sizeof(int)); 3168c2ecf20Sopenharmony_ci if (msg->msg_controllen < cmlen) 3178c2ecf20Sopenharmony_ci cmlen = msg->msg_controllen; 3188c2ecf20Sopenharmony_ci msg->msg_control += cmlen; 3198c2ecf20Sopenharmony_ci msg->msg_controllen -= cmlen; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (i < scm->fp->count || (scm->fp->count && fdmax <= 0)) 3248c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_CTRUNC; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* 3278c2ecf20Sopenharmony_ci * All of the files that fit in the message have had their usage counts 3288c2ecf20Sopenharmony_ci * incremented, so we just free the list. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci __scm_destroy(scm); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* Argument list sizes for compat_sys_socketcall */ 3348c2ecf20Sopenharmony_ci#define AL(x) ((x) * sizeof(u32)) 3358c2ecf20Sopenharmony_cistatic unsigned char nas[21] = { 3368c2ecf20Sopenharmony_ci AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 3378c2ecf20Sopenharmony_ci AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 3388c2ecf20Sopenharmony_ci AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 3398c2ecf20Sopenharmony_ci AL(4), AL(5), AL(4) 3408c2ecf20Sopenharmony_ci}; 3418c2ecf20Sopenharmony_ci#undef AL 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic inline long __compat_sys_sendmsg(int fd, 3448c2ecf20Sopenharmony_ci struct compat_msghdr __user *msg, 3458c2ecf20Sopenharmony_ci unsigned int flags) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, 3488c2ecf20Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, 3528c2ecf20Sopenharmony_ci unsigned int, flags) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci return __compat_sys_sendmsg(fd, msg, flags); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic inline long __compat_sys_sendmmsg(int fd, 3588c2ecf20Sopenharmony_ci struct compat_mmsghdr __user *mmsg, 3598c2ecf20Sopenharmony_ci unsigned int vlen, unsigned int flags) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 3628c2ecf20Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, 3668c2ecf20Sopenharmony_ci unsigned int, vlen, unsigned int, flags) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci return __compat_sys_sendmmsg(fd, mmsg, vlen, flags); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic inline long __compat_sys_recvmsg(int fd, 3728c2ecf20Sopenharmony_ci struct compat_msghdr __user *msg, 3738c2ecf20Sopenharmony_ci unsigned int flags) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, 3768c2ecf20Sopenharmony_ci flags | MSG_CMSG_COMPAT, false); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, 3808c2ecf20Sopenharmony_ci unsigned int, flags) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci return __compat_sys_recvmsg(fd, msg, flags); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic inline long __compat_sys_recvfrom(int fd, void __user *buf, 3868c2ecf20Sopenharmony_ci compat_size_t len, unsigned int flags, 3878c2ecf20Sopenharmony_ci struct sockaddr __user *addr, 3888c2ecf20Sopenharmony_ci int __user *addrlen) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, 3918c2ecf20Sopenharmony_ci addrlen); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len, 4008c2ecf20Sopenharmony_ci unsigned int, flags, struct sockaddr __user *, addr, 4018c2ecf20Sopenharmony_ci int __user *, addrlen) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg, 4078c2ecf20Sopenharmony_ci unsigned int, vlen, unsigned int, flags, 4088c2ecf20Sopenharmony_ci struct __kernel_timespec __user *, timeout) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 4118c2ecf20Sopenharmony_ci flags | MSG_CMSG_COMPAT, timeout, NULL); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT_32BIT_TIME 4158c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg, 4168c2ecf20Sopenharmony_ci unsigned int, vlen, unsigned int, flags, 4178c2ecf20Sopenharmony_ci struct old_timespec32 __user *, timeout) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, 4208c2ecf20Sopenharmony_ci flags | MSG_CMSG_COMPAT, NULL, timeout); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci#endif 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci u32 a[AUDITSC_ARGS]; 4278c2ecf20Sopenharmony_ci unsigned int len; 4288c2ecf20Sopenharmony_ci u32 a0, a1; 4298c2ecf20Sopenharmony_ci int ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (call < SYS_SOCKET || call > SYS_SENDMMSG) 4328c2ecf20Sopenharmony_ci return -EINVAL; 4338c2ecf20Sopenharmony_ci len = nas[call]; 4348c2ecf20Sopenharmony_ci if (len > sizeof(a)) 4358c2ecf20Sopenharmony_ci return -EINVAL; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (copy_from_user(a, args, len)) 4388c2ecf20Sopenharmony_ci return -EFAULT; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ret = audit_socketcall_compat(len / sizeof(a[0]), a); 4418c2ecf20Sopenharmony_ci if (ret) 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci a0 = a[0]; 4458c2ecf20Sopenharmony_ci a1 = a[1]; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci switch (call) { 4488c2ecf20Sopenharmony_ci case SYS_SOCKET: 4498c2ecf20Sopenharmony_ci ret = __sys_socket(a0, a1, a[2]); 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci case SYS_BIND: 4528c2ecf20Sopenharmony_ci ret = __sys_bind(a0, compat_ptr(a1), a[2]); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci case SYS_CONNECT: 4558c2ecf20Sopenharmony_ci ret = __sys_connect(a0, compat_ptr(a1), a[2]); 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci case SYS_LISTEN: 4588c2ecf20Sopenharmony_ci ret = __sys_listen(a0, a1); 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci case SYS_ACCEPT: 4618c2ecf20Sopenharmony_ci ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0); 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case SYS_GETSOCKNAME: 4648c2ecf20Sopenharmony_ci ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2])); 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci case SYS_GETPEERNAME: 4678c2ecf20Sopenharmony_ci ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2])); 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci case SYS_SOCKETPAIR: 4708c2ecf20Sopenharmony_ci ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3])); 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case SYS_SEND: 4738c2ecf20Sopenharmony_ci ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0); 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci case SYS_SENDTO: 4768c2ecf20Sopenharmony_ci ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], 4778c2ecf20Sopenharmony_ci compat_ptr(a[4]), a[5]); 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci case SYS_RECV: 4808c2ecf20Sopenharmony_ci ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], 4818c2ecf20Sopenharmony_ci NULL, NULL); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case SYS_RECVFROM: 4848c2ecf20Sopenharmony_ci ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], 4858c2ecf20Sopenharmony_ci compat_ptr(a[4]), 4868c2ecf20Sopenharmony_ci compat_ptr(a[5])); 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci case SYS_SHUTDOWN: 4898c2ecf20Sopenharmony_ci ret = __sys_shutdown(a0, a1); 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci case SYS_SETSOCKOPT: 4928c2ecf20Sopenharmony_ci ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]); 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case SYS_GETSOCKOPT: 4958c2ecf20Sopenharmony_ci ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]), 4968c2ecf20Sopenharmony_ci compat_ptr(a[4])); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case SYS_SENDMSG: 4998c2ecf20Sopenharmony_ci ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case SYS_SENDMMSG: 5028c2ecf20Sopenharmony_ci ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case SYS_RECVMSG: 5058c2ecf20Sopenharmony_ci ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci case SYS_RECVMMSG: 5088c2ecf20Sopenharmony_ci ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2], 5098c2ecf20Sopenharmony_ci a[3] | MSG_CMSG_COMPAT, NULL, 5108c2ecf20Sopenharmony_ci compat_ptr(a[4])); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case SYS_ACCEPT4: 5138c2ecf20Sopenharmony_ci ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci default: 5168c2ecf20Sopenharmony_ci ret = -EINVAL; 5178c2ecf20Sopenharmony_ci break; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci return ret; 5208c2ecf20Sopenharmony_ci} 521