1/* 2 * Copyright (c) 2000-2007 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 && procp && !(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 struct sockopt sopt; 191 int error = 0; 192 int dropsockref = -1; 193 194 socket_lock(so, 1); 195 196 sopt.sopt_level = cmd; 197 sopt.sopt_name = (int)data; 198 sopt.sopt_p = p; 199 200 /* Call the socket filter's ioctl handler for most ioctls */ 201 if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') { 202 int filtered = 0; 203 struct socket_filter_entry *filter; 204 205 for (filter = so->so_filt; filter && error == 0; 206 filter = filter->sfe_next_onsocket) { 207 if (filter->sfe_filter->sf_filter.sf_ioctl) { 208 if (filtered == 0) { 209 sflt_use(so); 210 socket_unlock(so, 0); 211 filtered = 1; 212 } 213 error = filter->sfe_filter->sf_filter. 214 sf_ioctl(filter->sfe_cookie, so, cmd, data); 215 } 216 } 217 218 if (filtered) { 219 socket_lock(so, 0); 220 sflt_unuse(so); 221 } 222 223 if (error != 0) 224 goto out; 225 } 226 227 switch (cmd) { 228 229 case FIONBIO: 230 if (*(int *)data) 231 so->so_state |= SS_NBIO; 232 else 233 so->so_state &= ~SS_NBIO; 234 235 goto out; 236 237 case FIOASYNC: 238 if (*(int *)data) { 239 so->so_state |= SS_ASYNC; 240 so->so_rcv.sb_flags |= SB_ASYNC; 241 so->so_snd.sb_flags |= SB_ASYNC; 242 } else { 243 so->so_state &= ~SS_ASYNC; 244 so->so_rcv.sb_flags &= ~SB_ASYNC; 245 so->so_snd.sb_flags &= ~SB_ASYNC; 246 } 247 goto out; 248 249 case FIONREAD: 250 *(int *)data = so->so_rcv.sb_cc; 251 goto out; 252 253 case SIOCSPGRP: 254 so->so_pgid = *(int *)data; 255 goto out; 256 257 case SIOCGPGRP: 258 *(int *)data = so->so_pgid; 259 goto out; 260 261 case SIOCATMARK: 262 *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 263 goto out; 264 265 case SIOCSETOT: { 266 /* 267 * Set socket level options here and then call protocol 268 * specific routine. 269 */ 270 struct socket *cloned_so = NULL; 271 int cloned_fd = *(int *)data; 272 273 /* let's make sure it's either -1 or a valid file descriptor */ 274 if (cloned_fd != -1) { 275 error = file_socket(cloned_fd, &cloned_so); 276 if (error) { 277 goto out; 278 } 279 dropsockref = cloned_fd; 280 } 281 282 /* Always set socket non-blocking for OT */ 283 so->so_state |= SS_NBIO; 284 so->so_options |= SO_DONTTRUNC | SO_WANTMORE; 285 so->so_flags |= SOF_NOSIGPIPE; 286 287 if (cloned_so && so != cloned_so) { 288 /* Flags options */ 289 so->so_options |= 290 cloned_so->so_options & ~SO_ACCEPTCONN; 291 292 /* SO_LINGER */ 293 if (so->so_options & SO_LINGER) 294 so->so_linger = cloned_so->so_linger; 295 296 /* SO_SNDBUF, SO_RCVBUF */ 297 if (cloned_so->so_snd.sb_hiwat > 0) { 298 if (sbreserve(&so->so_snd, 299 cloned_so->so_snd.sb_hiwat) == 0) { 300 error = ENOBUFS; 301 goto out; 302 } 303 } 304 if (cloned_so->so_rcv.sb_hiwat > 0) { 305 if (sbreserve(&so->so_rcv, 306 cloned_so->so_rcv.sb_hiwat) == 0) { 307 error = ENOBUFS; 308 goto out; 309 } 310 } 311 312 /* SO_SNDLOWAT, SO_RCVLOWAT */ 313 so->so_snd.sb_lowat = 314 (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ? 315 so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat; 316 so->so_rcv.sb_lowat = 317 (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ? 318 so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat; 319 320 /* SO_SNDTIMEO, SO_RCVTIMEO */ 321 so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo; 322 so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo; 323 } 324 325 error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 326 data, 0, p); 327 /* Just ignore protocols that do not understand it */ 328 if (error == EOPNOTSUPP) 329 error = 0; 330 331 goto out; 332 } 333 } 334 /* 335 * Interface/routing/protocol specific ioctls: 336 * interface and routing ioctls should have a 337 * different entry since a socket's unnecessary 338 */ 339 if (IOCGROUP(cmd) == 'i') { 340 error = ifioctllocked(so, cmd, data, p); 341 } else { 342 if (IOCGROUP(cmd) == 'r') 343 error = rtioctl(cmd, data, p); 344 else 345 error = (*so->so_proto->pr_usrreqs->pru_control)(so, 346 cmd, data, 0, p); 347 } 348 349out: 350 if (dropsockref != -1) 351 file_drop(dropsockref); 352 socket_unlock(so, 1); 353 354 if (error == EJUSTRETURN) 355 error = 0; 356 357 return (error); 358} 359 360int 361soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx) 362{ 363 struct socket *so; 364 int error; 365 proc_t procp = vfs_context_proc(ctx); 366 367 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 368 /* This is not a valid open file descriptor */ 369 return (EBADF); 370 } 371 372 error = soioctl(so, cmd, data, procp); 373 374 if (error == 0 && cmd == SIOCSETOT) 375 fp->f_fglob->fg_flag |= FNONBLOCK; 376 377 return (error); 378} 379 380int 381soo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx) 382{ 383 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 384 int retnum = 0; 385 proc_t procp; 386 387 if (so == NULL || so == (struct socket *)-1) 388 return (0); 389 390 procp = vfs_context_proc(ctx); 391 392#if CONFIG_MACF_SOCKET 393 if (mac_socket_check_select(vfs_context_ucred(ctx), so, which) != 0); 394 return (0); 395#endif /* CONFIG_MACF_SOCKET */ 396 397 398 socket_lock(so, 1); 399 switch (which) { 400 401 case FREAD: 402 so->so_rcv.sb_flags |= SB_SEL; 403 if (soreadable(so)) { 404 retnum = 1; 405 so->so_rcv.sb_flags &= ~SB_SEL; 406 goto done; 407 } 408 selrecord(procp, &so->so_rcv.sb_sel, wql); 409 break; 410 411 case FWRITE: 412 so->so_snd.sb_flags |= SB_SEL; 413 if (sowriteable(so)) { 414 retnum = 1; 415 so->so_snd.sb_flags &= ~SB_SEL; 416 goto done; 417 } 418 selrecord(procp, &so->so_snd.sb_sel, wql); 419 break; 420 421 case 0: 422 so->so_rcv.sb_flags |= SB_SEL; 423 if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) { 424 retnum = 1; 425 so->so_rcv.sb_flags &= ~SB_SEL; 426 goto done; 427 } 428 selrecord(procp, &so->so_rcv.sb_sel, wql); 429 break; 430 } 431 432done: 433 socket_unlock(so, 1); 434 return (retnum); 435} 436 437int 438soo_stat(struct socket *so, void *ub, int isstat64) 439{ 440 int ret; 441 /* warning avoidance ; protected by isstat64 */ 442 struct stat *sb = (struct stat *)0; 443 /* warning avoidance ; protected by isstat64 */ 444 struct stat64 *sb64 = (struct stat64 *)0; 445 446#if CONFIG_MACF_SOCKET 447 ret = mac_socket_check_stat(kauth_cred_get(), so); 448 if (ret) 449 return (ret); 450#endif 451 452 if (isstat64 != 0) { 453 sb64 = (struct stat64 *)ub; 454 bzero((caddr_t)sb64, sizeof (*sb64)); 455 } else { 456 sb = (struct stat *)ub; 457 bzero((caddr_t)sb, sizeof (*sb)); 458 } 459 460 socket_lock(so, 1); 461 if (isstat64 != 0) { 462 sb64->st_mode = S_IFSOCK; 463 if ((so->so_state & SS_CANTRCVMORE) == 0 || 464 so->so_rcv.sb_cc != 0) 465 sb64->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 466 if ((so->so_state & SS_CANTSENDMORE) == 0) 467 sb64->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 468 sb64->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 469 sb64->st_uid = so->so_uid; 470 sb64->st_gid = -1; /* XXX -- what else to do? */ 471 } else { 472 sb->st_mode = S_IFSOCK; 473 if ((so->so_state & SS_CANTRCVMORE) == 0 || 474 so->so_rcv.sb_cc != 0) 475 sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 476 if ((so->so_state & SS_CANTSENDMORE) == 0) 477 sb->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 478 sb->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 479 sb->st_uid = so->so_uid; 480 sb->st_gid = -1; /* XXX -- what else to do? */ 481 } 482 483 ret = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub, isstat64); 484 socket_unlock(so, 1); 485 return (ret); 486} 487 488/* ARGSUSED */ 489static int 490soo_close(struct fileglob *fg, __unused vfs_context_t ctx) 491{ 492 int error = 0; 493 struct socket *sp; 494 495 sp = (struct socket *)fg->fg_data; 496 fg->fg_data = NULL; 497 498 if (sp) 499 error = soclose(sp); 500 501 return (error); 502} 503 504static int 505soo_drain(struct fileproc *fp, __unused vfs_context_t ctx) 506{ 507 int error = 0; 508 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 509 510 if (so) { 511 socket_lock(so, 1); 512 so->so_state |= SS_DRAINING; 513 514 wakeup((caddr_t)&so->so_timeo); 515 sorwakeup(so); 516 sowwakeup(so); 517 518 socket_unlock(so, 1); 519 } 520 521 return (error); 522} 523