X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..c7d2c2c6ee645e10cbccdd01c6191873ec77239d:/bsd/kern/sys_socket.c

diff --git a/bsd/kern/sys_socket.c b/bsd/kern/sys_socket.c
index 471cac76a..11df996b6 100644
--- a/bsd/kern/sys_socket.c
+++ b/bsd/kern/sys_socket.c
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * 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
@@ -11,10 +11,10 @@
  * 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.
- * 
+ *
  * 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,
@@ -22,7 +22,7 @@
  * 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_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
@@ -97,15 +97,15 @@ 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
+const struct fileops socketops = {
+	DTYPE_SOCKET,
+	soo_read,
+	soo_write,
+	soo_ioctl,
+	soo_select,
+	soo_close,
+	soo_kqfilter,
+	soo_drain
 };
 
 /* ARGSUSED */
@@ -137,7 +137,6 @@ soo_read(struct fileproc *fp, struct uio *uio, __unused int flags,
 		return (error);
 #endif /* CONFIG_MACF_SOCKET */
 
-//###LD will have to change
 	fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive;
 
 	stat = (*fsoreceive)(so, 0, uio, 0, 0, 0);
@@ -188,49 +187,45 @@ __private_extern__ int
 soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
 {
 	int error = 0;
-	int dropsockref = -1;
+	int int_arg;
 
 	socket_lock(so, 1);
 
-	/* Call the socket filter's ioctl handler for most ioctls */
+	/* call the socket filter's ioctl handler anything but ours */
 	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);
+		switch (cmd) {
+		case SIOCGASSOCIDS32:
+		case SIOCGASSOCIDS64:
+		case SIOCGCONNIDS32:
+		case SIOCGCONNIDS64:
+		case SIOCGCONNINFO32:
+		case SIOCGCONNINFO64:
+		case SIOCSCONNORDER:
+		case SIOCGCONNORDER:
+			/* don't pass to filter */
+			break;
+
+		default:
+			error = sflt_ioctl(so, cmd, data);
+			if (error != 0)
+				goto out;
+			break;
 		}
-
-		if (error != 0)
-			goto out;
 	}
 
 	switch (cmd) {
-
-	case FIONBIO:
-		if (*(int *)data)
+	case FIONBIO:			/* int */
+		bcopy(data, &int_arg, sizeof (int_arg));
+		if (int_arg)
 			so->so_state |= SS_NBIO;
 		else
 			so->so_state &= ~SS_NBIO;
 
 		goto out;
 
-	case FIOASYNC:
-		if (*(int *)data) {
+	case FIOASYNC:			/* int */
+		bcopy(data, &int_arg, sizeof (int_arg));
+		if (int_arg) {
 			so->so_state |= SS_ASYNC;
 			so->so_rcv.sb_flags |= SB_ASYNC;
 			so->so_snd.sb_flags |= SB_ASYNC;
@@ -241,91 +236,40 @@ soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
 		}
 		goto out;
 
-	case FIONREAD:
-		*(int *)data = so->so_rcv.sb_cc;
+	case FIONREAD:			/* int */
+		bcopy(&so->so_rcv.sb_cc, data, sizeof (u_int32_t));
 		goto out;
 
-	case SIOCSPGRP:
-		so->so_pgid = *(int *)data;
+	case SIOCSPGRP:			/* int */
+		bcopy(data, &so->so_pgid, sizeof (pid_t));
 		goto out;
 
-	case SIOCGPGRP:
-		*(int *)data = so->so_pgid;
+	case SIOCGPGRP:			/* int */
+		bcopy(&so->so_pgid, data, sizeof (pid_t));
 		goto out;
 
-	case SIOCATMARK:
-		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
+	case SIOCATMARK:		/* int */
+		int_arg = (so->so_state & SS_RCVATMARK) != 0;
+		bcopy(&int_arg, data, sizeof (int_arg));
 		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 | 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;
+	case SIOCSETOT:			/* int; deprecated */
+		error = EOPNOTSUPP;
+		goto out;
 
+	case SIOCGASSOCIDS32:		/* so_aidreq32 */
+	case SIOCGASSOCIDS64:		/* so_aidreq64 */
+	case SIOCGCONNIDS32:		/* so_cidreq32 */
+	case SIOCGCONNIDS64:		/* so_cidreq64 */
+	case SIOCGCONNINFO32:		/* so_cinforeq32 */
+	case SIOCGCONNINFO64:		/* so_cinforeq64 */
+	case SIOCSCONNORDER:		/* so_cordreq */
+	case SIOCGCONNORDER:		/* so_cordreq */
+		error = (*so->so_proto->pr_usrreqs->pru_control)(so,
+		    cmd, data, NULL, p);
 		goto out;
 	}
-	}
+
 	/*
 	 * Interface/routing/protocol specific ioctls:
 	 * interface and routing ioctls should have a
@@ -338,12 +282,10 @@ soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
 			error = rtioctl(cmd, data, p);
 		else
 			error = (*so->so_proto->pr_usrreqs->pru_control)(so,
-			    cmd, data, 0, p);
+			    cmd, data, NULL, p);
 	}
 
 out:
-	if (dropsockref != -1)
-		file_drop(dropsockref);
 	socket_unlock(so, 1);
 
 	if (error == EJUSTRETURN)
@@ -356,7 +298,6 @@ int
 soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx)
 {
 	struct socket *so;
-	int error;
 	proc_t procp = vfs_context_proc(ctx);
 
 	if ((so = (struct socket *)fp->f_fglob->fg_data) == NULL) {
@@ -364,12 +305,7 @@ soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx)
 		return (EBADF);
 	}
 
-	error = soioctl(so, cmd, data, procp);
-
-	if (error == 0 && cmd == SIOCSETOT)
-		fp->f_fglob->fg_flag |= FNONBLOCK;
-
-	return (error);
+	return (soioctl(so, cmd, data, procp));
 }
 
 int
@@ -381,11 +317,11 @@ soo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
 
 	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);
+	if (mac_socket_check_select(vfs_context_ucred(ctx), so, which) != 0)
 		return (0);
 #endif /* CONFIG_MACF_SOCKET */
 
@@ -461,8 +397,8 @@ soo_stat(struct socket *so, void *ub, int isstat64)
 		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? */
+		sb64->st_uid = kauth_cred_getuid(so->so_cred);
+		sb64->st_gid = kauth_cred_getgid(so->so_cred);
 	} else {
 		sb->st_mode = S_IFSOCK;
 		if ((so->so_state & SS_CANTRCVMORE) == 0 ||
@@ -471,8 +407,8 @@ soo_stat(struct socket *so, void *ub, int isstat64)
 		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? */
+		sb->st_uid = kauth_cred_getuid(so->so_cred);
+		sb->st_gid = kauth_cred_getgid(so->so_cred);
 	}
 
 	ret = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub, isstat64);
@@ -509,9 +445,52 @@ soo_drain(struct fileproc *fp, __unused vfs_context_t ctx)
 		wakeup((caddr_t)&so->so_timeo);
 		sorwakeup(so);
 		sowwakeup(so);
+		soevent(so, SO_FILT_HINT_LOCKED);
 
 		socket_unlock(so, 1);
 	}
 
 	return (error);
 }
+
+/*
+ * 's' group ioctls.
+ *
+ * The switch statement below does nothing at runtime, as it serves as a
+ * compile time check to ensure that all of the socket 's' ioctls (those
+ * in the 's' group going thru soo_ioctl) that are made available by the
+ * networking stack is unique.  This works as long as this routine gets
+ * updated each time a new interface ioctl gets added.
+ *
+ * Any failures at compile time indicates duplicated ioctl values.
+ */
+static __attribute__((unused)) void
+soioctl_cassert(void)
+{
+	/*
+	 * This is equivalent to _CASSERT() and the compiler wouldn't
+	 * generate any instructions, thus for compile time only.
+	 */
+	switch ((u_long)0) {
+	case 0:
+
+	/* bsd/sys/sockio.h */
+	case SIOCSHIWAT:
+	case SIOCGHIWAT:
+	case SIOCSLOWAT:
+	case SIOCGLOWAT:
+	case SIOCATMARK:
+	case SIOCSPGRP:
+	case SIOCGPGRP:
+	case SIOCSETOT:
+	case SIOCGASSOCIDS32:
+	case SIOCGASSOCIDS64:
+	case SIOCGCONNIDS32:
+	case SIOCGCONNIDS64:
+	case SIOCGCONNINFO32:
+	case SIOCGCONNINFO64:
+	case SIOCSCONNORDER:
+	case SIOCGCONNORDER:
+		;
+	}
+}