PERFORCE change 156891 for review

Robert Watson rwatson at FreeBSD.org
Thu Jan 29 15:22:57 PST 2009


http://perforce.freebsd.org/chv.cgi?CH=156891

Change 156891 by rwatson at rwatson_freebsd_capabilities on 2009/01/29 23:22:21

	Add cap_fextract_mmap() and fget_mmap(), which unlike the normal
	versions of these calls, returns a maximum set of mapping-related
	capability rights rather than just checking the passed set.  This
	is merged with maxprot, retained in each mapping to use in
	validating requests to expand rights on a mapping using
	mprotect().  A new capability right, CAP_MAPEXEC, is added; the
	MAP prefix is to more clearly differentiate this from general
	execution rights on binaries represented by capabilities.  None
	of this resolves i386's confusion between read and execute
	rights.
	
	With these change, mmap() tests in the capability regression
	suite are now passed.

Affected files ...

.. //depot/projects/trustedbsd/capabilities/src/sys/kern/kern_descrip.c#18 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#22 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#22 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/file.h#12 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/vm/vm_mmap.c#7 edit

Differences ...

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/kern_descrip.c#18 (text+ko) ====

@@ -2088,7 +2088,7 @@
 #define	FGET_GETCAP	0x00000002
 static __inline int
 _fget(struct thread *td, int fd, struct file **fpp, int flags,
-    cap_rights_t rights, int fget_flags)
+    cap_rights_t rights, u_char *maxprotp, int fget_flags)
 {
 	struct filedesc *fdp;
 	struct file *fp;
@@ -2122,7 +2122,10 @@
 		 * capability and find the underlying object.  From now on
 		 * 'fp' refers to the actual object of interest.
 		 */
-		error = cap_fextract(fp, rights, &fp);
+		if (maxprotp != NULL)
+			error = cap_fextract_mmap(fp, rights, maxprotp, &fp);
+		else
+			error = cap_fextract(fp, rights, &fp);
 		if (error) {
 			FILEDESC_SUNLOCK(fdp);
 			return (error);
@@ -2154,21 +2157,29 @@
 fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, 0, rights, FGET_HOLD));
+	return(_fget(td, fd, fpp, 0, rights, NULL, FGET_HOLD));
+}
+
+int
+fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp,
+    struct file **fpp)
+{
+
+	return (_fget(td, fd, fpp, 0, rights, maxprotp, FGET_HOLD));
 }
 
 int
 fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, FREAD, rights, FGET_HOLD));
+	return(_fget(td, fd, fpp, FREAD, rights, NULL, FGET_HOLD));
 }
 
 int
 fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, FWRITE, rights, FGET_HOLD));
+	return(_fget(td, fd, fpp, FWRITE, rights, NULL, FGET_HOLD));
 }
 
 /*
@@ -2180,7 +2191,7 @@
 fgetcap(struct thread *td, int fd, struct file **fpp)
 {
 
-	return (_fget(td, fd, fpp, 0, 0, FGET_GETCAP | FGET_HOLD));
+	return (_fget(td, fd, fpp, 0, 0, NULL, FGET_GETCAP | FGET_HOLD));
 }
 
 /*
@@ -2198,7 +2209,7 @@
 	int error;
 
 	*vpp = NULL;
-	if ((error = _fget(td, fd, &fp, flags, rights, 0)) != 0)
+	if ((error = _fget(td, fd, &fp, flags, rights, NULL, 0)) != 0)
 		return (error);
 	if (fp->f_vnode == NULL) {
 		error = EINVAL;
@@ -2256,7 +2267,7 @@
 	*spp = NULL;
 	if (fflagp != NULL)
 		*fflagp = 0;
-	if ((error = _fget(td, fd, &fp, 0, rights, 0)) != 0)
+	if ((error = _fget(td, fd, &fp, 0, rights, NULL, 0)) != 0)
 		return (error);
 	if (fp->f_type != DTYPE_SOCKET) {
 		error = ENOTSOCK;

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#22 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2008 Robert N. M. Watson
+ * Copyright (c) 2008-2009 Robert N. M. Watson
  * All rights reserved.
  *
  * WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
@@ -50,7 +50,7 @@
 #include "opt_capabilities.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#21 $");
+__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#22 $");
 
 #include <sys/param.h>
 #include <sys/capability.h>
@@ -68,6 +68,7 @@
 #include <security/audit/audit.h>
 
 #include <vm/uma.h>
+#include <vm/vm.h>
 
 #ifdef CAPABILITIES
 
@@ -184,6 +185,40 @@
 }
 
 /*
+ * 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_fextract_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);
+	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);
+}
+
+/*
  * Extract rights from a capability for monitoring purposes -- not for use in
  * any other way, as we want to keep all capability permission evaluation in
  * this one file.
@@ -446,6 +481,18 @@
 }
 
 int
+cap_fextract_mmap(struct file *fp_cap, u_char *maxprotp, struct file **fpp)
+{
+
+	KASSERT(fp_cap->f_type != DTYPE_CAPABILITY,
+	    ("cap_fextract_mmap: saw capability"));
+
+	*fpp = fp_cap;
+	*maxprotp = VM_PROT_ALL;
+	return (0:
+}
+
+int
 cap_enter(struct thread *td, struct cap_enter_args *uap)
 {
 

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#22 (text+ko) ====

@@ -30,7 +30,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#21 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#22 $
  */
 
 /*
@@ -91,7 +91,8 @@
 #define	CAP_PDGETPID		0x0000100000000000ULL	/* pdgetpid(2) */
 #define	CAP_PDWAIT		0x0000200000000000ULL	/* pdwait(2) */
 #define	CAP_PDKILL		0x0000400000000000ULL	/* pdkill(2) */
-#define	CAP_MASK_VALID		0x00003fffffffffffULL
+#define	CAP_MAPEXEC		0x0000800000000000ULL	/* mmap(2) as exec */
+#define	CAP_MASK_VALID		0x0000ffffffffffffULL
 
 /*
  * Notes:
@@ -142,6 +143,8 @@
  */
 int	cap_fextract(struct file *fp_cap, cap_rights_t rights,
 	    struct file **fpp);
+int	cap_fextract_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

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/file.h#12 (text+ko) ====

@@ -180,6 +180,8 @@
 extern volatile int openfiles;	/* actual number of open files */
 
 int fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp);
+int fget_mmap(struct thread *td, int fd, cap_rights_t rights,
+    u_char *maxprotp, struct file **fpp);
 int fget_read(struct thread *td, int fd, cap_rights_t rights,
     struct file **fpp);
 int fget_write(struct thread *td, int fd, cap_rights_t rights,

==== //depot/projects/trustedbsd/capabilities/src/sys/vm/vm_mmap.c#7 (text+ko) ====

@@ -216,12 +216,13 @@
 	struct vnode *vp;
 	vm_offset_t addr;
 	vm_size_t size, pageoff;
-	vm_prot_t prot, maxprot;
+	vm_prot_t cap_maxprot, prot, maxprot;
 	void *handle;
 	objtype_t handle_type;
 	int flags, error;
 	off_t pos;
 	struct vmspace *vms = td->td_proc->p_vmspace;
+	cap_rights_t rights;
 
 	addr = (vm_offset_t) uap->addr;
 	size = uap->len;
@@ -297,17 +298,25 @@
 		 */
 		handle = NULL;
 		handle_type = OBJT_DEFAULT;
+		cap_maxprot = VM_PROT_ALL;
 		maxprot = VM_PROT_ALL;
 		pos = 0;
 	} else {
 		/*
-		 * Mapping file, get fp for validation and
-		 * don't let the descriptor disappear on us if we block.
-		 *
-		 * XXXRW: should extract capability rights and incorporate
-		 * them into maxprot, just file flags.
+		 * Mapping file, get fp for validation and don't let the
+		 * descriptor disappear on us if we block.  Check capability
+		 * rights, but also return the maximum rights to be combined
+		 * with maxprot later.
 		 */
-		if ((error = fget(td, uap->fd, CAP_MMAP, &fp)) != 0)
+		rights = CAP_MMAP;
+		if (prot & PROT_READ)
+			rights |= CAP_READ;
+		if (prot & PROT_WRITE)
+			rights |= CAP_WRITE;
+		if (prot & PROT_EXEC)
+			rights |= CAP_MAPEXEC;
+		if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot,
+		    &fp)) != 0)
 			goto done;
 		if (fp->f_type == DTYPE_SHM) {
 			handle = fp->f_data;
@@ -374,6 +383,7 @@
 			}
 		} else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) {
 			maxprot |= VM_PROT_WRITE;
+			cap_maxprot |= VM_PROT_WRITE;
 		}
 		handle = (void *)vp;
 		handle_type = OBJT_VNODE;
@@ -392,6 +402,7 @@
 	}
 
 	td->td_fpop = fp;
+	maxprot &= cap_maxprot;
 	error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
 	    flags, handle_type, handle, pos);
 	td->td_fpop = NULL;


More information about the p4-projects mailing list