1 /* $NetBSD: netbsd32_socket.c,v 1.39 2012/01/20 14:08:07 joerg 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.39 2012/01/20 14:08:07 joerg 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; 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 if (len <= 0) 150 break; 151 } 152 153 free_control_mbuf(l, control, m); 154 155 mp->msg_controllen = q - (char *)mp->msg_control; 156 return error; 157 } 158 159 int 160 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval) 161 { 162 /* { 163 syscallarg(int) s; 164 syscallarg(netbsd32_msghdrp_t) msg; 165 syscallarg(int) flags; 166 } */ 167 struct netbsd32_msghdr msg32; 168 struct iovec aiov[UIO_SMALLIOV], *iov; 169 struct msghdr msg; 170 int error; 171 struct mbuf *from, *control; 172 size_t iovsz; 173 174 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 175 if (error) 176 return (error); 177 178 iovsz = msg32.msg_iovlen * sizeof(struct iovec); 179 if (msg32.msg_iovlen > UIO_SMALLIOV) { 180 if (msg32.msg_iovlen > IOV_MAX) 181 return (EMSGSIZE); 182 iov = kmem_alloc(iovsz, KM_SLEEP); 183 } else 184 iov = aiov; 185 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov, 186 msg32.msg_iovlen); 187 if (error) 188 goto done; 189 190 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 191 msg.msg_name = NETBSD32PTR64(msg32.msg_name); 192 msg.msg_namelen = msg32.msg_namelen; 193 msg.msg_control = NETBSD32PTR64(msg32.msg_control); 194 msg.msg_controllen = msg32.msg_controllen; 195 msg.msg_iov = iov; 196 msg.msg_iovlen = msg32.msg_iovlen; 197 198 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, 199 msg.msg_control != NULL ? &control : NULL, retval); 200 if (error != 0) 201 goto done; 202 203 if (msg.msg_control != NULL) 204 error = copyout32_msg_control(l, &msg, control); 205 206 if (error == 0) 207 error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0, 208 from); 209 if (from != NULL) 210 m_free(from); 211 if (error == 0) { 212 ktrkuser("msghdr", &msg, sizeof msg); 213 msg32.msg_namelen = msg.msg_namelen; 214 msg32.msg_controllen = msg.msg_controllen; 215 msg32.msg_flags = msg.msg_flags; 216 error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32)); 217 } 218 219 done: 220 if (iov != aiov) 221 kmem_free(iov, iovsz); 222 return (error); 223 } 224 225 static int 226 copyin32_msg_control(struct lwp *l, struct msghdr *mp) 227 { 228 /* 229 * Handle cmsg if there is any. 230 */ 231 struct cmsghdr *cmsg, cmsg32, *cc; 232 struct mbuf *ctl_mbuf; 233 ssize_t resid = mp->msg_controllen; 234 size_t clen, cidx = 0, cspace; 235 u_int8_t *control; 236 int error; 237 238 ctl_mbuf = m_get(M_WAIT, MT_CONTROL); 239 clen = MLEN; 240 control = mtod(ctl_mbuf, void *); 241 memset(control, 0, clen); 242 243 cc = CMSG32_FIRSTHDR(mp); 244 do { 245 error = copyin(cc, &cmsg32, sizeof(cmsg32)); 246 if (error) 247 goto failure; 248 249 /* 250 * Sanity check the control message length. 251 */ 252 if (cmsg32.cmsg_len > resid || 253 cmsg32.cmsg_len < sizeof(cmsg32)) { 254 error = EINVAL; 255 goto failure; 256 } 257 258 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0)); 259 260 /* Check the buffer is big enough */ 261 if (__predict_false(cidx + cspace > clen)) { 262 u_int8_t *nc; 263 size_t nclen; 264 265 nclen = cidx + cspace; 266 if (nclen >= PAGE_SIZE) { 267 error = EINVAL; 268 goto failure; 269 } 270 nc = realloc(clen <= MLEN ? NULL : control, 271 nclen, M_TEMP, M_WAITOK); 272 if (!nc) { 273 error = ENOMEM; 274 goto failure; 275 } 276 if (cidx <= MLEN) { 277 /* Old buffer was in mbuf... */ 278 memcpy(nc, control, cidx); 279 memset(nc + cidx, 0, nclen - cidx); 280 } else { 281 memset(nc + nclen, 0, nclen - clen); 282 } 283 control = nc; 284 clen = nclen; 285 } 286 287 /* Copy header */ 288 cmsg = (void *)&control[cidx]; 289 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0)); 290 cmsg->cmsg_level = cmsg32.cmsg_level; 291 cmsg->cmsg_type = cmsg32.cmsg_type; 292 293 /* Copyin the data */ 294 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg), 295 cmsg32.cmsg_len - CMSG32_LEN(0)); 296 if (error) 297 goto failure; 298 299 resid -= CMSG32_ALIGN(cmsg32.cmsg_len); 300 cidx += cmsg->cmsg_len; 301 } while ((cc = CMSG32_NXTHDR(mp, cc)) && resid > 0); 302 303 /* If we allocated a buffer, attach to mbuf */ 304 if (cidx > MLEN) { 305 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL); 306 ctl_mbuf->m_flags |= M_EXT_RW; 307 } 308 control = NULL; 309 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx); 310 311 mp->msg_control = ctl_mbuf; 312 mp->msg_flags |= MSG_CONTROLMBUF; 313 314 ktrkuser("msgcontrol", mtod(ctl_mbuf, void *), 315 mp->msg_controllen); 316 317 return 0; 318 319 failure: 320 if (control != mtod(ctl_mbuf, void *)) 321 free(control, M_MBUF); 322 m_free(ctl_mbuf); 323 return error; 324 } 325 326 int 327 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval) 328 { 329 /* { 330 syscallarg(int) s; 331 syscallarg(const netbsd32_msghdrp_t) msg; 332 syscallarg(int) flags; 333 } */ 334 struct msghdr msg; 335 struct netbsd32_msghdr msg32; 336 struct iovec aiov[UIO_SMALLIOV], *iov; 337 struct netbsd32_iovec *iov32; 338 size_t iovsz; 339 int error; 340 341 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32)); 342 if (error) 343 return (error); 344 netbsd32_to_msghdr(&msg32, &msg); 345 msg.msg_flags = 0; 346 347 if (CMSG32_FIRSTHDR(&msg)) { 348 error = copyin32_msg_control(l, &msg); 349 if (error) 350 return (error); 351 } else { 352 msg.msg_control = NULL; 353 msg.msg_controllen = 0; 354 } 355 356 iovsz = msg.msg_iovlen * sizeof(struct iovec); 357 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) { 358 if ((u_int)msg.msg_iovlen > IOV_MAX) 359 return (EMSGSIZE); 360 iov = kmem_alloc(iovsz, KM_SLEEP); 361 } else 362 iov = aiov; 363 364 iov32 = NETBSD32PTR64(msg32.msg_iov); 365 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen); 366 if (error) 367 goto done; 368 msg.msg_iov = iov; 369 370 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 371 done: 372 if (iov != aiov) 373 kmem_free(iov, iovsz); 374 return (error); 375 } 376 377 int 378 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval) 379 { 380 /* { 381 syscallarg(int) s; 382 syscallarg(netbsd32_voidp) buf; 383 syscallarg(netbsd32_size_t) len; 384 syscallarg(int) flags; 385 syscallarg(netbsd32_sockaddrp_t) from; 386 syscallarg(netbsd32_intp) fromlenaddr; 387 } */ 388 struct msghdr msg; 389 struct iovec aiov; 390 int error; 391 struct mbuf *from; 392 393 msg.msg_name = NULL; 394 msg.msg_iov = &aiov; 395 msg.msg_iovlen = 1; 396 aiov.iov_base = SCARG_P32(uap, buf); 397 aiov.iov_len = SCARG(uap, len); 398 msg.msg_control = NULL; 399 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS; 400 401 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval); 402 if (error != 0) 403 return error; 404 405 error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr), 406 MSG_LENUSRSPACE, from); 407 if (from != NULL) 408 m_free(from); 409 return error; 410 } 411 412 int 413 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval) 414 { 415 /* { 416 syscallarg(int) s; 417 syscallarg(const netbsd32_voidp) buf; 418 syscallarg(netbsd32_size_t) len; 419 syscallarg(int) flags; 420 syscallarg(const netbsd32_sockaddrp_t) to; 421 syscallarg(int) tolen; 422 } */ 423 struct msghdr msg; 424 struct iovec aiov; 425 426 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */ 427 msg.msg_namelen = SCARG(uap, tolen); 428 msg.msg_iov = &aiov; 429 msg.msg_iovlen = 1; 430 msg.msg_control = 0; 431 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */ 432 aiov.iov_len = SCARG(uap, len); 433 msg.msg_flags = 0; 434 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 435 } 436