1/* 2 * Copyright (c) 2000-2013 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 100const struct fileops socketops = { 101 DTYPE_SOCKET, 102 soo_read, 103 soo_write, 104 soo_ioctl, 105 soo_select, 106 soo_close, 107 soo_kqfilter, 108 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 fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive; 141 142 stat = (*fsoreceive)(so, 0, uio, 0, 0, 0); 143 return (stat); 144} 145 146/* ARGSUSED */ 147static int 148soo_write(struct fileproc *fp, struct uio *uio, __unused int flags, 149 vfs_context_t ctx) 150{ 151 struct socket *so; 152 int stat; 153 int (*fsosend)(struct socket *so2, struct sockaddr *addr, 154 struct uio *uio2, struct mbuf *top, struct mbuf *control, 155 int flags2); 156 proc_t procp; 157 158#if CONFIG_MACF_SOCKET 159 int error; 160#endif 161 162 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 163 /* This is not a valid open file descriptor */ 164 return (EBADF); 165 } 166 167#if CONFIG_MACF_SOCKET 168 /* JMM - have to fetch the socket's remote addr */ 169 error = mac_socket_check_send(vfs_context_ucred(ctx), so, NULL); 170 if (error) 171 return (error); 172#endif /* CONFIG_MACF_SOCKET */ 173 174 fsosend = so->so_proto->pr_usrreqs->pru_sosend; 175 176 stat = (*fsosend)(so, 0, uio, 0, 0, 0); 177 178 /* Generation of SIGPIPE can be controlled per socket */ 179 procp = vfs_context_proc(ctx); 180 if (stat == EPIPE && !(so->so_flags & SOF_NOSIGPIPE)) 181 psignal(procp, SIGPIPE); 182 183 return (stat); 184} 185 186__private_extern__ int 187soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) 188{ 189 int error = 0; 190 int int_arg; 191 192 socket_lock(so, 1); 193 194 /* call the socket filter's ioctl handler anything but ours */ 195 if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') { 196 switch (cmd) { 197 case SIOCGASSOCIDS32: 198 case SIOCGASSOCIDS64: 199 case SIOCGCONNIDS32: 200 case SIOCGCONNIDS64: 201 case SIOCGCONNINFO32: 202 case SIOCGCONNINFO64: 203 case SIOCSCONNORDER: 204 case SIOCGCONNORDER: 205 /* don't pass to filter */ 206 break; 207 208 default: 209 error = sflt_ioctl(so, cmd, data); 210 if (error != 0) 211 goto out; 212 break; 213 } 214 } 215 216 switch (cmd) { 217 case FIONBIO: /* int */ 218 bcopy(data, &int_arg, sizeof (int_arg)); 219 if (int_arg) 220 so->so_state |= SS_NBIO; 221 else 222 so->so_state &= ~SS_NBIO; 223 224 goto out; 225 226 case FIOASYNC: /* int */ 227 bcopy(data, &int_arg, sizeof (int_arg)); 228 if (int_arg) { 229 so->so_state |= SS_ASYNC; 230 so->so_rcv.sb_flags |= SB_ASYNC; 231 so->so_snd.sb_flags |= SB_ASYNC; 232 } else { 233 so->so_state &= ~SS_ASYNC; 234 so->so_rcv.sb_flags &= ~SB_ASYNC; 235 so->so_snd.sb_flags &= ~SB_ASYNC; 236 } 237 goto out; 238 239 case FIONREAD: /* int */ 240 bcopy(&so->so_rcv.sb_cc, data, sizeof (u_int32_t)); 241 goto out; 242 243 case SIOCSPGRP: /* int */ 244 bcopy(data, &so->so_pgid, sizeof (pid_t)); 245 goto out; 246 247 case SIOCGPGRP: /* int */ 248 bcopy(&so->so_pgid, data, sizeof (pid_t)); 249 goto out; 250 251 case SIOCATMARK: /* int */ 252 int_arg = (so->so_state & SS_RCVATMARK) != 0; 253 bcopy(&int_arg, data, sizeof (int_arg)); 254 goto out; 255 256 case SIOCSETOT: /* int; deprecated */ 257 error = EOPNOTSUPP; 258 goto out; 259 260 case SIOCGASSOCIDS32: /* so_aidreq32 */ 261 case SIOCGASSOCIDS64: /* so_aidreq64 */ 262 case SIOCGCONNIDS32: /* so_cidreq32 */ 263 case SIOCGCONNIDS64: /* so_cidreq64 */ 264 case SIOCGCONNINFO32: /* so_cinforeq32 */ 265 case SIOCGCONNINFO64: /* so_cinforeq64 */ 266 case SIOCSCONNORDER: /* so_cordreq */ 267 case SIOCGCONNORDER: /* so_cordreq */ 268 error = (*so->so_proto->pr_usrreqs->pru_control)(so, 269 cmd, data, NULL, p); 270 goto out; 271 } 272 273 /* 274 * Interface/routing/protocol specific ioctls: 275 * interface and routing ioctls should have a 276 * different entry since a socket's unnecessary 277 */ 278 if (IOCGROUP(cmd) == 'i') { 279 error = ifioctllocked(so, cmd, data, p); 280 } else { 281 if (IOCGROUP(cmd) == 'r') 282 error = rtioctl(cmd, data, p); 283 else 284 error = (*so->so_proto->pr_usrreqs->pru_control)(so, 285 cmd, data, NULL, p); 286 } 287 288out: 289 socket_unlock(so, 1); 290 291 if (error == EJUSTRETURN) 292 error = 0; 293 294 return (error); 295} 296 297int 298soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx) 299{ 300 struct socket *so; 301 proc_t procp = vfs_context_proc(ctx); 302 303 if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { 304 /* This is not a valid open file descriptor */ 305 return (EBADF); 306 } 307 308 return (soioctl(so, cmd, data, procp)); 309} 310 311int 312soo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx) 313{ 314 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 315 int retnum = 0; 316 proc_t procp; 317 318 if (so == NULL || so == (struct socket *)-1) 319 return (0); 320 321 procp = vfs_context_proc(ctx); 322 323#if CONFIG_MACF_SOCKET 324 if (mac_socket_check_select(vfs_context_ucred(ctx), so, which) != 0) 325 return (0); 326#endif /* CONFIG_MACF_SOCKET */ 327 328 329 socket_lock(so, 1); 330 switch (which) { 331 332 case FREAD: 333 so->so_rcv.sb_flags |= SB_SEL; 334 if (soreadable(so)) { 335 retnum = 1; 336 so->so_rcv.sb_flags &= ~SB_SEL; 337 goto done; 338 } 339 selrecord(procp, &so->so_rcv.sb_sel, wql); 340 break; 341 342 case FWRITE: 343 so->so_snd.sb_flags |= SB_SEL; 344 if (sowriteable(so)) { 345 retnum = 1; 346 so->so_snd.sb_flags &= ~SB_SEL; 347 goto done; 348 } 349 selrecord(procp, &so->so_snd.sb_sel, wql); 350 break; 351 352 case 0: 353 so->so_rcv.sb_flags |= SB_SEL; 354 if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) { 355 retnum = 1; 356 so->so_rcv.sb_flags &= ~SB_SEL; 357 goto done; 358 } 359 selrecord(procp, &so->so_rcv.sb_sel, wql); 360 break; 361 } 362 363done: 364 socket_unlock(so, 1); 365 return (retnum); 366} 367 368int 369soo_stat(struct socket *so, void *ub, int isstat64) 370{ 371 int ret; 372 /* warning avoidance ; protected by isstat64 */ 373 struct stat *sb = (struct stat *)0; 374 /* warning avoidance ; protected by isstat64 */ 375 struct stat64 *sb64 = (struct stat64 *)0; 376 377#if CONFIG_MACF_SOCKET 378 ret = mac_socket_check_stat(kauth_cred_get(), so); 379 if (ret) 380 return (ret); 381#endif 382 383 if (isstat64 != 0) { 384 sb64 = (struct stat64 *)ub; 385 bzero((caddr_t)sb64, sizeof (*sb64)); 386 } else { 387 sb = (struct stat *)ub; 388 bzero((caddr_t)sb, sizeof (*sb)); 389 } 390 391 socket_lock(so, 1); 392 if (isstat64 != 0) { 393 sb64->st_mode = S_IFSOCK; 394 if ((so->so_state & SS_CANTRCVMORE) == 0 || 395 so->so_rcv.sb_cc != 0) 396 sb64->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 397 if ((so->so_state & SS_CANTSENDMORE) == 0) 398 sb64->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 399 sb64->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 400 sb64->st_uid = kauth_cred_getuid(so->so_cred); 401 sb64->st_gid = kauth_cred_getgid(so->so_cred); 402 } else { 403 sb->st_mode = S_IFSOCK; 404 if ((so->so_state & SS_CANTRCVMORE) == 0 || 405 so->so_rcv.sb_cc != 0) 406 sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; 407 if ((so->so_state & SS_CANTSENDMORE) == 0) 408 sb->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; 409 sb->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; 410 sb->st_uid = kauth_cred_getuid(so->so_cred); 411 sb->st_gid = kauth_cred_getgid(so->so_cred); 412 } 413 414 ret = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub, isstat64); 415 socket_unlock(so, 1); 416 return (ret); 417} 418 419/* ARGSUSED */ 420static int 421soo_close(struct fileglob *fg, __unused vfs_context_t ctx) 422{ 423 int error = 0; 424 struct socket *sp; 425 426 sp = (struct socket *)fg->fg_data; 427 fg->fg_data = NULL; 428 429 if (sp) 430 error = soclose(sp); 431 432 return (error); 433} 434 435static int 436soo_drain(struct fileproc *fp, __unused vfs_context_t ctx) 437{ 438 int error = 0; 439 struct socket *so = (struct socket *)fp->f_fglob->fg_data; 440 441 if (so) { 442 socket_lock(so, 1); 443 so->so_state |= SS_DRAINING; 444 445 wakeup((caddr_t)&so->so_timeo); 446 sorwakeup(so); 447 sowwakeup(so); 448 soevent(so, SO_FILT_HINT_LOCKED); 449 450 socket_unlock(so, 1); 451 } 452 453 return (error); 454} 455 456/* 457 * 's' group ioctls. 458 * 459 * The switch statement below does nothing at runtime, as it serves as a 460 * compile time check to ensure that all of the socket 's' ioctls (those 461 * in the 's' group going thru soo_ioctl) that are made available by the 462 * networking stack is unique. This works as long as this routine gets 463 * updated each time a new interface ioctl gets added. 464 * 465 * Any failures at compile time indicates duplicated ioctl values. 466 */ 467static __attribute__((unused)) void 468soioctl_cassert(void) 469{ 470 /* 471 * This is equivalent to _CASSERT() and the compiler wouldn't 472 * generate any instructions, thus for compile time only. 473 */ 474 switch ((u_long)0) { 475 case 0: 476 477 /* bsd/sys/sockio.h */ 478 case SIOCSHIWAT: 479 case SIOCGHIWAT: 480 case SIOCSLOWAT: 481 case SIOCGLOWAT: 482 case SIOCATMARK: 483 case SIOCSPGRP: 484 case SIOCGPGRP: 485 case SIOCSETOT: 486 case SIOCGASSOCIDS32: 487 case SIOCGASSOCIDS64: 488 case SIOCGCONNIDS32: 489 case SIOCGCONNIDS64: 490 case SIOCGCONNINFO32: 491 case SIOCGCONNINFO64: 492 case SIOCSCONNORDER: 493 case SIOCGCONNORDER: 494 ; 495 } 496} 497