1 /* $NetBSD: uipc_syscalls_43.c,v 1.25 2005/12/11 12:19:56 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1990, 1993 5 * The Regents of the University of California. 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 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_43.c,v 1.25 2005/12/11 12:19:56 christos Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/filedesc.h> 40 #include <sys/kernel.h> 41 #include <sys/proc.h> 42 #include <sys/file.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/stat.h> 46 #include <sys/ioctl.h> 47 #include <sys/fcntl.h> 48 #include <sys/malloc.h> 49 #include <sys/syslog.h> 50 #include <sys/unistd.h> 51 #include <sys/resourcevar.h> 52 #include <sys/mbuf.h> /* for MLEN */ 53 #include <sys/protosw.h> 54 55 #include <sys/mount.h> 56 #include <sys/sa.h> 57 #include <sys/syscallargs.h> 58 59 #include <compat/sys/socket.h> 60 #include <net/if.h> 61 62 #include <compat/common/compat_util.h> 63 #include <compat/sys/socket.h> 64 65 #include <uvm/uvm_extern.h> 66 67 /* 68 * Following 4.3 syscalls were not versioned, even through they should 69 * have been: 70 * connect(2), bind(2), sendto(2) 71 */ 72 73 static int compat_43_sa_put(caddr_t); 74 75 int 76 compat_43_sys_accept(struct lwp *l, void *v, register_t *retval) 77 { 78 struct compat_43_sys_accept_args /* { 79 syscallarg(int) s; 80 syscallarg(caddr_t) name; 81 syscallarg(int *) anamelen; 82 } */ *uap = v; 83 int error; 84 85 if ((error = sys_accept(l, v, retval)) != 0) 86 return error; 87 88 if (SCARG(uap, name) 89 && (error = compat_43_sa_put(SCARG(uap, name)))) 90 return (error); 91 92 return 0; 93 } 94 95 int 96 compat_43_sys_getpeername(struct lwp *l, void *v, register_t *retval) 97 { 98 struct compat_43_sys_getpeername_args /* { 99 syscallarg(int) fdes; 100 syscallarg(caddr_t) asa; 101 syscallarg(int *) alen; 102 } */ *uap = v; 103 104 int error; 105 106 if ((error = sys_getpeername(l, v, retval)) != 0) 107 return error; 108 109 if ((error = compat_43_sa_put(SCARG(uap, asa)))) 110 return (error); 111 112 return 0; 113 } 114 115 int 116 compat_43_sys_getsockname(struct lwp *l, void *v, register_t *retval) 117 { 118 struct compat_43_sys_getsockname_args /* { 119 syscallarg(int) fdes; 120 syscallarg(caddr_t) asa; 121 syscallarg(int *) alen; 122 } */ *uap = v; 123 int error; 124 125 if ((error = sys_getsockname(l, v, retval)) != 0) 126 return error; 127 128 if ((error = compat_43_sa_put(SCARG(uap, asa)))) 129 return (error); 130 131 return 0; 132 } 133 134 int 135 compat_43_sys_recv(struct lwp *l, void *v, register_t *retval) 136 { 137 struct compat_43_sys_recv_args /* { 138 syscallarg(int) s; 139 syscallarg(caddr_t) buf; 140 syscallarg(int) len; 141 syscallarg(int) flags; 142 } */ *uap = v; 143 struct sys_recvfrom_args bra; 144 145 SCARG(&bra, s) = SCARG(uap, s); 146 SCARG(&bra, buf) = SCARG(uap, buf); 147 SCARG(&bra, len) = (size_t) SCARG(uap, len); 148 SCARG(&bra, flags) = SCARG(uap, flags); 149 SCARG(&bra, from) = NULL; 150 SCARG(&bra, fromlenaddr) = NULL; 151 152 return (sys_recvfrom(l, &bra, retval)); 153 } 154 155 int 156 compat_43_sys_recvfrom(struct lwp *l, void *v, register_t *retval) 157 { 158 struct compat_43_sys_recvfrom_args /* { 159 syscallarg(int) s; 160 syscallarg(caddr_t) buf; 161 syscallarg(size_t) len; 162 syscallarg(int) flags; 163 syscallarg(caddr_t) from; 164 syscallarg(int *) fromlenaddr; 165 } */ *uap = v; 166 int error; 167 168 if ((error = sys_recvfrom(l, v, retval))) 169 return (error); 170 171 if (SCARG(uap, from) && (error = compat_43_sa_put(SCARG(uap, from)))) 172 return (error); 173 174 return (0); 175 } 176 177 /* 178 * Old recvmsg. Arrange necessary structures, calls generic code and 179 * adjusts results accordingly. 180 */ 181 int 182 compat_43_sys_recvmsg(struct lwp *l, void *v, register_t *retval) 183 { 184 struct compat_43_sys_recvmsg_args /* { 185 syscallarg(int) s; 186 syscallarg(struct omsghdr *) msg; 187 syscallarg(int) flags; 188 } */ *uap = v; 189 struct proc *p = l->l_proc; 190 struct omsghdr omsg; 191 struct msghdr msg; 192 struct iovec aiov[UIO_SMALLIOV], *iov; 193 int error; 194 195 error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&omsg, 196 sizeof (struct omsghdr)); 197 if (error) 198 return (error); 199 if ((u_int)omsg.msg_iovlen > UIO_SMALLIOV) { 200 if ((u_int)omsg.msg_iovlen > IOV_MAX) 201 return (EMSGSIZE); 202 iov = malloc(sizeof(struct iovec) * omsg.msg_iovlen, 203 M_IOV, M_WAITOK); 204 } else 205 iov = aiov; 206 207 error = copyin((caddr_t)omsg.msg_iov, (caddr_t)iov, 208 (unsigned)(omsg.msg_iovlen * sizeof (struct iovec))); 209 if (error) 210 goto done; 211 212 msg.msg_name = omsg.msg_name; 213 msg.msg_namelen = omsg.msg_namelen; 214 msg.msg_iovlen = omsg.msg_iovlen; 215 msg.msg_iov = iov; 216 msg.msg_flags = SCARG(uap, flags); 217 218 /* 219 * If caller passes accrights, arrange things for generic code to 220 * DTRT. 221 */ 222 if (omsg.msg_accrights && omsg.msg_accrightslen) { 223 caddr_t sg = stackgap_init(p, 0); 224 struct cmsg *ucmsg; 225 226 /* it was this way in 4.4BSD */ 227 if ((u_int) omsg.msg_accrightslen > MLEN) 228 return (EINVAL); 229 230 ucmsg = stackgap_alloc(p, &sg, CMSG_SPACE(omsg.msg_accrightslen)); 231 if (ucmsg == NULL) 232 return (EMSGSIZE); 233 234 msg.msg_control = ucmsg; 235 msg.msg_controllen = CMSG_SPACE(omsg.msg_accrightslen); 236 } else { 237 msg.msg_control = NULL; 238 msg.msg_controllen = 0; 239 } 240 241 error = recvit(l, SCARG(uap, s), &msg, 242 (caddr_t)&SCARG(uap, msg)->msg_namelen, retval); 243 244 /* 245 * If there is any control information and it's SCM_RIGHTS, 246 * pass it back to the program. 247 */ 248 if (!error && omsg.msg_accrights && msg.msg_controllen > 0) { 249 struct cmsghdr *cmsg; 250 251 /* safe - msg.msg_controllen set by kernel */ 252 cmsg = (struct cmsghdr *) malloc(msg.msg_controllen, 253 M_TEMP, M_WAITOK); 254 255 error = copyin(msg.msg_control, cmsg, msg.msg_controllen); 256 if (error) { 257 free(cmsg, M_TEMP); 258 return (error); 259 } 260 261 if (cmsg->cmsg_level != SOL_SOCKET 262 || cmsg->cmsg_type != SCM_RIGHTS 263 || copyout(CMSG_DATA(cmsg), omsg.msg_accrights, 264 cmsg->cmsg_len)) { 265 omsg.msg_accrightslen = 0; 266 } 267 268 free(cmsg, M_TEMP); 269 270 if (!error) { 271 error = copyout(&cmsg->cmsg_len, 272 &SCARG(uap, msg)->msg_accrightslen, sizeof(int)); 273 } 274 } 275 276 if (!error && omsg.msg_name) { 277 int namelen; 278 279 if ((error = copyin(&SCARG(uap, msg)->msg_namelen, &namelen, sizeof(int)) == 0) 280 && namelen > 0) 281 error = compat_43_sa_put(omsg.msg_name); 282 } 283 284 done: 285 if (iov != aiov) 286 free(iov, M_IOV); 287 return (error); 288 } 289 290 int 291 compat_43_sys_send(struct lwp *l, void *v, register_t *retval) 292 { 293 struct compat_43_sys_send_args /* { 294 syscallarg(int) s; 295 syscallarg(caddr_t) buf; 296 syscallarg(int) len; 297 syscallarg(int) flags; 298 } */ *uap = v; 299 struct sys_sendto_args bsa; 300 301 SCARG(&bsa, s) = SCARG(uap, s); 302 SCARG(&bsa, buf) = SCARG(uap, buf); 303 SCARG(&bsa, len) = SCARG(uap, len); 304 SCARG(&bsa, flags) = SCARG(uap, flags); 305 SCARG(&bsa, to) = NULL; 306 SCARG(&bsa, tolen) = 0; 307 308 return (sys_sendto(l, &bsa, retval)); 309 } 310 311 /* 312 * Old sendmsg. Arrange necessary structures, call generic code and 313 * adjust the results accordingly for old code. 314 */ 315 int 316 compat_43_sys_sendmsg(struct lwp *l, void *v, register_t *retval) 317 { 318 struct compat_43_sys_sendmsg_args /* { 319 syscallarg(int) s; 320 syscallarg(caddr_t) msg; 321 syscallarg(int) flags; 322 } */ *uap = v; 323 struct proc *p = l->l_proc; 324 struct omsghdr omsg; 325 struct msghdr msg; 326 struct iovec aiov[UIO_SMALLIOV], *iov; 327 int error; 328 caddr_t sg = stackgap_init(p, 0); 329 330 error = copyin(SCARG(uap, msg), (caddr_t)&omsg, 331 sizeof (struct omsghdr)); 332 if (error) 333 return (error); 334 if ((u_int)omsg.msg_iovlen > UIO_SMALLIOV) { 335 if ((u_int)omsg.msg_iovlen > IOV_MAX) 336 return (EMSGSIZE); 337 iov = malloc(sizeof(struct iovec) * omsg.msg_iovlen, 338 M_IOV, M_WAITOK); 339 } else 340 iov = aiov; 341 error = copyin((caddr_t)omsg.msg_iov, (caddr_t)iov, 342 (unsigned)(omsg.msg_iovlen * sizeof (struct iovec))); 343 if (error) 344 goto done; 345 346 if (omsg.msg_name) { 347 struct osockaddr *osa; 348 struct sockaddr *sa, *usa; 349 350 if ((u_int) omsg.msg_namelen > UCHAR_MAX) 351 return (EINVAL); 352 353 osa = malloc(omsg.msg_namelen, M_TEMP, M_WAITOK); 354 355 if ((error = copyin(omsg.msg_name, osa, omsg.msg_namelen))) { 356 free(osa, M_TEMP); 357 return (error); 358 } 359 360 sa = (struct sockaddr *) osa; 361 sa->sa_family = osa->sa_family; 362 sa->sa_len = omsg.msg_namelen; 363 364 usa = stackgap_alloc(p, &sg, omsg.msg_namelen); 365 if (!usa) { 366 free(osa, M_TEMP); 367 return (ENOMEM); 368 } 369 370 (void) copyout(sa, usa, omsg.msg_namelen); 371 free(osa, M_TEMP); 372 373 msg.msg_name = usa; 374 msg.msg_namelen = omsg.msg_namelen; 375 } else { 376 msg.msg_name = NULL; 377 msg.msg_namelen = 0; 378 } 379 msg.msg_iovlen = omsg.msg_iovlen; 380 msg.msg_iov = iov; 381 msg.msg_flags = 0; 382 383 if (omsg.msg_accrights && omsg.msg_accrightslen != 0) { 384 struct cmsghdr *cmsg, *ucmsg; 385 386 /* it was this way in 4.4BSD */ 387 if ((u_int) omsg.msg_accrightslen > MLEN) 388 return (EINVAL); 389 390 cmsg = malloc(CMSG_SPACE(omsg.msg_accrightslen), M_TEMP, 391 M_WAITOK); 392 cmsg->cmsg_len = CMSG_SPACE(omsg.msg_accrightslen); 393 cmsg->cmsg_level = SOL_SOCKET; 394 cmsg->cmsg_type = SCM_RIGHTS; 395 396 error = copyin(omsg.msg_accrights, CMSG_DATA(cmsg), 397 omsg.msg_accrightslen); 398 if (error) { 399 free(cmsg, M_TEMP); 400 return (error); 401 } 402 403 ucmsg = stackgap_alloc(p, &sg, CMSG_SPACE(omsg.msg_accrightslen)); 404 if (!ucmsg) { 405 free(cmsg, M_TEMP); 406 return (EMSGSIZE); 407 } 408 409 (void) copyout(cmsg, ucmsg, CMSG_SPACE(omsg.msg_accrightslen)); 410 free(cmsg, M_TEMP); 411 412 msg.msg_control = ucmsg; 413 msg.msg_controllen = CMSG_SPACE(omsg.msg_accrightslen); 414 } else { 415 msg.msg_control = NULL; 416 msg.msg_controllen = 0; 417 } 418 419 error = sendit(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval); 420 done: 421 if (iov != aiov) 422 FREE(iov, M_IOV); 423 return (error); 424 } 425 426 static int 427 compat_43_sa_put(from) 428 caddr_t from; 429 { 430 struct osockaddr *osa = (struct osockaddr *) from; 431 struct sockaddr sa; 432 struct osockaddr *kosa; 433 int error, len; 434 435 /* 436 * Only read/write the sockaddr family and length, the rest is 437 * not changed. 438 */ 439 len = sizeof(sa.sa_len) + sizeof(sa.sa_family); 440 441 error = copyin((caddr_t) osa, (caddr_t) &sa, len); 442 if (error) 443 return (error); 444 445 /* Note: we convert from sockaddr sa_family to osockaddr one here */ 446 kosa = (struct osockaddr *) &sa; 447 kosa->sa_family = sa.sa_family; 448 error = copyout(kosa, osa, len); 449 if (error) 450 return (error); 451 452 return (0); 453 } 454 455 int 456 compat_ifioctl(struct socket *so, u_long cmd, caddr_t data, struct lwp *l) 457 { 458 int error, ocmd = cmd; 459 struct ifreq *ifr = (struct ifreq *)data; 460 struct ifnet *ifp = ifunit(ifr->ifr_name); 461 462 if (ifp == NULL) 463 return ENXIO; 464 465 switch (cmd) { 466 case SIOCSIFADDR: 467 case SIOCSIFDSTADDR: 468 case SIOCSIFBRDADDR: 469 case SIOCSIFNETMASK: 470 #if BYTE_ORDER != BIG_ENDIAN 471 if (ifr->ifr_addr.sa_family == 0 && 472 ifr->ifr_addr.sa_len < 16) { 473 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 474 ifr->ifr_addr.sa_len = 16; 475 } 476 #else 477 if (ifr->ifr_addr.sa_len == 0) 478 ifr->ifr_addr.sa_len = 16; 479 #endif 480 break; 481 482 case OSIOCGIFADDR: 483 cmd = SIOCGIFADDR; 484 break; 485 486 case OSIOCGIFDSTADDR: 487 cmd = SIOCGIFDSTADDR; 488 break; 489 490 case OSIOCGIFBRDADDR: 491 cmd = SIOCGIFBRDADDR; 492 break; 493 494 case OSIOCGIFNETMASK: 495 cmd = SIOCGIFNETMASK; 496 } 497 498 error = (*so->so_proto->pr_usrreq)(so, PRU_CONTROL, 499 (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)ifp, l); 500 501 switch (ocmd) { 502 case OSIOCGIFADDR: 503 case OSIOCGIFDSTADDR: 504 case OSIOCGIFBRDADDR: 505 case OSIOCGIFNETMASK: 506 *(u_int16_t *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 507 } 508 return error; 509 } 510