Date: Mon, 21 Jan 2008 11:02:23 GMT From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 133771 for review Message-ID: <200801211102.m0LB2NeC011517@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=133771 Change 133771 by rwatson@rwatson_freebsd_capabilities on 2008/01/21 11:02:01 Use panic() rather than KASSERT() to handle failure to allocate a zone for capabilities -- we want to fail cleanly even without INVARIANTS. Add cap_check() utility routine to test rights on a capability, and use in various fo_* methods. Add cap_fget(), which given a file descriptor that may be a capability, tests the rights against the capability (if any) and returns the actual object file descriptor to operate on. This is just a first hack and it will almost certainly change. Affected files ... .. //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#2 edit .. //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#3 edit Differences ... ==== //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#2 (text+ko) ==== @@ -55,7 +55,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#1 $"); +__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#2 $"); #include <sys/param.h> #include <sys/capability.h> @@ -110,14 +110,55 @@ capability_init(void *dummy __unused) { - capability_zone = uma_zcreate("pipe", sizeof(struct capability), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - KASSERT(capability_zone != NULL, - ("capability_zone not initialized")); + capability_zone = uma_zcreate("capability", + sizeof(struct capability), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, + 0); + if (capability_zone == NULL) + panic("capability_init: capability_zone not initialized"); } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, capability_init, NULL); /* + * Test whether a capability grants the requested rights. + */ +static int +cap_check(struct capability *c, cap_rights_t rights) +{ + + if ((c->cap_rights | rights) != c->cap_rights) + return (EACCES); + return (0); +} + +/* + * Given a file descriptor, test it against a capability rights mask and then + * return the file descriptor on which to actually perform the requested + * operation. As long as the reference to fp_cap remains valid, the returned + * pointer in *fp will remain valid, so no extra reference management is + * required, and the caller should fdrop() fp_cap as normal when done with + * both. + * + * XXXRW: This will almost certainly change. + */ +int +cap_fget(struct file *fp_cap, cap_rights_t rights, struct file **fpp) +{ + struct capability *c; + int error; + + if (fp_cap->f_type != DTYPE_CAPABILITY) { + *fpp = fp_cap; + return (0); + } + c = fp_cap->f_data; + error = cap_check(c, rights); + if (error) + return (error); + *fpp = c->cap_file; + return (0); +} + +/* * Create a new capability reference to either an existing file object or an * an existing capability. */ @@ -140,6 +181,9 @@ * If a new capability is being derived from an existing capability, * then the new capability rights must be a subset of the existing * rights. + * + * XXXRW: Should we have a priv_check() here that can override this + * policy? */ if (fp->f_type == DTYPE_CAPABILITY) { c_old = fp->f_data; @@ -210,15 +254,15 @@ int flags, struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_read: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_READ)) - return (EACCES); - fp_object = c->cap_file; - return (fo_read(fp_object, uio, active_cred, flags, td)); + error = cap_check(c, CAP_READ); + if (error) + return (error); + return (fo_read(c->cap_file, uio, active_cred, flags, td)); } static int @@ -226,15 +270,15 @@ int flags, struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_write: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_WRITE)) - return (EACCES); - fp_object = c->cap_file; - return (fo_write(fp_object, uio, active_cred, flags, td)); + error = cap_check(c, CAP_WRITE); + if (error) + return (error); + return (fo_write(c->cap_file, uio, active_cred, flags, td)); } static int @@ -242,15 +286,15 @@ struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_truncate: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_FTRUNCATE)) - return (EACCES); - fp_object = c->cap_file; - return (fo_truncate(fp_object, length, active_cred, td)); + error = cap_check(c, CAP_FTRUNCATE); + if (error) + return (error); + return (fo_truncate(c->cap_file, length, active_cred, td)); } static int @@ -258,15 +302,15 @@ struct ucred *active_cred, struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_ioctl: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_IOCTL)) - return (EACCES); - fp_object = c->cap_file; - return (fo_ioctl(fp_object, com, data, active_cred, td)); + error = cap_check(c, CAP_IOCTL); + if (error) + return (error); + return (fo_ioctl(c->cap_file, com, data, active_cred, td)); } static int @@ -274,30 +318,30 @@ struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_poll: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_EVENT)) - return (EACCES); - fp_object = c->cap_file; - return (fo_poll(fp_object, events, active_cred, td)); + error = cap_check(c, CAP_EVENT); + if (error) + return (error); + return (fo_poll(c->cap_file, events, active_cred, td)); } static int capability_kqfilter(struct file *fp, struct knote *kn) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_kqfilter: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_EVENT)) - return (EACCES); - fp_object = c->cap_file; - return (fo_kqfilter(fp_object, kn)); + error = cap_check(c, CAP_EVENT); + if (error) + return (error); + return (fo_kqfilter(c->cap_file, kn)); } static int @@ -305,15 +349,15 @@ struct thread *td) { struct capability *c; - struct file *fp_object; + int error; KASSERT(fp->f_type == DTYPE_CAPABILITY, ("capability_stat: !capability")); c = fp->f_data; - if (!(c->cap_rights & CAP_FSTAT)) - return (EACCES); - fp_object = c->cap_file; - return (fo_stat(fp_object, sb, active_cred, td)); + error = cap_check(c, CAP_FSTAT); + if (error) + return (error); + return (fo_stat(c->cap_file, sb, active_cred, td)); } static int ==== //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#3 (text+ko) ==== @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#2 $ + * $P4: //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#3 $ */ /* @@ -105,6 +105,9 @@ */ #ifdef _KERNEL +struct file; +int cap_fget(struct file *fp_cap, cap_rights_t rights, + struct file **fpp); #else /* !_KERNEL */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801211102.m0LB2NeC011517>