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);
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to