Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jul 2011 14:40:32 +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: r223762 - in head/sys: kern sys
Message-ID:  <201107041440.p64EeWx6022884@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107041440.p64EeWx6022884>