Author: jonathan
Date: Mon Jul  4 14:40:32 2011
New Revision: 223762
URL: http://svn.freebsd.org/changeset/base/223762

Log:
  Add kernel functions to unwrap capabilities.
  
  cap_funwrap() and cap_funwrap_mmap() unwrap capabilities, exposing the
  underlying object. Attempting to unwrap a capability with an inadequate
  rights mask (e.g. calling cap_funwrap(fp, CAP_WRITE | CAP_MMAP, &result)
  on a capability whose rights mask is CAP_READ | CAP_MMAP) will result in
  ENOTCAPABLE.
  
  Unwrapping a non-capability is effectively a no-op.
  
  These functions will be used by Capsicum-aware versions of _fget(), etc.
  
  Approved by: mentor (rwatson), re (Capsicum blanket)
  Sponsored by: Google Inc

Modified:
  head/sys/kern/sys_capability.c
  head/sys/sys/capability.h

Modified: head/sys/kern/sys_capability.c
==============================================================================
--- head/sys/kern/sys_capability.c      Mon Jul  4 13:55:55 2011        
(r223761)
+++ head/sys/kern/sys_capability.c      Mon Jul  4 14:40:32 2011        
(r223762)
@@ -116,3 +116,125 @@ cap_getmode(struct thread *td, struct ca
 }
 
 #endif /* CAPABILITY_MODE */
+
+#ifdef CAPABILITIES
+
+/*
+ * struct capability describes a capability, and is hung off of its struct
+ * file f_data field.  cap_file and cap_rightss are static once hooked up, as
+ * neither the object it references nor the rights it encapsulates are
+ * permitted to change.  cap_filelist may change when other capabilites are
+ * added or removed from the same file, and is currently protected by the
+ * pool mutex for the object file descriptor.
+ */
+struct capability {
+       struct file     *cap_object;    /* Underlying object's file. */
+       struct file     *cap_file;      /* Back-pointer to cap's file. */
+       cap_rights_t     cap_rights;    /* Mask of rights on object. */
+       LIST_ENTRY(capability)  cap_filelist; /* Object's cap list. */
+};
+
+/*
+ * 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 (ENOTCAPABLE);
+       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.
+ */
+int
+cap_funwrap(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_object;
+       return (0);
+}
+
+/*
+ * Slightly different routine for memory mapping file descriptors: unwrap the
+ * capability and check CAP_MMAP, but also return a bitmask representing the
+ * maximum mapping rights the capability allows on the object.
+ */
+int
+cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp,
+    struct file **fpp)
+{
+       struct capability *c;
+       u_char maxprot;
+       int error;
+
+       if (fp_cap->f_type != DTYPE_CAPABILITY) {
+               *fpp = fp_cap;
+               *maxprotp = VM_PROT_ALL;
+               return (0);
+       }
+       c = fp_cap->f_data;
+       error = cap_check(c, rights | CAP_MMAP);
+       if (error)
+               return (error);
+       *fpp = c->cap_object;
+       maxprot = 0;
+       if (c->cap_rights & CAP_READ)
+               maxprot |= VM_PROT_READ;
+       if (c->cap_rights & CAP_WRITE)
+               maxprot |= VM_PROT_WRITE;
+       if (c->cap_rights & CAP_MAPEXEC)
+               maxprot |= VM_PROT_EXECUTE;
+       *maxprotp = maxprot;
+       return (0);
+}
+
+#else /* !CAPABILITIES */
+
+/*
+ * Stub Capability functions for when options CAPABILITIES isn't compiled
+ * into the kernel.
+ */
+int
+cap_funwrap(struct file *fp_cap, cap_rights_t rights, struct file **fpp)
+{
+
+       KASSERT(fp_cap->f_type != DTYPE_CAPABILITY,
+           ("cap_funwrap: saw capability"));
+
+       *fpp = fp_cap;
+       return (0);
+}
+
+int
+cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp,
+    struct file **fpp)
+{
+
+       KASSERT(fp_cap->f_type != DTYPE_CAPABILITY,
+           ("cap_funwrap_mmap: saw capability"));
+
+       *fpp = fp_cap;
+       *maxprotp = VM_PROT_ALL;
+       return (0);
+}
+
+#endif /* CAPABILITIES */
+

Modified: head/sys/sys/capability.h
==============================================================================
--- head/sys/sys/capability.h   Mon Jul  4 13:55:55 2011        (r223761)
+++ head/sys/sys/capability.h   Mon Jul  4 14:40:32 2011        (r223762)
@@ -38,10 +38,50 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+#include <sys/file.h>
+
+/*
+ * Possible rights on capabilities.
+ *
+ * Notes:
+ * Some system calls don't require a capability in order to perform an
+ * operation on an fd.  These include: close, dup, dup2.
+ *
+ * sendfile is authorized using CAP_READ on the file and CAP_WRITE on the
+ * socket.
+ *
+ * mmap() and aio*() system calls will need special attention as they may
+ * involve reads or writes depending a great deal on context.
+ */
+#define        CAP_READ                0x0000000000000001ULL   /* read/recv */
+#define        CAP_WRITE               0x0000000000000002ULL   /* write/send */
+#define        CAP_MMAP                0x0000000000000004ULL   /* mmap */
+#define        CAP_MAPEXEC             0x0000000000000008ULL   /* mmap(2) as 
exec */
+#define        CAP_MASK_VALID          0x000000000000000fULL
+
 #ifdef _KERNEL
 
 #define IN_CAPABILITY_MODE(td) (td->td_ucred->cr_flags & CRED_FLAG_CAPMODE)
 
+/*
+ * Unwrap a capability if its rights mask is a superset of 'rights'.
+ *
+ * Unwrapping a non-capability is effectively a no-op; the value of fp_cap
+ * is simply copied into fpp.
+ */
+int    cap_funwrap(struct file *fp_cap, cap_rights_t rights,
+           struct file **fpp);
+int    cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights,
+           u_char *maxprotp, struct file **fpp);
+
+/*
+ * For the purposes of procstat(1) and similar tools, allow kern_descrip.c to
+ * extract the rights from a capability.  However, this should not be used by
+ * kernel code generally, instead cap_funwrap() should be used in order to
+ * keep all access control in one place.
+ */
+cap_rights_t   cap_rights(struct file *fp_cap);
+
 #else /* !_KERNEL */
 
 __BEGIN_DECLS
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to