X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/91447636331957f3d9b5ca5b508f07c526b0074d..060df5ea7c632b1ac8cc8aac1fb59758165c2084:/bsd/kern/sys_socket.c diff --git a/bsd/kern/sys_socket.c b/bsd/kern/sys_socket.c index 1e7b7d3c0..471cac76a 100644 --- a/bsd/kern/sys_socket.c +++ b/bsd/kern/sys_socket.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -53,6 +59,12 @@ * * @(#)sys_socket.c 8.1 (Berkeley) 6/10/93 */ +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ #include #include @@ -68,104 +80,144 @@ #include #include #include +#include #include #include +#if CONFIG_MACF +#include +#endif + /* * File operations on sockets. */ -int soo_read(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, - int flags, struct proc *p); -int soo_write(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, - int flags, struct proc *p); -int soo_close(struct fileglob *fp, struct proc *p); -int soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, struct proc *p); -int soo_stat(struct socket *so, struct stat *ub); -int soo_select(struct fileproc *fp, int which, void * wql, struct proc *p); -int soo_kqfilter(struct fileproc *fp, struct knote *kn, struct proc *p); -int soo_drain(struct fileproc *fp, struct proc *p); - -struct fileops socketops = - { soo_read, soo_write, soo_ioctl, soo_select, soo_close, soo_kqfilter, soo_drain }; +static int soo_read(struct fileproc *, struct uio *, int, vfs_context_t ctx); +static int soo_write(struct fileproc *, struct uio *, int, vfs_context_t ctx); +static int soo_close(struct fileglob *, vfs_context_t ctx); +static int soo_drain(struct fileproc *, vfs_context_t ctx); + +/* TODO: these should be in header file */ +extern int soo_ioctl(struct fileproc *, u_long, caddr_t, vfs_context_t ctx); +extern int soo_stat(struct socket *, void *, int); +extern int soo_select(struct fileproc *, int, void *, vfs_context_t ctx); +extern int soo_kqfilter(struct fileproc *, struct knote *, vfs_context_t ctx); + +struct fileops socketops = { + soo_read, soo_write, soo_ioctl, soo_select, soo_close, + soo_kqfilter, soo_drain +}; /* ARGSUSED */ -int -soo_read( - struct fileproc *fp, - struct uio *uio, - __unused kauth_cred_t cred, - __unused int flags, - __unused struct proc *p) +static int +soo_read(struct fileproc *fp, struct uio *uio, __unused int flags, +#if !CONFIG_MACF_SOCKET + __unused +#endif + vfs_context_t ctx) { struct socket *so; int stat; - int (*fsoreceive)(struct socket *so2, - struct sockaddr **paddr, - struct uio *uio2, struct mbuf **mp0, - struct mbuf **controlp, int *flagsp); +#if CONFIG_MACF_SOCKET + int error; +#endif + int (*fsoreceive)(struct socket *so2, struct sockaddr **paddr, + struct uio *uio2, struct mbuf **mp0, struct mbuf **controlp, + int *flagsp); + + if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { + /* This is not a valid open file descriptor */ + return (EBADF); + } +#if CONFIG_MACF_SOCKET + error = mac_socket_check_receive(vfs_context_ucred(ctx), so); + if (error) + return (error); +#endif /* CONFIG_MACF_SOCKET */ - if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { - /* This is not a valid open file descriptor */ - return(EBADF); - } //###LD will have to change fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive; - + stat = (*fsoreceive)(so, 0, uio, 0, 0, 0); - return stat; + return (stat); } /* ARGSUSED */ -int -soo_write( - struct fileproc *fp, - struct uio *uio, - __unused kauth_cred_t cred, - __unused int flags, - struct proc *procp) +static int +soo_write(struct fileproc *fp, struct uio *uio, __unused int flags, + vfs_context_t ctx) { struct socket *so; - int (*fsosend)(struct socket *so2, struct sockaddr *addr, - struct uio *uio2, struct mbuf *top, - struct mbuf *control, int flags2); - int stat; + int stat; + int (*fsosend)(struct socket *so2, struct sockaddr *addr, + struct uio *uio2, struct mbuf *top, struct mbuf *control, + int flags2); + proc_t procp; + +#if CONFIG_MACF_SOCKET + int error; +#endif if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { /* This is not a valid open file descriptor */ return (EBADF); } +#if CONFIG_MACF_SOCKET + /* JMM - have to fetch the socket's remote addr */ + error = mac_socket_check_send(vfs_context_ucred(ctx), so, NULL); + if (error) + return (error); +#endif /* CONFIG_MACF_SOCKET */ + fsosend = so->so_proto->pr_usrreqs->pru_sosend; stat = (*fsosend)(so, 0, uio, 0, 0, 0); /* Generation of SIGPIPE can be controlled per socket */ - if (stat == EPIPE && procp && !(so->so_flags & SOF_NOSIGPIPE)) + procp = vfs_context_proc(ctx); + if (stat == EPIPE && !(so->so_flags & SOF_NOSIGPIPE)) psignal(procp, SIGPIPE); - return stat; + return (stat); } __private_extern__ int -soioctl( - struct socket *so, - u_long cmd, - caddr_t data, - struct proc *p) +soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) { - struct sockopt sopt; - int error = 0; + int error = 0; int dropsockref = -1; - socket_lock(so, 1); - sopt.sopt_level = cmd; - sopt.sopt_name = (int)data; - sopt.sopt_p = p; + /* Call the socket filter's ioctl handler for most ioctls */ + if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') { + int filtered = 0; + struct socket_filter_entry *filter; + + for (filter = so->so_filt; filter && error == 0; + filter = filter->sfe_next_onsocket) { + if (filter->sfe_filter->sf_filter.sf_ioctl) { + if (filtered == 0) { + sflt_use(so); + socket_unlock(so, 0); + filtered = 1; + } + error = filter->sfe_filter->sf_filter. + sf_ioctl(filter->sfe_cookie, so, cmd, data); + } + } + + if (filtered) { + socket_lock(so, 0); + sflt_unuse(so); + } + + if (error != 0) + goto out; + } switch (cmd) { @@ -202,131 +254,141 @@ soioctl( goto out; case SIOCATMARK: - *(int *)data = (so->so_state&SS_RCVATMARK) != 0; + *(int *)data = (so->so_state&SS_RCVATMARK) != 0; goto out; case SIOCSETOT: { - /* - * Set socket level options here and then call protocol - * specific routine. - */ - struct socket *cloned_so = NULL; - int cloned_fd = *(int *)data; - - /* let's make sure it's either -1 or a valid file descriptor */ - if (cloned_fd != -1) { - error = file_socket(cloned_fd, &cloned_so); - if (error) { - goto out; - } - dropsockref = cloned_fd; - } - - /* Always set socket non-blocking for OT */ - so->so_state |= SS_NBIO; - so->so_options |= SO_DONTTRUNC | SO_WANTMORE; - so->so_flags |= SOF_NOSIGPIPE; - - if (cloned_so && so != cloned_so) { - /* Flags options */ - so->so_options |= cloned_so->so_options & ~SO_ACCEPTCONN; - - /* SO_LINGER */ - if (so->so_options & SO_LINGER) - so->so_linger = cloned_so->so_linger; - - /* SO_SNDBUF, SO_RCVBUF */ - if (cloned_so->so_snd.sb_hiwat > 0) { - if (sbreserve(&so->so_snd, cloned_so->so_snd.sb_hiwat) == 0) { - error = ENOBUFS; - goto out; - } - } - if (cloned_so->so_rcv.sb_hiwat > 0) { - if (sbreserve(&so->so_rcv, cloned_so->so_rcv.sb_hiwat) == 0) { - error = ENOBUFS; - goto out; - } - } - - /* SO_SNDLOWAT, SO_RCVLOWAT */ - so->so_snd.sb_lowat = - (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ? - so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat; - so->so_rcv.sb_lowat = - (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ? - so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat; - - /* SO_SNDTIMEO, SO_RCVTIMEO */ - so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo; - so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo; - } - - error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, 0, p); - /* Just ignore protocols that do not understand it */ - if (error == EOPNOTSUPP) - error = 0; + /* + * Set socket level options here and then call protocol + * specific routine. + */ + struct socket *cloned_so = NULL; + int cloned_fd = *(int *)data; + + /* let's make sure it's either -1 or a valid file descriptor */ + if (cloned_fd != -1) { + error = file_socket(cloned_fd, &cloned_so); + if (error) { + goto out; + } + dropsockref = cloned_fd; + } + + /* Always set socket non-blocking for OT */ + so->so_state |= SS_NBIO; + so->so_options |= SO_DONTTRUNC | SO_WANTMORE; + so->so_flags |= SOF_NOSIGPIPE | SOF_NPX_SETOPTSHUT; + + if (cloned_so && so != cloned_so) { + /* Flags options */ + so->so_options |= + cloned_so->so_options & ~SO_ACCEPTCONN; + + /* SO_LINGER */ + if (so->so_options & SO_LINGER) + so->so_linger = cloned_so->so_linger; + + /* SO_SNDBUF, SO_RCVBUF */ + if (cloned_so->so_snd.sb_hiwat > 0) { + if (sbreserve(&so->so_snd, + cloned_so->so_snd.sb_hiwat) == 0) { + error = ENOBUFS; + goto out; + } + } + if (cloned_so->so_rcv.sb_hiwat > 0) { + if (sbreserve(&so->so_rcv, + cloned_so->so_rcv.sb_hiwat) == 0) { + error = ENOBUFS; + goto out; + } + } + + /* SO_SNDLOWAT, SO_RCVLOWAT */ + so->so_snd.sb_lowat = + (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ? + so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat; + so->so_rcv.sb_lowat = + (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ? + so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat; + + /* SO_SNDTIMEO, SO_RCVTIMEO */ + so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo; + so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo; + } + + error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, + data, 0, p); + /* Just ignore protocols that do not understand it */ + if (error == EOPNOTSUPP) + error = 0; goto out; - } + } } /* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ - if (IOCGROUP(cmd) == 'i') - error = ifioctllocked(so, cmd, data, p); - else - if (IOCGROUP(cmd) == 'r') - error = rtioctl(cmd, data, p); - else - error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, 0, p); + if (IOCGROUP(cmd) == 'i') { + error = ifioctllocked(so, cmd, data, p); + } else { + if (IOCGROUP(cmd) == 'r') + error = rtioctl(cmd, data, p); + else + error = (*so->so_proto->pr_usrreqs->pru_control)(so, + cmd, data, 0, p); + } out: if (dropsockref != -1) file_drop(dropsockref); socket_unlock(so, 1); - return error; + if (error == EJUSTRETURN) + error = 0; + + return (error); } int -soo_ioctl(fp, cmd, data, p) - struct fileproc *fp; - u_long cmd; - register caddr_t data; - struct proc *p; +soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx) { - register struct socket *so; + struct socket *so; int error; - + proc_t procp = vfs_context_proc(ctx); if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) { /* This is not a valid open file descriptor */ return (EBADF); } - - error = soioctl(so, cmd, data, p); - + + error = soioctl(so, cmd, data, procp); + if (error == 0 && cmd == SIOCSETOT) fp->f_fglob->fg_flag |= FNONBLOCK; - return error; + return (error); } int -soo_select(fp, which, wql, p) - struct fileproc *fp; - int which; - void * wql; - struct proc *p; +soo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx) { - register struct socket *so = (struct socket *)fp->f_fglob->fg_data; - int retnum=0; + struct socket *so = (struct socket *)fp->f_fglob->fg_data; + int retnum = 0; + proc_t procp; - if (so == NULL || so == (struct socket*)-1) + if (so == NULL || so == (struct socket *)-1) return (0); + + procp = vfs_context_proc(ctx); + +#if CONFIG_MACF_SOCKET + if (mac_socket_check_select(vfs_context_ucred(ctx), so, which) != 0); + return (0); +#endif /* CONFIG_MACF_SOCKET */ + socket_lock(so, 1); switch (which) { @@ -338,7 +400,7 @@ soo_select(fp, which, wql, p) so->so_rcv.sb_flags &= ~SB_SEL; goto done; } - selrecord(p, &so->so_rcv.sb_sel, wql); + selrecord(procp, &so->so_rcv.sb_sel, wql); break; case FWRITE: @@ -348,7 +410,7 @@ soo_select(fp, which, wql, p) so->so_snd.sb_flags &= ~SB_SEL; goto done; } - selrecord(p, &so->so_snd.sb_sel, wql); + selrecord(procp, &so->so_snd.sb_sel, wql); break; case 0: @@ -358,34 +420,69 @@ soo_select(fp, which, wql, p) so->so_rcv.sb_flags &= ~SB_SEL; goto done; } - selrecord(p, &so->so_rcv.sb_sel, wql); + selrecord(procp, &so->so_rcv.sb_sel, wql); break; } - + done: socket_unlock(so, 1); return (retnum); } - int -soo_stat(so, ub) - register struct socket *so; - register struct stat *ub; +soo_stat(struct socket *so, void *ub, int isstat64) { - int stat; + int ret; + /* warning avoidance ; protected by isstat64 */ + struct stat *sb = (struct stat *)0; + /* warning avoidance ; protected by isstat64 */ + struct stat64 *sb64 = (struct stat64 *)0; + +#if CONFIG_MACF_SOCKET + ret = mac_socket_check_stat(kauth_cred_get(), so); + if (ret) + return (ret); +#endif + + if (isstat64 != 0) { + sb64 = (struct stat64 *)ub; + bzero((caddr_t)sb64, sizeof (*sb64)); + } else { + sb = (struct stat *)ub; + bzero((caddr_t)sb, sizeof (*sb)); + } - bzero((caddr_t)ub, sizeof (*ub)); socket_lock(so, 1); - ub->st_mode = S_IFSOCK; - stat = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub); + if (isstat64 != 0) { + sb64->st_mode = S_IFSOCK; + if ((so->so_state & SS_CANTRCVMORE) == 0 || + so->so_rcv.sb_cc != 0) + sb64->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if ((so->so_state & SS_CANTSENDMORE) == 0) + sb64->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + sb64->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; + sb64->st_uid = so->so_uid; + sb64->st_gid = -1; /* XXX -- what else to do? */ + } else { + sb->st_mode = S_IFSOCK; + if ((so->so_state & SS_CANTRCVMORE) == 0 || + so->so_rcv.sb_cc != 0) + sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if ((so->so_state & SS_CANTSENDMORE) == 0) + sb->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + sb->st_size = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; + sb->st_uid = so->so_uid; + sb->st_gid = -1; /* XXX -- what else to do? */ + } + + ret = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub, isstat64); socket_unlock(so, 1); - return stat; + return (ret); } /* ARGSUSED */ -int -soo_close(struct fileglob *fg, __unused proc_t p) +static int +soo_close(struct fileglob *fg, __unused vfs_context_t ctx) { int error = 0; struct socket *sp; @@ -393,16 +490,14 @@ soo_close(struct fileglob *fg, __unused proc_t p) sp = (struct socket *)fg->fg_data; fg->fg_data = NULL; - if (sp) - error = soclose(sp); - + error = soclose(sp); return (error); } -int -soo_drain(struct fileproc *fp, __unused struct proc *p) +static int +soo_drain(struct fileproc *fp, __unused vfs_context_t ctx) { int error = 0; struct socket *so = (struct socket *)fp->f_fglob->fg_data; @@ -414,10 +509,9 @@ soo_drain(struct fileproc *fp, __unused struct proc *p) wakeup((caddr_t)&so->so_timeo); sorwakeup(so); sowwakeup(so); - + socket_unlock(so, 1); } - return error; + return (error); } -