1 /* $NetBSD: netbsd32_socket.c,v 1.42 2015/07/22 14:25:39 maxv 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.42 2015/07/22 14:25:39 maxv 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_DATA(cmsg) \ 57 ((u_char *)(void *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr))) 58 59 #define CMSG32_NXTHDR(mhdr, cmsg) \ 60 (((char *)(cmsg) + CMSG32_ALIGN((cmsg)->cmsg_len) + \ 61 CMSG32_ALIGN(sizeof(struct cmsghdr)) > \ 62 (((char *)(mhdr)->msg_control) + (mhdr)->msg_controllen)) ? \ 63 (struct cmsghdr *)0 : \ 64 (struct cmsghdr *)((char *)(cmsg) + \ 65 CMSG32_ALIGN((cmsg)->cmsg_len))) 66 #define CMSG32_FIRSTHDR(mhdr) \ 67 ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ 68 (struct cmsghdr *)(mhdr)->msg_control : \ 69 (struct cmsghdr *)0) 70 71 #define CMSG32_SPACE(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l)) 72 #define CMSG32_LEN(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l)) 73 74 static int 75 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len, struct mbuf *m, char **q, bool *truncated) 76 { 77 struct cmsghdr *cmsg, cmsg32; 78 int i, j, error; 79 80 *truncated = false; 81 cmsg = mtod(m, struct cmsghdr *); 82 do { 83 if ((char *)cmsg == mtod(m, char *) + m->m_len) 84 break; 85 if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg)) 86 return EINVAL; 87 cmsg32 = *cmsg; 88 j = cmsg->cmsg_len - CMSG_LEN(0); 89 i = cmsg32.cmsg_len = CMSG32_LEN(j); 90 if (i > *len) { 91 mp->msg_flags |= MSG_CTRUNC; 92 if (cmsg->cmsg_level == SOL_SOCKET 93 && cmsg->cmsg_type == SCM_RIGHTS) { 94 *truncated = true; 95 return 0; 96 } 97 j -= i - *len; 98 i = *len; 99 } 100 101 ktrkuser("msgcontrol", cmsg, cmsg->cmsg_len); 102 error = copyout(&cmsg32, *q, MAX(i, sizeof(cmsg32))); 103 if (error) 104 return (error); 105 if (i > CMSG32_LEN(0)) { 106 error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0), i - CMSG32_LEN(0)); 107 if (error) 108 return (error); 109 } 110 j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0)); 111 if (*len >= j) { 112 *len -= j; 113 *q += j; 114 } else { 115 *q += i; 116 *len = 0; 117 } 118 cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len)); 119 } while (*len > 0); 120 121 return 0; 122 } 123 124 static int 125 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control) 126 { 127 int len, error = 0; 128 struct mbuf *m; 129 char *q; 130 bool truncated; 131 132 len = mp->msg_controllen; 133 if (len <= 0 || control == 0) { 134 mp->msg_controllen = 0; 135 free_control_mbuf(l, control, control); 136 return 0; 137 } 138 139 q = (char *)mp->msg_control; 140 141 for (m = control; len > 0 && m != NULL; m = m->m_next) { 142 error = copyout32_msg_control_mbuf(l, mp, &len, m, &q, &truncated); 143 if (truncated) { 144 m = control; 145 break; 146 } 147 if (error) 148 break; 149 } 150 151 free_control_mbuf(l, control, m); 152 153 mp->msg_controllen = q - (char *)mp->msg_control; 154 return error; 155 } 156 157 int 158 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval) 159 { 160 /* { 161 syscallarg(int) s; 162 syscallarg(netbsd32_msghdrp_t) msg; 163 syscallarg(int) flags; 164 } */ 165 struct netbsd32_msghdr msg32; 166 struct iovec aiov[UIO_SMALLIOV], *iov; 167 struct msghdr msg; 168 int error; 169 struct mbuf *from, *control; 170 size_t iovsz; 171 172 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 173 if (error) 174 return (error); 175 176 iovsz = msg32.msg_iovlen * sizeof(struct iovec); 177 if (msg32.msg_iovlen > UIO_SMALLIOV) { 178 if (msg32.msg_iovlen > IOV_MAX) 179 return (EMSGSIZE); 180 iov = kmem_alloc(iovsz, KM_SLEEP); 181 } else 182 iov = aiov; 183 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov, 184 msg32.msg_iovlen); 185 if (error) 186 goto done; 187 188 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 189 msg.msg_name = NETBSD32PTR64(msg32.msg_name); 190 msg.msg_namelen = msg32.msg_namelen; 191 msg.msg_control = NETBSD32PTR64(msg32.msg_control); 192 msg.msg_controllen = msg32.msg_controllen; 193 msg.msg_iov = iov; 194 msg.msg_iovlen = msg32.msg_iovlen; 195 196 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, 197 msg.msg_control != NULL ? &control : NULL, retval); 198 if (error != 0) 199 goto done; 200 201 if (msg.msg_control != NULL) 202 error = copyout32_msg_control(l, &msg, control); 203 204 if (error == 0) 205 error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0, 206 from); 207 if (from != NULL) 208 m_free(from); 209 if (error == 0) { 210 ktrkuser("msghdr", &msg, sizeof msg); 211 msg32.msg_namelen = msg.msg_namelen; 212 msg32.msg_controllen = msg.msg_controllen; 213 msg32.msg_flags = msg.msg_flags; 214 error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32)); 215 } 216 217 done: 218 if (iov != aiov) 219 kmem_free(iov, iovsz); 220 return (error); 221 } 222 223 static int 224 copyin32_msg_control(struct lwp *l, struct msghdr *mp) 225 { 226 /* 227 * Handle cmsg if there is any. 228 */ 229 struct cmsghdr *cmsg, cmsg32, *cc; 230 struct mbuf *ctl_mbuf; 231 ssize_t resid = mp->msg_controllen; 232 size_t clen, cidx = 0, cspace; 233 u_int8_t *control; 234 int error; 235 236 ctl_mbuf = m_get(M_WAIT, MT_CONTROL); 237 clen = MLEN; 238 control = mtod(ctl_mbuf, void *); 239 memset(control, 0, clen); 240 241 cc = CMSG32_FIRSTHDR(mp); 242 do { 243 error = copyin(cc, &cmsg32, sizeof(cmsg32)); 244 if (error) 245 goto failure; 246 247 /* 248 * Sanity check the control message length. 249 */ 250 if (cmsg32.cmsg_len > resid || 251 cmsg32.cmsg_len < sizeof(cmsg32)) { 252 error = EINVAL; 253 goto failure; 254 } 255 256 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0)); 257 258 /* Check the buffer is big enough */ 259 if (__predict_false(cidx + cspace > clen)) { 260 u_int8_t *nc; 261 size_t nclen; 262 263 nclen = cidx + cspace; 264 if (nclen >= PAGE_SIZE) { 265 error = EINVAL; 266 goto failure; 267 } 268 nc = realloc(clen <= MLEN ? NULL : control, 269 nclen, M_TEMP, M_WAITOK); 270 if (!nc) { 271 error = ENOMEM; 272 goto failure; 273 } 274 if (cidx <= MLEN) { 275 /* Old buffer was in mbuf... */ 276 memcpy(nc, control, cidx); 277 memset(nc + cidx, 0, nclen - cidx); 278 } else { 279 memset(nc + nclen, 0, nclen - clen); 280 } 281 control = nc; 282 clen = nclen; 283 } 284 285 /* Copy header */ 286 cmsg = (void *)&control[cidx]; 287 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0)); 288 cmsg->cmsg_level = cmsg32.cmsg_level; 289 cmsg->cmsg_type = cmsg32.cmsg_type; 290 291 /* Copyin the data */ 292 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg), 293 cmsg32.cmsg_len - CMSG32_LEN(0)); 294 if (error) 295 goto failure; 296 297 resid -= CMSG32_ALIGN(cmsg32.cmsg_len); 298 cidx += cmsg->cmsg_len; 299 } while (resid > 0 && (cc = CMSG32_NXTHDR(mp, &cmsg32))); 300 301 /* If we allocated a buffer, attach to mbuf */ 302 if (cidx > MLEN) { 303 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL); 304 ctl_mbuf->m_flags |= M_EXT_RW; 305 } 306 control = NULL; 307 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx); 308 309 mp->msg_control = ctl_mbuf; 310 mp->msg_flags |= MSG_CONTROLMBUF; 311 312 ktrkuser("msgcontrol", mtod(ctl_mbuf, void *), 313 mp->msg_controllen); 314 315 return 0; 316 317 failure: 318 if (control != mtod(ctl_mbuf, void *)) 319 free(control, M_MBUF); 320 m_free(ctl_mbuf); 321 return error; 322 } 323 324 int 325 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval) 326 { 327 /* { 328 syscallarg(int) s; 329 syscallarg(const netbsd32_msghdrp_t) msg; 330 syscallarg(int) flags; 331 } */ 332 struct msghdr msg; 333 struct netbsd32_msghdr msg32; 334 struct iovec aiov[UIO_SMALLIOV], *iov = aiov; 335 struct netbsd32_iovec *iov32; 336 size_t iovsz; 337 int error; 338 339 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 340 if (error) 341 return (error); 342 netbsd32_to_msghdr(&msg32, &msg); 343 msg.msg_flags = 0; 344 345 if (CMSG32_FIRSTHDR(&msg)) { 346 error = copyin32_msg_control(l, &msg); 347 if (error) 348 return (error); 349 /* From here on, msg.msg_control is allocated */ 350 } else { 351 msg.msg_control = NULL; 352 msg.msg_controllen = 0; 353 } 354 355 iovsz = msg.msg_iovlen * sizeof(struct iovec); 356 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 357 if ((u_int)msg.msg_iovlen > IOV_MAX) { 358 error = EMSGSIZE; 359 goto out; 360 } 361 iov = kmem_alloc(iovsz, KM_SLEEP); 362 } 363 364 iov32 = NETBSD32PTR64(msg32.msg_iov); 365 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen); 366 if (error) 367 goto out; 368 msg.msg_iov = iov; 369 370 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 371 /* msg.msg_control freed by do_sys_sendmsg() */ 372 373 if (iov != aiov) 374 kmem_free(iov, iovsz); 375 return (error); 376 377 out: 378 if (iov != aiov) 379 kmem_free(iov, iovsz); 380 if (msg.msg_control) 381 m_free(msg.msg_control); 382 return error; 383 } 384 385 int 386 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval) 387 { 388 /* { 389 syscallarg(int) s; 390 syscallarg(netbsd32_voidp) buf; 391 syscallarg(netbsd32_size_t) len; 392 syscallarg(int) flags; 393 syscallarg(netbsd32_sockaddrp_t) from; 394 syscallarg(netbsd32_intp) fromlenaddr; 395 } */ 396 struct msghdr msg; 397 struct iovec aiov; 398 int error; 399 struct mbuf *from; 400 401 msg.msg_name = NULL; 402 msg.msg_iov = &aiov; 403 msg.msg_iovlen = 1; 404 aiov.iov_base = SCARG_P32(uap, buf); 405 aiov.iov_len = SCARG(uap, len); 406 msg.msg_control = NULL; 407 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 408 409 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval); 410 if (error != 0) 411 return error; 412 413 error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr), 414 MSG_LENUSRSPACE, from); 415 if (from != NULL) 416 m_free(from); 417 return error; 418 } 419 420 int 421 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval) 422 { 423 /* { 424 syscallarg(int) s; 425 syscallarg(const netbsd32_voidp) buf; 426 syscallarg(netbsd32_size_t) len; 427 syscallarg(int) flags; 428 syscallarg(const netbsd32_sockaddrp_t) to; 429 syscallarg(int) tolen; 430 } */ 431 struct msghdr msg; 432 struct iovec aiov; 433 434 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */ 435 msg.msg_namelen = SCARG(uap, tolen); 436 msg.msg_iov = &aiov; 437 msg.msg_iovlen = 1; 438 msg.msg_control = 0; 439 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */ 440 aiov.iov_len = SCARG(uap, len); 441 msg.msg_flags = 0; 442 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 443 } 444