1 /* $NetBSD: netbsd32_socket.c,v 1.45 2018/05/03 21:43:33 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2001 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.45 2018/05/03 21:43:33 christos Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #define msg __msg /* Don't ask me! */ 35 #include <sys/mount.h> 36 #include <sys/socket.h> 37 #include <sys/sockio.h> 38 #include <sys/socketvar.h> 39 #include <sys/mbuf.h> 40 #include <sys/ktrace.h> 41 #include <sys/file.h> 42 #include <sys/filedesc.h> 43 #include <sys/syscallargs.h> 44 #include <sys/proc.h> 45 #include <sys/dirent.h> 46 47 #include <compat/netbsd32/netbsd32.h> 48 #include <compat/netbsd32/netbsd32_syscallargs.h> 49 #include <compat/netbsd32/netbsd32_conv.h> 50 51 /* 52 * XXX Assumes that struct sockaddr is compatible. 53 */ 54 55 #define CMSG32_ALIGN(n) (((n) + ALIGNBYTES32) & ~ALIGNBYTES32) 56 #define CMSG32_ASIZE CMSG32_ALIGN(sizeof(struct cmsghdr)) 57 #define CMSG32_DATA(cmsg) (__CASTV(u_char *, cmsg) + CMSG32_ASIZE) 58 #define CMSG32_MSGNEXT(ucmsg, kcmsg) \ 59 (__CASTV(char *, kcmsg) + CMSG32_ALIGN((ucmsg)->cmsg_len)) 60 #define CMSG32_MSGEND(mhdr) \ 61 (__CASTV(char *, (mhdr)->msg_control) + (mhdr)->msg_controllen) 62 63 #define CMSG32_NXTHDR(mhdr, ucmsg, kcmsg) \ 64 __CASTV(struct cmsghdr *, \ 65 CMSG32_MSGNEXT(ucmsg, kcmsg) + \ 66 CMSG32_ASIZE > CMSG32_MSGEND(mhdr) ? 0 : \ 67 CMSG32_MSGNEXT(ucmsg, kcmsg)) 68 #define CMSG32_FIRSTHDR(mhdr) \ 69 __CASTV(struct cmsghdr *, \ 70 (mhdr)->msg_controllen < sizeof(struct cmsghdr) ? 0 : \ 71 (mhdr)->msg_control) 72 73 #define CMSG32_SPACE(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l)) 74 #define CMSG32_LEN(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l)) 75 76 static int 77 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len, 78 struct mbuf *m, char **q, bool *truncated) 79 { 80 struct cmsghdr *cmsg, cmsg32; 81 int i, j, error; 82 83 *truncated = false; 84 cmsg = mtod(m, struct cmsghdr *); 85 do { 86 if ((char *)cmsg == mtod(m, char *) + m->m_len) 87 break; 88 if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg)) 89 return EINVAL; 90 cmsg32 = *cmsg; 91 j = cmsg->cmsg_len - CMSG_LEN(0); 92 i = cmsg32.cmsg_len = CMSG32_LEN(j); 93 if (i > *len) { 94 mp->msg_flags |= MSG_CTRUNC; 95 if (cmsg->cmsg_level == SOL_SOCKET 96 && cmsg->cmsg_type == SCM_RIGHTS) { 97 *truncated = true; 98 return 0; 99 } 100 j -= i - *len; 101 i = *len; 102 } 103 104 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len); 105 error = copyout(&cmsg32, *q, MAX(i, sizeof(cmsg32))); 106 if (error) 107 return (error); 108 if (i > CMSG32_LEN(0)) { 109 error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0), 110 i - CMSG32_LEN(0)); 111 if (error) 112 return (error); 113 } 114 j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0)); 115 if (*len >= j) { 116 *len -= j; 117 *q += j; 118 } else { 119 *q += i; 120 *len = 0; 121 } 122 cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len)); 123 } while (*len > 0); 124 125 return 0; 126 } 127 128 static int 129 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control) 130 { 131 int len, error = 0; 132 struct mbuf *m; 133 char *q; 134 bool truncated; 135 136 len = mp->msg_controllen; 137 if (len <= 0 || control == 0) { 138 mp->msg_controllen = 0; 139 free_control_mbuf(l, control, control); 140 return 0; 141 } 142 143 q = (char *)mp->msg_control; 144 145 for (m = control; len > 0 && m != NULL; m = m->m_next) { 146 error = copyout32_msg_control_mbuf(l, mp, &len, m, &q, 147 &truncated); 148 if (truncated) { 149 m = control; 150 break; 151 } 152 if (error) 153 break; 154 } 155 156 free_control_mbuf(l, control, m); 157 158 mp->msg_controllen = q - (char *)mp->msg_control; 159 return error; 160 } 161 162 int 163 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, 164 register_t *retval) 165 { 166 /* { 167 syscallarg(int) s; 168 syscallarg(netbsd32_msghdrp_t) msg; 169 syscallarg(int) flags; 170 } */ 171 struct netbsd32_msghdr msg32; 172 struct iovec aiov[UIO_SMALLIOV], *iov; 173 struct msghdr msg; 174 int error; 175 struct mbuf *from, *control; 176 size_t iovsz; 177 178 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 179 if (error) 180 return (error); 181 182 iovsz = msg32.msg_iovlen * sizeof(struct iovec); 183 if (msg32.msg_iovlen > UIO_SMALLIOV) { 184 if (msg32.msg_iovlen > IOV_MAX) 185 return (EMSGSIZE); 186 iov = kmem_alloc(iovsz, KM_SLEEP); 187 } else 188 iov = aiov; 189 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov, 190 msg32.msg_iovlen); 191 if (error) 192 goto done; 193 194 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 195 msg.msg_name = NETBSD32PTR64(msg32.msg_name); 196 msg.msg_namelen = msg32.msg_namelen; 197 msg.msg_control = NETBSD32PTR64(msg32.msg_control); 198 msg.msg_controllen = msg32.msg_controllen; 199 msg.msg_iov = iov; 200 msg.msg_iovlen = msg32.msg_iovlen; 201 202 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, 203 &from, msg.msg_control != NULL ? &control : NULL, retval); 204 if (error != 0) 205 goto done; 206 207 if (msg.msg_control != NULL) 208 error = copyout32_msg_control(l, &msg, control); 209 210 if (error == 0) 211 error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0, 212 from); 213 if (from != NULL) 214 m_free(from); 215 if (error == 0) { 216 msg32.msg_namelen = msg.msg_namelen; 217 msg32.msg_controllen = msg.msg_controllen; 218 msg32.msg_flags = msg.msg_flags; 219 ktrkuser("msghdr", &msg, sizeof msg); 220 error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32)); 221 } 222 223 done: 224 if (iov != aiov) 225 kmem_free(iov, iovsz); 226 return (error); 227 } 228 229 static int 230 copyin32_msg_control(struct lwp *l, struct msghdr *mp) 231 { 232 /* 233 * Handle cmsg if there is any. 234 */ 235 struct cmsghdr *cmsg, cmsg32, *cc; 236 struct mbuf *ctl_mbuf; 237 ssize_t resid = mp->msg_controllen; 238 size_t clen, cidx = 0, cspace; 239 u_int8_t *control; 240 int error; 241 242 ctl_mbuf = m_get(M_WAIT, MT_CONTROL); 243 clen = MLEN; 244 control = mtod(ctl_mbuf, void *); 245 memset(control, 0, clen); 246 247 for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc)) 248 { 249 error = copyin(cc, &cmsg32, sizeof(cmsg32)); 250 if (error) 251 goto failure; 252 253 /* 254 * Sanity check the control message length. 255 */ 256 if (cmsg32.cmsg_len > resid || 257 cmsg32.cmsg_len < sizeof(cmsg32)) { 258 error = EINVAL; 259 goto failure; 260 } 261 262 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0)); 263 264 /* Check the buffer is big enough */ 265 if (__predict_false(cidx + cspace > clen)) { 266 u_int8_t *nc; 267 size_t nclen; 268 269 nclen = cidx + cspace; 270 if (nclen >= PAGE_SIZE) { 271 error = EINVAL; 272 goto failure; 273 } 274 nc = realloc(clen <= MLEN ? NULL : control, 275 nclen, M_TEMP, M_WAITOK); 276 if (!nc) { 277 error = ENOMEM; 278 goto failure; 279 } 280 if (cidx <= MLEN) { 281 /* Old buffer was in mbuf... */ 282 memcpy(nc, control, cidx); 283 memset(nc + cidx, 0, nclen - cidx); 284 } else { 285 memset(nc + nclen, 0, nclen - clen); 286 } 287 control = nc; 288 clen = nclen; 289 } 290 291 /* Copy header */ 292 cmsg = (void *)&control[cidx]; 293 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0)); 294 cmsg->cmsg_level = cmsg32.cmsg_level; 295 cmsg->cmsg_type = cmsg32.cmsg_type; 296 297 /* Copyin the data */ 298 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg), 299 cmsg32.cmsg_len - CMSG32_LEN(0)); 300 if (error) 301 goto failure; 302 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len); 303 304 resid -= CMSG32_ALIGN(cmsg32.cmsg_len); 305 cidx += CMSG_ALIGN(cmsg->cmsg_len); 306 } 307 308 /* If we allocated a buffer, attach to mbuf */ 309 if (cidx > MLEN) { 310 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL); 311 ctl_mbuf->m_flags |= M_EXT_RW; 312 } 313 control = NULL; 314 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx); 315 316 mp->msg_control = ctl_mbuf; 317 mp->msg_flags |= MSG_CONTROLMBUF; 318 319 320 return 0; 321 322 failure: 323 if (control != mtod(ctl_mbuf, void *)) 324 free(control, M_MBUF); 325 m_free(ctl_mbuf); 326 return error; 327 } 328 329 int 330 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, 331 register_t *retval) 332 { 333 /* { 334 syscallarg(int) s; 335 syscallarg(const netbsd32_msghdrp_t) msg; 336 syscallarg(int) flags; 337 } */ 338 struct msghdr msg; 339 struct netbsd32_msghdr msg32; 340 struct iovec aiov[UIO_SMALLIOV], *iov = aiov; 341 struct netbsd32_iovec *iov32; 342 size_t iovsz; 343 int error; 344 345 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 346 if (error) 347 return (error); 348 netbsd32_to_msghdr(&msg32, &msg); 349 msg.msg_flags = 0; 350 351 if (CMSG32_FIRSTHDR(&msg)) { 352 error = copyin32_msg_control(l, &msg); 353 if (error) 354 return (error); 355 /* From here on, msg.msg_control is allocated */ 356 } else { 357 msg.msg_control = NULL; 358 msg.msg_controllen = 0; 359 } 360 361 iovsz = msg.msg_iovlen * sizeof(struct iovec); 362 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 363 if ((u_int)msg.msg_iovlen > IOV_MAX) { 364 error = EMSGSIZE; 365 goto out; 366 } 367 iov = kmem_alloc(iovsz, KM_SLEEP); 368 } 369 370 iov32 = NETBSD32PTR64(msg32.msg_iov); 371 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen); 372 if (error) 373 goto out; 374 msg.msg_iov = iov; 375 376 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), 377 retval); 378 /* msg.msg_control freed by do_sys_sendmsg() */ 379 380 if (iov != aiov) 381 kmem_free(iov, iovsz); 382 return (error); 383 384 out: 385 if (iov != aiov) 386 kmem_free(iov, iovsz); 387 if (msg.msg_control) 388 m_free(msg.msg_control); 389 return error; 390 } 391 392 int 393 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, 394 register_t *retval) 395 { 396 /* { 397 syscallarg(int) s; 398 syscallarg(netbsd32_voidp) buf; 399 syscallarg(netbsd32_size_t) len; 400 syscallarg(int) flags; 401 syscallarg(netbsd32_sockaddrp_t) from; 402 syscallarg(netbsd32_intp) fromlenaddr; 403 } */ 404 struct msghdr msg; 405 struct iovec aiov; 406 int error; 407 struct mbuf *from; 408 409 msg.msg_name = NULL; 410 msg.msg_iov = &aiov; 411 msg.msg_iovlen = 1; 412 aiov.iov_base = SCARG_P32(uap, buf); 413 aiov.iov_len = SCARG(uap, len); 414 msg.msg_control = NULL; 415 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 416 417 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval); 418 if (error != 0) 419 return error; 420 421 error = copyout_sockname(SCARG_P32(uap, from), 422 SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from); 423 if (from != NULL) 424 m_free(from); 425 return error; 426 } 427 428 int 429 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, 430 register_t *retval) 431 { 432 /* { 433 syscallarg(int) s; 434 syscallarg(const netbsd32_voidp) buf; 435 syscallarg(netbsd32_size_t) len; 436 syscallarg(int) flags; 437 syscallarg(const netbsd32_sockaddrp_t) to; 438 syscallarg(int) tolen; 439 } */ 440 struct msghdr msg; 441 struct iovec aiov; 442 443 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */ 444 msg.msg_namelen = SCARG(uap, tolen); 445 msg.msg_iov = &aiov; 446 msg.msg_iovlen = 1; 447 msg.msg_control = 0; 448 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */ 449 aiov.iov_len = SCARG(uap, len); 450 msg.msg_flags = 0; 451 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), 452 retval); 453 } 454