1 /*- 2 * Copyright (c) 2015-2017 Nuxi, https://nuxi.nl/ 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/capsicum.h> 31 #include <sys/lock.h> 32 #include <sys/malloc.h> 33 #include <sys/mbuf.h> 34 #include <sys/mutex.h> 35 #include <sys/proc.h> 36 #include <sys/protosw.h> 37 #include <sys/socket.h> 38 #include <sys/socketvar.h> 39 #include <sys/syscallsubr.h> 40 #include <sys/systm.h> 41 42 #include <net/vnet.h> 43 44 #include <netinet/in.h> 45 46 #include <contrib/cloudabi/cloudabi_types_common.h> 47 48 #include <compat/cloudabi/cloudabi_proto.h> 49 #include <compat/cloudabi/cloudabi_util.h> 50 51 int 52 cloudabi_sys_sock_shutdown(struct thread *td, 53 struct cloudabi_sys_sock_shutdown_args *uap) 54 { 55 int how; 56 57 switch (uap->how) { 58 case CLOUDABI_SHUT_RD: 59 how = SHUT_RD; 60 break; 61 case CLOUDABI_SHUT_WR: 62 how = SHUT_WR; 63 break; 64 case CLOUDABI_SHUT_RD | CLOUDABI_SHUT_WR: 65 how = SHUT_RDWR; 66 break; 67 default: 68 return (EINVAL); 69 } 70 71 return (kern_shutdown(td, uap->sock, how)); 72 } 73 74 int 75 cloudabi_sock_recv(struct thread *td, cloudabi_fd_t fd, struct iovec *data, 76 size_t datalen, cloudabi_fd_t *fds, size_t fdslen, 77 cloudabi_riflags_t flags, size_t *rdatalen, size_t *rfdslen, 78 cloudabi_roflags_t *rflags) 79 { 80 struct msghdr hdr = { 81 .msg_iov = data, 82 .msg_iovlen = datalen, 83 }; 84 struct mbuf *control; 85 int error; 86 87 /* Convert flags. */ 88 if (flags & CLOUDABI_SOCK_RECV_PEEK) 89 hdr.msg_flags |= MSG_PEEK; 90 if (flags & CLOUDABI_SOCK_RECV_WAITALL) 91 hdr.msg_flags |= MSG_WAITALL; 92 93 control = NULL; 94 error = kern_recvit(td, fd, &hdr, UIO_SYSSPACE, 95 fdslen > 0 ? &control : NULL); 96 if (error != 0) 97 return (error); 98 99 /* Convert return values. */ 100 *rdatalen = td->td_retval[0]; 101 td->td_retval[0] = 0; 102 *rfdslen = 0; 103 *rflags = 0; 104 if (hdr.msg_flags & MSG_TRUNC) 105 *rflags |= CLOUDABI_SOCK_RECV_DATA_TRUNCATED; 106 107 /* Extract file descriptors from SCM_RIGHTS messages. */ 108 if (control != NULL) { 109 struct cmsghdr *chdr; 110 111 hdr.msg_control = mtod(control, void *); 112 hdr.msg_controllen = control->m_len; 113 for (chdr = CMSG_FIRSTHDR(&hdr); chdr != NULL; 114 chdr = CMSG_NXTHDR(&hdr, chdr)) { 115 if (chdr->cmsg_level == SOL_SOCKET && 116 chdr->cmsg_type == SCM_RIGHTS) { 117 size_t nfds; 118 119 nfds = (chdr->cmsg_len - CMSG_LEN(0)) / 120 sizeof(int); 121 if (nfds > fdslen) { 122 /* Unable to store file descriptors. */ 123 *rflags |= 124 CLOUDABI_SOCK_RECV_FDS_TRUNCATED; 125 m_dispose_extcontrolm(control); 126 break; 127 } 128 error = copyout(CMSG_DATA(chdr), fds, 129 nfds * sizeof(int)); 130 if (error != 0) 131 break; 132 fds += nfds; 133 fdslen -= nfds; 134 *rfdslen += nfds; 135 } 136 } 137 if (control != NULL) { 138 if (error != 0) 139 m_dispose_extcontrolm(control); 140 m_free(control); 141 } 142 } 143 return (error); 144 } 145 146 int 147 cloudabi_sock_send(struct thread *td, cloudabi_fd_t fd, struct iovec *data, 148 size_t datalen, const cloudabi_fd_t *fds, size_t fdslen, size_t *rdatalen) 149 { 150 struct msghdr hdr = { 151 .msg_iov = data, 152 .msg_iovlen = datalen, 153 }; 154 struct mbuf *control; 155 int error; 156 157 /* Convert file descriptor array to an SCM_RIGHTS message. */ 158 if (fdslen > MCLBYTES || CMSG_SPACE(fdslen * sizeof(int)) > MCLBYTES) { 159 return (EINVAL); 160 } else if (fdslen > 0) { 161 struct cmsghdr *chdr; 162 163 control = m_get2(CMSG_SPACE(fdslen * sizeof(int)), 164 M_WAITOK, MT_CONTROL, 0); 165 control->m_len = CMSG_SPACE(fdslen * sizeof(int)); 166 167 chdr = mtod(control, struct cmsghdr *); 168 chdr->cmsg_len = CMSG_LEN(fdslen * sizeof(int)); 169 chdr->cmsg_level = SOL_SOCKET; 170 chdr->cmsg_type = SCM_RIGHTS; 171 error = copyin(fds, CMSG_DATA(chdr), fdslen * sizeof(int)); 172 if (error != 0) { 173 m_free(control); 174 return (error); 175 } 176 } else { 177 control = NULL; 178 } 179 180 error = kern_sendit(td, fd, &hdr, MSG_NOSIGNAL, control, UIO_USERSPACE); 181 if (error != 0) 182 return (error); 183 *rdatalen = td->td_retval[0]; 184 td->td_retval[0] = 0; 185 return (0); 186 } 187