PERFORCE change 14779 for review

Brian Feldman green at freebsd.org
Tue Jul 23 15:35:04 GMT 2002


http://people.freebsd.org/~peter/p4db/chv.cgi?CH=14779

Change 14779 by green at green_laptop_2 on 2002/07/23 08:34:07

	Begin support for MAC management of mmap(2)ed files.  Currently,
	revocation at the time of mac_relabel_subject(9) is implemented.

Affected files ...

.. //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#189 edit
.. //depot/projects/trustedbsd/mac/sys/security/mac_biba/mac_biba.c#64 edit
.. //depot/projects/trustedbsd/mac/sys/security/mac_mls/mac_mls.c#52 edit
.. //depot/projects/trustedbsd/mac/sys/sys/mac_policy.h#83 edit

Differences ...

==== //depot/projects/trustedbsd/mac/sys/kern/kern_mac.c#189 (text+ko) ====

@@ -65,6 +65,11 @@
 #include <sys/sx.h>
 #include <sys/sysctl.h>
 
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
 #include <fs/devfs/devfs.h>
 
 #include <net/bpf.h>
@@ -143,8 +148,11 @@
 static int	mac_policy_unregister(struct mac_policy_conf *mpc);
 
 static int	mac_stdcreatevnode_ea(struct vnode *vp);
+static void mac_subject_mmapped_drop_perms(struct thread *td,
+    struct ucred *cred);
+static void mac_subject_mmapped_drop_perms_recurse(struct thread *td,
+    struct ucred *cred, struct vm_map *map);
 
-
 /*
  * mac_policy_list_lock protects the consistency of 'mac_policy_list',
  * the linked list of attached policy modules.  Read-only consumers of
@@ -235,6 +243,162 @@
 const size_t maxlabelsize = 65536;
 
 /*
+ * When relabeling a subject, call out to the policies for the maximum
+ * permission allowed for each object type we know about in its
+ * memory space, and revoke access (in the least surprising ways we
+ * know) when necessary.  The process lock is not held here.
+ */
+static void
+mac_subject_mmapped_drop_perms(struct thread *td, struct ucred *cred)
+{
+
+	/* XXX freeze all other threads */
+	mtx_lock(&Giant);
+	mac_subject_mmapped_drop_perms_recurse(td, cred,
+	    &td->td_proc->p_vmspace->vm_map);
+	mtx_unlock(&Giant);
+	/* XXX allow other threads to continue */
+}
+
+static __inline const char *
+prot2str(vm_prot_t prot)
+{
+
+	switch (prot & VM_PROT_ALL) {
+	case VM_PROT_READ:
+		return ("r--");
+	case VM_PROT_READ | VM_PROT_WRITE:
+		return ("rw-");
+	case VM_PROT_READ | VM_PROT_EXECUTE:
+		return ("r-x");
+	case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+		return ("rwx");
+	case VM_PROT_WRITE:
+		return ("-w-");
+	case VM_PROT_EXECUTE:
+		return ("--x");
+	case VM_PROT_WRITE | VM_PROT_EXECUTE:
+		return ("-wx");
+	default:
+		return ("---");
+	}
+}
+
+static void
+mac_subject_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred,
+    struct vm_map *map)
+{
+	struct vm_map_entry *vme;
+	vm_prot_t result, revokeperms;
+	vm_object_t object;
+	vm_ooffset_t offset;
+	struct vnode *vp;
+
+	vm_map_lock_read(map);
+	for (vme = map->header.next; vme != &map->header; vme = vme->next) {
+		if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
+			mac_subject_mmapped_drop_perms_recurse(td, cred,
+			    vme->object.sub_map);
+			continue;
+		}
+		/*
+		 * Skip over entries that obviously are not shared.
+		 */
+		if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
+		    !vme->max_protection)
+			continue;
+		/*
+		 * Drill down to the deepest backing object.
+		 */
+		offset = vme->offset;
+		object = vme->object.vm_object;
+		if (object == NULL)
+			continue;
+		while (object->backing_object != NULL) {
+			object = object->backing_object;
+			offset += object->backing_object_offset;
+		}
+		/*
+		 * At the moment, vm_maps and objects aren't considered
+		 * by the MAC system, so only things with backing by a
+		 * normal object (read: vnodes) are checked.
+		 */
+		if (object->type != OBJT_VNODE)
+			continue;
+		vp = (struct vnode *)object->handle;
+		result = VM_PROT_ALL;
+		/*
+		 * This should be some sort of MAC_BITWISE, maybe :)
+		 */
+		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+		MAC_BOOLEAN(cred_check_vnode_mmap_perms, &, cred,
+		    vp, &vp->v_label);
+		VOP_UNLOCK(vp, 0, td);
+		/*
+		 * Find out what maximum protection we may be allowing
+		 * now but a policy needs to get removed.
+		 */
+		revokeperms = vme->max_protection & ~result;
+		if (!revokeperms)
+			continue;
+		printf("pid %d: revoking %s perms from %#lx:%d "
+		    "(max %s/cur %s)\n", td->td_proc->p_pid,
+		    prot2str(revokeperms), vme->start, vme->end - vme->start,
+		    prot2str(vme->max_protection), prot2str(vme->protection));
+		vm_map_lock_upgrade(map);
+		/*
+		 * This is the really simple case: if a map has more
+		 * max_protection than is allowed, but it's not being
+		 * actually used (that is, the current protection is
+		 * still allowed), we can just wipe it out and do
+		 * nothing more.
+		 */
+		if ((vme->protection & revokeperms) == 0) {
+			vme->max_protection -= revokeperms;
+		} else {
+			if (revokeperms & VM_PROT_WRITE) {
+				/*
+				 * In the more complicated case, flush out all
+				 * pending changes to the object then turn it
+				 * copy-on-write.
+				 */
+				vm_object_reference(object);
+				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+				vm_object_page_clean(object,
+				    OFF_TO_IDX(offset),
+				    OFF_TO_IDX(offset + vme->end - vme->start +
+					PAGE_MASK),
+				    OBJPC_SYNC);
+				VOP_UNLOCK(vp, 0, td);
+				vm_object_deallocate(object);
+				/*
+				 * Why bother if there's no read permissions
+				 * anymore?  For the rest of it, we need to
+				 * leave the write permissions on for COW
+				 * to happen.
+				 */
+				if ((revokeperms & VM_PROT_READ) == 0)
+					vme->eflags |= MAP_ENTRY_COW |
+					    MAP_ENTRY_NEEDS_COPY;
+			}
+			if (revokeperms & VM_PROT_EXECUTE) {
+				vme->max_protection &= ~VM_PROT_EXECUTE;
+				vme->protection &= ~VM_PROT_EXECUTE;
+			}
+			if (revokeperms & VM_PROT_READ) {
+				vme->max_protection = 0;
+				vme->protection = 0;
+			}
+			pmap_protect(map->pmap, vme->start, vme->end,
+			    vme->protection & ~revokeperms);
+			vm_map_simplify_entry(map, vme);
+		}
+		vm_map_lock_downgrade(map);
+	}
+	vm_map_unlock_read(map);
+}
+
+/*
  * Initialize the MAC subsystem, including appropriate SMP locks.
  */
 static void
@@ -614,6 +778,10 @@
 			mpc->mpc_ops->mpo_cred_check_stat_vnode =
 			    mpe->mpe_function;
 			break;
+		case MAC_CRED_CHECK_VNODE_MMAP_PERMS:
+			mpc->mpc_ops->mpo_cred_check_vnode_mmap_perms =
+			    mpe->mpe_function;
+			break;
 		case MAC_IFNET_CHECK_SEND_MBUF:
 			mpc->mpc_ops->mpo_ifnet_check_send_mbuf =
 			    mpe->mpe_function;
@@ -1987,11 +2155,17 @@
 	return (error);
 }
 
+/*
+ * When the subject's label changes, it may require revocation of privilege
+ * to mapped objects.  This can't be done on-the-fly later with a unified
+ * buffer cache.
+ */
 static void
 mac_relabel_subject(struct ucred *cred, struct label *newlabel)
 {
 
 	MAC_PERFORM(relabel_subject, cred, newlabel);
+	mac_subject_mmapped_drop_perms(curthread, cred);
 }
 
 void
@@ -2568,10 +2742,11 @@
 
 	setsugid(p);
 	crcopy(newcred, oldcred);
+	PROC_UNLOCK(p);
 	mac_relabel_subject(newcred, &intlabel);
 
+	PROC_LOCK(p);
 	p->p_ucred = newcred;
-
 	PROC_UNLOCK(p);
 	crfree(oldcred);
 	mac_destroy_temp(&intlabel);

==== //depot/projects/trustedbsd/mac/sys/security/mac_biba/mac_biba.c#64 (text+ko) ====

@@ -70,6 +70,8 @@
 #include <netinet/in.h>
 #include <netinet/ip_var.h>
 
+#include <vm/vm.h>
+
 #include <security/mac_biba/mac_biba.h>
 
 SYSCTL_DECL(_security_mac);
@@ -1816,6 +1818,26 @@
 	return (mac_biba_equal_single(p, s) ? 0 : EACCES);
 }
 
+static int
+mac_biba_cred_check_vnode_mmap_perms(struct ucred *cred, struct vnode *vp,
+    struct label *label)
+{
+	struct mac_biba *subj, *obj;
+	vm_prot_t prot = 0;
+
+	if (!mac_biba_enabled)
+		return (0);
+
+	subj = SLOT(&cred->cr_label);
+	obj = SLOT(label);
+
+	if (mac_biba_dominate_single(obj, subj))
+		prot |= VM_PROT_READ | VM_PROT_EXECUTE;
+	if (mac_biba_dominate_single(subj, obj))
+		prot |= VM_PROT_WRITE;
+	return (prot);
+}
+
 static struct mac_policy_op_entry mac_biba_ops[] =
 {
 	{ MAC_DESTROY,
@@ -2010,6 +2032,8 @@
 	    (macop_t)mac_biba_ifnet_check_send_mbuf },
 	{ MAC_SOCKET_CHECK_RECEIVE_MBUF,
 	    (macop_t)mac_biba_socket_check_receive_mbuf },
+	{ MAC_CRED_CHECK_VNODE_MMAP_PERMS,
+	    (macop_t)mac_biba_cred_check_vnode_mmap_perms },
 	{ MAC_OP_LAST, NULL }
 };
 

==== //depot/projects/trustedbsd/mac/sys/security/mac_mls/mac_mls.c#52 (text+ko) ====

@@ -70,6 +70,8 @@
 #include <netinet/in.h>
 #include <netinet/ip_var.h>
 
+#include <vm/vm.h>
+
 #include <security/mac_mls/mac_mls.h>
 
 SYSCTL_DECL(_security_mac);
@@ -1759,6 +1761,26 @@
 	return (mac_mls_equal_single(p, s) ? 0 : EACCES);
 }
 
+static int
+mac_mls_cred_check_vnode_mmap_perms(struct ucred *cred, struct vnode *vp,
+    struct label *label)
+{
+	struct mac_mls *subj, *obj;
+	vm_prot_t prot = 0;
+
+	if (!mac_mls_enabled)
+		return (0);
+
+	subj = SLOT(&cred->cr_label);
+	obj = SLOT(label);
+
+	if (mac_mls_dominate_single(subj, obj))
+		prot |= VM_PROT_READ | VM_PROT_EXECUTE;
+	if (mac_mls_dominate_single(obj, subj))
+		prot |= VM_PROT_WRITE;
+	return (prot);
+}
+
 static struct mac_policy_op_entry mac_mls_ops[] =
 {
 	{ MAC_DESTROY,
@@ -1953,6 +1975,8 @@
 	    (macop_t)mac_mls_ifnet_check_send_mbuf },
 	{ MAC_SOCKET_CHECK_RECEIVE_MBUF,
 	    (macop_t)mac_mls_socket_check_receive_mbuf },
+	{ MAC_CRED_CHECK_VNODE_MMAP_PERMS,
+	    (macop_t)mac_mls_cred_check_vnode_mmap_perms },
 	{ MAC_OP_LAST, NULL }
 };
 

==== //depot/projects/trustedbsd/mac/sys/sys/mac_policy.h#83 (text+ko) ====

@@ -313,6 +313,9 @@
 		    struct proc *proc, int signum);
 	int	(*mpo_cred_check_stat_vnode)(struct ucred *cred,
 		    struct vnode *vp, struct label *label);
+	/* XXX should be vm_prot_t, not u_char directly */
+	u_char	(*mpo_cred_check_vnode_mmap_perms)(struct ucred *cred,
+		    struct vnode *vp, struct label *label);
 	int	(*mpo_ifnet_check_send_mbuf)(struct ifnet *ifnet,
 		    struct label *ifnetlabel, struct mbuf *mbuf,
 		    struct label *mbuflabel);
@@ -425,6 +428,7 @@
 	MAC_CRED_CHECK_SCHED_PROC,
 	MAC_CRED_CHECK_SIGNAL_PROC,
 	MAC_CRED_CHECK_STAT_VNODE,
+	MAC_CRED_CHECK_VNODE_MMAP_PERMS,
 	MAC_IFNET_CHECK_SEND_MBUF,
 	MAC_SOCKET_CHECK_RECEIVE_MBUF,
 };
To Unsubscribe: send mail to majordomo at trustedbsd.org
with "unsubscribe trustedbsd-cvs" in the body of the message



More information about the trustedbsd-cvs mailing list