Date: Tue, 5 Jul 2011 13:45:10 +0000 (UTC) From: Jonathan Anderson <jonathan@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r223785 - in head/sys: kern sys Message-ID: <201107051345.p65DjAkY070856@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 <sys/cdefs.h> __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 <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/domain.h> #include <sys/fcntl.h> @@ -91,6 +93,7 @@ __FBSDID("$FreeBSD$"); #include <security/audit/audit.h> #include <vm/uma.h> +#include <vm/vm.h> #include <ddb/ddb.h> @@ -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); /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107051345.p65DjAkY070856>