Skip site navigation (1)Skip section navigation (2)
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>