From owner-p4-projects Tue Jul 23 8:35:38 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2B46C37B401; Tue, 23 Jul 2002 08:35:09 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A62C937B400 for ; Tue, 23 Jul 2002 08:35:08 -0700 (PDT) Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 17AF343E67 for ; Tue, 23 Jul 2002 08:35:07 -0700 (PDT) (envelope-from green@freebsd.org) Received: from freefall.freebsd.org (perforce@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.4/8.12.4) with ESMTP id g6NFZ6JU093100 for ; Tue, 23 Jul 2002 08:35:06 -0700 (PDT) (envelope-from green@freebsd.org) Received: (from perforce@localhost) by freefall.freebsd.org (8.12.4/8.12.4/Submit) id g6NFZ4hO093095 for perforce@freebsd.org; Tue, 23 Jul 2002 08:35:04 -0700 (PDT) Date: Tue, 23 Jul 2002 08:35:04 -0700 (PDT) Message-Id: <200207231535.g6NFZ4hO093095@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: perforce set sender to green@freebsd.org using -f From: Brian Feldman Subject: PERFORCE change 14779 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://people.freebsd.org/~peter/p4db/chv.cgi?CH=14779 Change 14779 by green@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 #include +#include +#include +#include +#include + #include #include @@ -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 #include +#include + #include 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 #include +#include + #include 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@FreeBSD.org with "unsubscribe p4-projects" in the body of the message