From owner-p4-projects@FreeBSD.ORG Mon Jan 21 16:19:03 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 11EEF16A41A; Mon, 21 Jan 2008 16:19:03 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CB1CC16A46C for ; Mon, 21 Jan 2008 16:19:01 +0000 (UTC) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id B969113C4D5 for ; Mon, 21 Jan 2008 16:19:01 +0000 (UTC) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m0LGJ1EN050840 for ; Mon, 21 Jan 2008 16:19:01 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m0LGJ1Tx050803 for perforce@freebsd.org; Mon, 21 Jan 2008 16:19:01 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Date: Mon, 21 Jan 2008 16:19:01 GMT Message-Id: <200801211619.m0LGJ1Tx050803@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to bb+lists.freebsd.perforce@cyrus.watson.org using -f From: Robert Watson To: Perforce Change Reviews Cc: Subject: PERFORCE change 133789 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Jan 2008 16:19:03 -0000 http://perforce.freebsd.org/chv.cgi?CH=133789 Change 133789 by rwatson@rwatson_freebsd_capabilities on 2008/01/21 16:18:42 Implement capability checks for many common socket system calls. Affected files ... .. //depot/projects/trustedbsd/capabilities/src/sys/kern/uipc_syscalls.c#2 edit Differences ... ==== //depot/projects/trustedbsd/capabilities/src/sys/kern/uipc_syscalls.c#2 (text+ko) ==== @@ -36,11 +36,13 @@ __FBSDID("$FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.263 2008/01/13 14:44:09 attilio Exp $"); #include "opt_sctp.h" +#include "opt_capabilities.h" #include "opt_compat.h" #include "opt_ktrace.h" #include "opt_mac.h" #include +#include #include #include #include @@ -106,6 +108,7 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0, "Number of sendfile(2) sf_bufs in use"); +#if 0 /* * Convert a user file descriptor to a kernel file entry. A reference on the * file entry is held upon returning. This is lighter weight than @@ -142,8 +145,60 @@ *fpp = fp; return (error); } +#endif /* + * Convert a user file descriptor to a kernel file entry and check that, if + * it is a capability, the right rights are present. A reference on the file + * entry is held upon returning. + */ +static int +getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights, + struct file **fpp, u_int *fflagp) +{ + struct file *fp; + int error; + + fp = NULL; + if (fdp == NULL) { + *fpp = NULL; + return (EBADF); + } + FILEDESC_SLOCK(fdp); + fp = fget_locked(fdp, fd); + if (fp == NULL) { + error = EBADF; + goto out; + } + + /* + * If the file descriptor is for a capability, test rights and use + * the file descriptor referenced by the capability. + */ +#ifdef CAPABILITIES + if (fp->f_type == DTYPE_CAPABILITY) { + error = cap_fget(fp, rights, &fp); + if (error) { + fp = NULL; + goto out; + } + } +#endif /* CAPABILITIES */ + if (fp->f_vnode == NULL) { + error = EINVAL; + fp = NULL; + goto out; + } else { + fhold(fp); + error = 0; + } +out: + FILEDESC_SUNLOCK(fdp); + *fpp = fp; + return (error); +} + +/* * System call interface to the socket abstraction. */ #if defined(COMPAT_43) @@ -218,7 +273,7 @@ struct file *fp; int error; - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -250,7 +305,8 @@ struct file *fp; int error; - error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp, + NULL); if (error == 0) { so = fp->f_data; #ifdef MAC @@ -345,7 +401,7 @@ } fdp = td->td_proc->p_fd; - error = getsock(fdp, s, &headfp, &fflag); + error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag); if (error) return (error); head = headfp->f_data; @@ -530,7 +586,7 @@ int error; int interrupted = 0; - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -732,11 +788,15 @@ struct socket *so; int i; int len, error; + cap_rights_t rights; #ifdef KTRACE struct uio *ktruio = NULL; #endif - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + rights = CAP_WRITE; + if (mp->msg_name != NULL) + rights |= CAP_CONNECT; + error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL); if (error) return (error); so = (struct socket *)fp->f_data; @@ -931,7 +991,7 @@ if(controlp != NULL) *controlp = 0; - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_READ, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1242,7 +1302,8 @@ struct file *fp; int error; - error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp, + NULL); if (error == 0) { so = fp->f_data; error = soshutdown(so, uap->how); @@ -1304,7 +1365,7 @@ panic("kern_setsockopt called with bad valseg"); } - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_SHUTDOWN, &fp, NULL); if (error == 0) { so = fp->f_data; error = sosetopt(so, &sopt); @@ -1382,7 +1443,7 @@ panic("kern_getsockopt called with bad valseg"); } - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL); if (error == 0) { so = fp->f_data; error = sogetopt(so, &sopt); @@ -1443,7 +1504,8 @@ if (*alen < 0) return (EINVAL); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp, + NULL); if (error) return (error); so = fp->f_data; @@ -1536,7 +1598,8 @@ if (*alen < 0) return (EINVAL); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp, + NULL); if (error) return (error); so = fp->f_data; @@ -1809,8 +1872,8 @@ * The socket must be a stream socket and connected. * Remember if it a blocking or non-blocking socket. */ - if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp, - NULL)) != 0) + if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_WRITE, + &sock_fp, NULL)) != 0) goto out; so = sock_fp->f_data; if (so->so_type != SOCK_STREAM) { @@ -2306,6 +2369,7 @@ #endif struct uio auio; struct iovec iov[1]; + cap_rights_t rights; if (uap->sinfo) { error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); @@ -2313,15 +2377,19 @@ return (error); u_sinfo = &sinfo; } + + rights = CAP_WRITE; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } + rights |= CAP_CONNECT; } - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + /* XXXRW: Is this use of rights right for SCTP? */ + error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); if (error) goto sctp_bad; @@ -2405,6 +2473,7 @@ #endif struct uio auio; struct iovec *iov, *tiov; + cap_rights_t rights; if (uap->sinfo) { error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); @@ -2412,15 +2481,17 @@ return (error); u_sinfo = &sinfo; } + rights = CAP_WRITE; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } + rights |= CAP_CONNECT; } - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); if (error) goto sctp_bad1; @@ -2516,7 +2587,7 @@ #ifdef KTRACE struct uio *ktruio = NULL; #endif - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_READ, &fp, NULL); if (error) { return (error); }