1/* 2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1982, 1986, 1990, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)sys_socket.c 8.1 (Berkeley) 6/10/93 61 */ 62/* 63 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 64 * support for mandatory and extensible security protections. This notice 65 * is included in support of clause 2.2 (b) of the Apple Public License, 66 * Version 2.0. 67 */ 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/file_internal.h> 72#include <sys/event.h> 73#include <sys/protosw.h> 74#include <sys/socket.h> 75#include <sys/socketvar.h> 76#include <sys/filio.h> /* XXX */ 77#include <sys/sockio.h> 78#include <sys/stat.h> 79#include <sys/uio.h> 80#include <sys/filedesc.h> 81#include <sys/kauth.h> 82#include <sys/signalvar.h> 83#include <sys/vnode.h> 84 85#include <net/if.h> 86#include <net/route.h> 87 88#if CONFIG_MACF 89#include <security/mac_framework.h> 90#endif 91 92/* 93 * File operations on sockets. 94 */ 95static int soo_read(struct fileproc *, struct uio *, int, vfs_context_t ctx); 96static int soo_write(struct fileproc *, struct uio *, int, vfs_context_t ctx); 97static int soo_close(struct fileglob *, vfs_context_t ctx); 98static int soo_drain(struct fileproc *, vfs_context_t ctx); 99 100/* TODO: these should be in header file */ 101extern int soo_ioctl(struct fileproc *, u_long, caddr_t, vfs_context_t ctx); 102extern int soo_stat(struct socket *, void *, int); 103extern int soo_select(struct fileproc *, int, void *, vfs_context_t ctx); 104extern int soo_kqfilter(struct fileproc *, struct knote *, vfs_context_t ctx); 105 106struct fileops socketops = { 107 soo_read, soo_write, soo_ioctl, soo_select, soo_close, 108 soo_kqfilter, soo_drain 109}; 110 111/* ARGSUSED */ 112static int 113soo_read(struct fileproc *fp, struct uio *uio, __unused int flags, 114#if !CONFIG_MACF_SOCKET 115 __unused 116#endif 117 vfs_context_t ctx) 118{ 119 struct socket *so; 120 int stat; 121#if CONFIG_MACF_SOCKET 122 int error; 123#endif 124 125 int (*fsoreceive)(struct socket *so2, struct sockaddr **paddr, 126 struct uio *uio2, struct mbuf **mp0, struct mbuf **controlp, 127 int *flagsp); 128 129 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 130 /* This is not a valid open file descriptor */ 131 return (EBADF); 132 } 133 134#if CONFIG_MACF_SOCKET 135 error = mac_socket_check_receive(vfs_context_ucred(ctx), so); 136 if (error) 137 return (error); 138#endif /* CONFIG_MACF_SOCKET */ 139 140//###LD will have to change 141 fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive; 142 143 stat = (*fsoreceive)(so, 0, uio, 0, 0, 0); 144 return (stat); 145} 146 147/* ARGSUSED */ 148static int 149soo_write(struct fileproc *fp, struct uio *uio, __unused int flags, 150 vfs_context_t ctx) 151{ 152 struct socket *so; 153 int stat; 154 int (*fsosend)(struct socket *so2, struct sockaddr *addr, 155 struct uio *uio2, struct mbuf *top, struct mbuf *control, 156 int flags2); 157 proc_t procp; 158 159#if CONFIG_MACF_SOCKET 160 int error; 161#endif 162 163 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 164 /* This is not a valid open file descriptor */ 165 return (EBADF); 166 } 167 168#if CONFIG_MACF_SOCKET 169 /* JMM - have to fetch the socket's remote addr */ 170 error = mac_socket_check_send(vfs_context_ucred(ctx), so, NULL); 171 if (error) 172 return (error); 173#endif /* CONFIG_MACF_SOCKET */ 174 175 fsosend = so->so_proto->pr_usrreqs->pru_sosend; 176 177 stat = (*fsosend)(so, 0, uio, 0, 0, 0); 178 179 /* Generation of SIGPIPE can be controlled per socket */ 180 procp = vfs_context_proc(ctx); 181 if (stat == EPIPE && !(so->so_flags & SOF_NOSIGPIPE)) 182 psignal(procp, SIGPIPE); 183 184 return (stat); 185} 186 187__private_extern__ int 188soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) 189{ 190 int error = 0; 191 int dropsockref = -1; 192 int int_arg; 193 194 socket_lock(so, 1); 195 196 /* Call the socket filter's ioctl handler for most ioctls */ 197 if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') { 198 error = sflt_ioctl(so, cmd, data); 199 if (error != 0) 200 goto out; 201 } 202 203 switch (cmd) { 204 205 case FIONBIO: /* int */ 206 bcopy(data, &int_arg, sizeof (int_arg)); 207 if (int_arg) 208 so->so_state |= SS_NBIO; 209 else 210 so->so_state &= ~SS_NBIO; 211 212 goto out; 213 214 case FIOASYNC: /* int */ 215 bcopy(data, &int_arg, sizeof (int_arg)); 216 if (int_arg) { 217 so->so_state |= SS_ASYNC; 218 so->so_rcv.sb_flags |= SB_ASYNC; 219 so->so_snd.sb_flags |= SB_ASYNC; 220 } else { 221 so->so_state &= ~SS_ASYNC; 222 so->so_rcv.sb_flags &= ~SB_ASYNC; 223 so->so_snd.sb_flags &= ~SB_ASYNC; 224 } 225 goto out; 226 227 case FIONREAD: /* int */ 228 bcopy(&so->so_rcv.sb_cc, data, sizeof (u_int32_t)); 229 goto out; 230 231 case SIOCSPGRP: /* int */ 232 bcopy(data, &so->so_pgid, sizeof (pid_t)); 233 goto out; 234 235 case SIOCGPGRP: /* int */ 236 bcopy(&so->so_pgid, data, sizeof (pid_t)); 237 goto out; 238 239 case SIOCATMARK: /* int */ 240 int_arg = (so->so_state & SS_RCVATMARK) != 0; 241 bcopy(&int_arg, data, sizeof (int_arg)); 242 goto out; 243 244 case SIOCSETOT: { /* int */ 245 /* 246 * Set socket level options here and then call protocol 247 * specific routine. 248 */ 249 struct socket *cloned_so = NULL; 250 int cloned_fd; 251 252 bcopy(data, &cloned_fd, sizeof (cloned_fd)); 253 254 /* let's make sure it's either -1 or a valid file descriptor */ 255 if (cloned_fd != -1) { 256 error = file_socket(cloned_fd, &cloned_so); 257 if (error) { 258 goto out; 259 } 260 dropsockref = cloned_fd; 261 } 262 263 /* Always set socket non-blocking for OT */ 264 so->so_state |= SS_NBIO; 265 so->so_options |= SO_DONTTRUNC | SO_WANTMORE; 266 so->so_flags |= SOF_NOSIGPIPE | SOF_NPX_SETOPTSHUT; 267 268 if (cloned_so && so != cloned_so) { 269 /* Flags options */ 270 so->so_options |= 271 cloned_so->so_options & ~SO_ACCEPTCONN; 272 273 /* SO_LINGER */ 274 if (so->so_options & SO_LINGER) 275 so->so_linger = cloned_so->so_linger; 276 277 /* SO_SNDBUF, SO_RCVBUF */ 278 if (cloned_so->so_snd.sb_hiwat > 0) { 279 if (sbreserve(&so->so_snd, 280 cloned_so->so_snd.sb_hiwat) == 0) { 281 error = ENOBUFS; 282 goto out; 283 } 284 } 285 if (cloned_so->so_rcv.sb_hiwat > 0) { 286 if (sbreserve(&so->so_rcv, 287 cloned_so->so_rcv.sb_hiwat) == 0) { 288 error = ENOBUFS; 289 goto out; 290 } 291 } 292 293 /* SO_SNDLOWAT, SO_RCVLOWAT */ 294 so->so_snd.sb_lowat = 295 (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ? 296 so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat; 297 so->so_rcv.sb_lowat = 298 (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ? 299 so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat; 300 301 /* SO_SNDTIMEO, SO_RCVTIMEO */ 302 so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo; 303 so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo; 304 } 305 306 error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 307 data, 0, p); 308 /* Just ignore protocols that do not understand it */ 309 if (error == EOPNOTSUPP) 310 error = 0; 311 312 goto out; 313 } 314 } 315 /* 316 * Interface/routing/protocol specific ioctls: 317 * interface and routing ioctls should have a 318 * different entry since a socket's unnecessary 319 */ 320 if (IOCGROUP(cmd) == 'i') { 321 error = ifioctllocked(so, cmd, data, p); 322 } else { 323 if (IOCGROUP(cmd) == 'r') 324 error = rtioctl(cmd, data, p); 325 else 326 error = (*so->so_proto->pr_usrreqs->pru_control)(so, 327 cmd, data, 0, p); 328 } 329 330out: 331 if (dropsockref != -1) 332 file_drop(dropsockref); 333 socket_unlock(so, 1); 334 335 if (error == EJUSTRETURN) 336 error = 0; 337 338 return (error); 339} 340 341int 342soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx) 343{ 344 struct socket *so; 345 int error; 346 proc_t procp = vfs_context_proc(ctx); 347 348 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 349 /* This is not a valid open file descriptor */ 350 return (EBADF); 351 } 352 353 error = soioctl(so, cmd, data, procp); 354 355 if (error == 0 && cmd == SIOCSETOT) 356 fp->f_fglob->fg_flag |= FNONBLOCK; 357 358 return (error); 359} 360 361int 362soo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx) 363{ 364 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 365 int retnum = 0; 366 proc_t procp; 367 368 if (so == NULL || so == (struct socket *)-1) 369 return (0); 370 371 procp = vfs_context_proc(ctx); 372 373#if CONFIG_MACF_SOCKET 374 if (mac_socket_check_select(vfs_context_ucred(ctx), so, which) != 0); 375 return (0); 376#endif /* CONFIG_MACF_SOCKET */ 377 378 379 socket_lock(so, 1); 380 switch (which) { 381 382 case FREAD: 383 so->so_rcv.sb_flags |= SB_SEL; 384 if (soreadable(so)) { 385 retnum = 1; 386 so->so_rcv.sb_flags &= ~SB_SEL; 387 goto done; 388 } 389 selrecord(procp, &so->so_rcv.sb_sel, wql); 390 break; 391 392 case FWRITE: 393 so->so_snd.sb_flags |= SB_SEL; 394 if (sowriteable(so)) { 395 retnum = 1; 396 so->so_snd.sb_flags &= ~SB_SEL; 397 goto done; 398 } 399 selrecord(procp, &so->so_snd.sb_sel, wql); 400 break; 401 402 case 0: 403 so->so_rcv.sb_flags |= SB_SEL; 404 if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) { 405 retnum = 1; 406 so->so_rcv.sb_flags &= ~SB_SEL; 407 goto done; 408 } 409 selrecord(procp, &so->so_rcv.sb_sel, wql); 410 break; 411 } 412 413done: 414 socket_unlock(so, 1); 415 return (retnum); 416} 417 418int 419soo_stat(struct socket *so, void *ub, int isstat64) 420{ 421 int ret; 422 /* warning avoidance ; protected by isstat64 */ 423 struct stat *sb = (struct stat *)0; 424 /* warning avoidance ; protected by isstat64 */ 425 struct stat64 *sb64 = (struct stat64 *)0; 426 427#if CONFIG_MACF_SOCKET 428 ret = mac_socket_check_stat(kauth_cred_get(), so); 429 if (ret) 430 return (ret); 431#endif 432 433 if (isstat64 != 0) { 434 sb64 = (struct stat64 *)ub; 435 bzero((caddr_t)sb64, sizeof (*sb64)); 436 } else { 437 sb = (struct stat *)ub; 438 bzero((caddr_t)sb, sizeof (*sb)); 439 } 440 441 socket_lock(so, 1); 442 if (isstat64 != 0) { 443 sb64->st_mode = S_IFSOCK; 444 if ((so->so_state & SS_CANTRCVMORE) == 0 || 445 so->so_rcv.sb_cc != 0) 446 sb64->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 447 if ((so->so_state & SS_CANTSENDMORE) == 0) 448 sb64->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 449 sb64->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 450 sb64->st_uid = kauth_cred_getuid(so->so_cred); 451 sb64->st_gid = kauth_cred_getgid(so->so_cred); 452 } else { 453 sb->st_mode = S_IFSOCK; 454 if ((so->so_state & SS_CANTRCVMORE) == 0 || 455 so->so_rcv.sb_cc != 0) 456 sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 457 if ((so->so_state & SS_CANTSENDMORE) == 0) 458 sb->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 459 sb->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 460 sb->st_uid = kauth_cred_getuid(so->so_cred); 461 sb->st_gid = kauth_cred_getgid(so->so_cred); 462 } 463 464 ret = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub, isstat64); 465 socket_unlock(so, 1); 466 return (ret); 467} 468 469/* ARGSUSED */ 470static int 471soo_close(struct fileglob *fg, __unused vfs_context_t ctx) 472{ 473 int error = 0; 474 struct socket *sp; 475 476 sp = (struct socket *)fg->fg_data; 477 fg->fg_data = NULL; 478 479 if (sp) 480 error = soclose(sp); 481 482 return (error); 483} 484 485static int 486soo_drain(struct fileproc *fp, __unused vfs_context_t ctx) 487{ 488 int error = 0; 489 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 490 491 if (so) { 492 socket_lock(so, 1); 493 so->so_state |= SS_DRAINING; 494 495 wakeup((caddr_t)&so->so_timeo); 496 sorwakeup(so); 497 sowwakeup(so); 498 soevent(so, SO_FILT_HINT_LOCKED); 499 500 socket_unlock(so, 1); 501 } 502 503 return (error); 504} 505