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