Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Jul 2011 13:45:10 +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: r223785 - in head/sys: kern sys
Message-ID:  <201107051345.p65DjAkY070856@svn.freebsd.org>

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



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