svn commit: r223762 - in head/sys: kern sys
Jonathan Anderson
jonathan at FreeBSD.org
Mon Jul 4 14:40:33 UTC 2011
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
More information about the svn-src-head
mailing list