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