From owner-svn-src-head@FreeBSD.ORG Tue Jul 5 13:45:10 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 87691106566B; Tue, 5 Jul 2011 13:45:10 +0000 (UTC) (envelope-from jonathan@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 76AF38FC0C; Tue, 5 Jul 2011 13:45:10 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p65DjAQF070859; Tue, 5 Jul 2011 13:45:10 GMT (envelope-from jonathan@svn.freebsd.org) Received: (from jonathan@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p65DjAkY070856; Tue, 5 Jul 2011 13:45:10 GMT (envelope-from jonathan@svn.freebsd.org) Message-Id: <201107051345.p65DjAkY070856@svn.freebsd.org> From: Jonathan Anderson Date: Tue, 5 Jul 2011 13:45:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r223785 - in head/sys: kern sys X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jul 2011 13:45:10 -0000 Author: jonathan Date: Tue Jul 5 13:45:10 2011 New Revision: 223785 URL: http://svn.freebsd.org/changeset/base/223785 Log: Rework _fget to accept capability parameters. This new version of _fget() requires new parameters: - cap_rights_t needrights the rights that we expect the capability's rights mask to include (e.g. CAP_READ if we are going to read from the file) - cap_rights_t *haverights used to return the capability's rights mask (ignored if NULL) - u_char *maxprotp the maximum mmap() rights (e.g. VM_PROT_READ) that can be permitted (only used if we are going to mmap the file; ignored if NULL) - int fget_flags FGET_GETCAP if we want to return the capability itself, rather than the underlying object which it wraps Approved by: mentor (rwatson), re (Capsicum blanket) Sponsored by: Google Inc Modified: head/sys/kern/kern_descrip.c head/sys/sys/file.h Modified: head/sys/kern/kern_descrip.c ============================================================================== --- head/sys/kern/kern_descrip.c Tue Jul 5 10:37:17 2011 (r223784) +++ head/sys/kern/kern_descrip.c Tue Jul 5 13:45:10 2011 (r223785) @@ -37,6 +37,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include "opt_ddb.h" #include "opt_ktrace.h" @@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -91,6 +93,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -2259,15 +2262,27 @@ fget_unlocked(struct filedesc *fdp, int * If the descriptor doesn't exist or doesn't match 'flags', EBADF is * returned. * + * If the FGET_GETCAP flag is set, the capability itself will be returned. + * Calling _fget() with FGET_GETCAP on a non-capability will return EINVAL. + * Otherwise, if the file is a capability, its rights will be checked against + * the capability rights mask, and if successful, the object will be unwrapped. + * * If an error occured the non-zero error is returned and *fpp is set to * NULL. Otherwise *fpp is held and set and zero is returned. Caller is * responsible for fdrop(). */ +#define FGET_GETCAP 0x00000001 static __inline int -_fget(struct thread *td, int fd, struct file **fpp, int flags) +_fget(struct thread *td, int fd, struct file **fpp, int flags, + cap_rights_t needrights, cap_rights_t *haverights, u_char *maxprotp, + int fget_flags) { struct filedesc *fdp; struct file *fp; +#ifdef CAPABILITIES + struct file *fp_fromcap; + int error; +#endif *fpp = NULL; if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) @@ -2278,6 +2293,47 @@ _fget(struct thread *td, int fd, struct fdrop(fp, td); return (EBADF); } + +#ifdef CAPABILITIES + /* + * If a capability has been requested, return the capability directly. + * Otherwise, check capability rights, extract the underlying object, + * and check its access flags. + */ + if (fget_flags & FGET_GETCAP) { + if (fp->f_type != DTYPE_CAPABILITY) { + fdrop(fp, td); + return (EINVAL); + } + } else { + if (maxprotp == NULL) + error = cap_funwrap(fp, needrights, &fp_fromcap); + else + error = cap_funwrap_mmap(fp, needrights, maxprotp, + &fp_fromcap); + if (error) { + fdrop(fp, td); + return (error); + } + + /* + * If we've unwrapped a file, drop the original capability + * and hold the new descriptor. fp after this point refers to + * the actual (unwrapped) object, not the capability. + */ + if (fp != fp_fromcap) { + fhold(fp_fromcap); + fdrop(fp, td); + fp = fp_fromcap; + } + } +#else /* !CAPABILITIES */ + KASSERT(fp->f_type != DTYPE_CAPABILITY, + ("%s: saw capability", __func__)); + if (maxprotp != NULL) + *maxprotp = VM_PROT_ALL; +#endif /* CAPABILITIES */ + /* * FREAD and FWRITE failure return EBADF as per POSIX. * @@ -2296,23 +2352,36 @@ int fget(struct thread *td, int fd, struct file **fpp) { - return(_fget(td, fd, fpp, 0)); + return(_fget(td, fd, fpp, 0, 0, NULL, NULL, 0)); } int fget_read(struct thread *td, int fd, struct file **fpp) { - return(_fget(td, fd, fpp, FREAD)); + return(_fget(td, fd, fpp, FREAD, 0, NULL, NULL, 0)); } int fget_write(struct thread *td, int fd, struct file **fpp) { - return(_fget(td, fd, fpp, FWRITE)); + return(_fget(td, fd, fpp, FWRITE, 0, NULL, NULL, 0)); +} + +/* + * Unlike the other fget() calls, which will accept and check capability rights + * but never return capabilities, fgetcap() returns the capability but doesn't + * check capability rights. + */ +int +fgetcap(struct thread *td, int fd, struct file **fpp) +{ + + return (_fget(td, fd, fpp, 0, 0, NULL, NULL, FGET_GETCAP)); } + /* * Like fget() but loads the underlying vnode, or returns an error if the * descriptor does not represent a vnode. Note that pipes use vnodes but @@ -2327,7 +2396,7 @@ _fgetvp(struct thread *td, int fd, struc int error; *vpp = NULL; - if ((error = _fget(td, fd, &fp, flags)) != 0) + if ((error = _fget(td, fd, &fp, flags, 0, NULL, NULL, 0)) != 0) return (error); if (fp->f_vnode == NULL) { error = EINVAL; @@ -2383,7 +2452,7 @@ fgetsock(struct thread *td, int fd, stru *spp = NULL; if (fflagp != NULL) *fflagp = 0; - if ((error = _fget(td, fd, &fp, 0)) != 0) + if ((error = _fget(td, fd, &fp, 0, 0, NULL, NULL, 0)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { error = ENOTSOCK; Modified: head/sys/sys/file.h ============================================================================== --- head/sys/sys/file.h Tue Jul 5 10:37:17 2011 (r223784) +++ head/sys/sys/file.h Tue Jul 5 13:45:10 2011 (r223785) @@ -179,6 +179,7 @@ extern volatile int openfiles; /* actual int fget(struct thread *td, int fd, struct file **fpp); int fget_read(struct thread *td, int fd, struct file **fpp); int fget_write(struct thread *td, int fd, struct file **fpp); +int fgetcap(struct thread *td, int fd, struct file **fpp); int _fdrop(struct file *fp, struct thread *td); /*