The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/security/mac/mac_process.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999-2002 Robert N. M. Watson
    3  * Copyright (c) 2001 Ilmar S. Habibulin
    4  * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
    5  * All rights reserved.
    6  *
    7  * This software was developed by Robert Watson and Ilmar Habibulin for the
    8  * TrustedBSD Project.
    9  *
   10  * This software was developed for the FreeBSD Project in part by Network
   11  * Associates Laboratories, the Security Research Division of Network
   12  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
   13  * as part of the DARPA CHATS research program.
   14  *
   15  * Redistribution and use in source and binary forms, with or without
   16  * modification, are permitted provided that the following conditions
   17  * are met:
   18  * 1. Redistributions of source code must retain the above copyright
   19  *    notice, this list of conditions and the following disclaimer.
   20  * 2. Redistributions in binary form must reproduce the above copyright
   21  *    notice, this list of conditions and the following disclaimer in the
   22  *    documentation and/or other materials provided with the distribution.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/5.4/sys/security/mac/mac_process.c 126097 2004-02-22 00:33:12Z rwatson $");
   39 
   40 #include "opt_mac.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/condvar.h>
   44 #include <sys/imgact.h>
   45 #include <sys/kernel.h>
   46 #include <sys/lock.h>
   47 #include <sys/malloc.h>
   48 #include <sys/mutex.h>
   49 #include <sys/mac.h>
   50 #include <sys/proc.h>
   51 #include <sys/sbuf.h>
   52 #include <sys/systm.h>
   53 #include <sys/vnode.h>
   54 #include <sys/mount.h>
   55 #include <sys/file.h>
   56 #include <sys/namei.h>
   57 #include <sys/sysctl.h>
   58 
   59 #include <vm/vm.h>
   60 #include <vm/pmap.h>
   61 #include <vm/vm_map.h>
   62 #include <vm/vm_object.h>
   63 
   64 #include <sys/mac_policy.h>
   65 
   66 #include <security/mac/mac_internal.h>
   67 
   68 int     mac_enforce_process = 1;
   69 SYSCTL_INT(_security_mac, OID_AUTO, enforce_process, CTLFLAG_RW,
   70     &mac_enforce_process, 0, "Enforce MAC policy on inter-process operations");
   71 TUNABLE_INT("security.mac.enforce_process", &mac_enforce_process);
   72 
   73 int     mac_enforce_vm = 1;
   74 SYSCTL_INT(_security_mac, OID_AUTO, enforce_vm, CTLFLAG_RW,
   75     &mac_enforce_vm, 0, "Enforce MAC policy on vm operations");
   76 TUNABLE_INT("security.mac.enforce_vm", &mac_enforce_vm);
   77 
   78 static int      mac_mmap_revocation = 1;
   79 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
   80     &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
   81     "relabel");
   82 
   83 static int      mac_mmap_revocation_via_cow = 0;
   84 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
   85     &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
   86     "copy-on-write semantics, or by removing all write access");
   87 
   88 #ifdef MAC_DEBUG
   89 static unsigned int nmaccreds, nmacprocs;
   90 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, creds, CTLFLAG_RD,
   91     &nmaccreds, 0, "number of ucreds in use");
   92 SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, procs, CTLFLAG_RD,
   93     &nmacprocs, 0, "number of procs in use");
   94 #endif
   95 
   96 static void     mac_cred_mmapped_drop_perms_recurse(struct thread *td,
   97                     struct ucred *cred, struct vm_map *map);
   98 
   99 struct label *
  100 mac_cred_label_alloc(void)
  101 {
  102         struct label *label;
  103 
  104         label = mac_labelzone_alloc(M_WAITOK);
  105         MAC_PERFORM(init_cred_label, label);
  106         MAC_DEBUG_COUNTER_INC(&nmaccreds);
  107         return (label);
  108 }
  109 
  110 void
  111 mac_init_cred(struct ucred *cred)
  112 {
  113 
  114         cred->cr_label = mac_cred_label_alloc();
  115 }
  116 
  117 static struct label *
  118 mac_proc_label_alloc(void)
  119 {
  120         struct label *label;
  121 
  122         label = mac_labelzone_alloc(M_WAITOK);
  123         MAC_PERFORM(init_proc_label, label);
  124         MAC_DEBUG_COUNTER_INC(&nmacprocs);
  125         return (label);
  126 }
  127 
  128 void
  129 mac_init_proc(struct proc *p)
  130 {
  131 
  132         p->p_label = mac_proc_label_alloc();
  133 }
  134 
  135 void
  136 mac_cred_label_free(struct label *label)
  137 {
  138 
  139         MAC_PERFORM(destroy_cred_label, label);
  140         mac_labelzone_free(label);
  141         MAC_DEBUG_COUNTER_DEC(&nmaccreds);
  142 }
  143 
  144 void
  145 mac_destroy_cred(struct ucred *cred)
  146 {
  147 
  148         mac_cred_label_free(cred->cr_label);
  149         cred->cr_label = NULL;
  150 }
  151 
  152 static void
  153 mac_proc_label_free(struct label *label)
  154 {
  155 
  156         MAC_PERFORM(destroy_proc_label, label);
  157         mac_labelzone_free(label);
  158         MAC_DEBUG_COUNTER_DEC(&nmacprocs);
  159 }
  160 
  161 void
  162 mac_destroy_proc(struct proc *p)
  163 {
  164 
  165         mac_proc_label_free(p->p_label);
  166         p->p_label = NULL;
  167 }
  168 
  169 int
  170 mac_externalize_cred_label(struct label *label, char *elements,
  171     char *outbuf, size_t outbuflen)
  172 {
  173         int error;
  174 
  175         MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen);
  176 
  177         return (error);
  178 }
  179 
  180 int
  181 mac_internalize_cred_label(struct label *label, char *string)
  182 {
  183         int error;
  184 
  185         MAC_INTERNALIZE(cred, label, string);
  186 
  187         return (error);
  188 }
  189 
  190 /*
  191  * Initialize MAC label for the first kernel process, from which other
  192  * kernel processes and threads are spawned.
  193  */
  194 void
  195 mac_create_proc0(struct ucred *cred)
  196 {
  197 
  198         MAC_PERFORM(create_proc0, cred);
  199 }
  200 
  201 /*
  202  * Initialize MAC label for the first userland process, from which other
  203  * userland processes and threads are spawned.
  204  */
  205 void
  206 mac_create_proc1(struct ucred *cred)
  207 {
  208 
  209         MAC_PERFORM(create_proc1, cred);
  210 }
  211 
  212 void
  213 mac_thread_userret(struct thread *td)
  214 {
  215 
  216         MAC_PERFORM(thread_userret, td);
  217 }
  218 
  219 /*
  220  * When a new process is created, its label must be initialized.  Generally,
  221  * this involves inheritence from the parent process, modulo possible
  222  * deltas.  This function allows that processing to take place.
  223  */
  224 void
  225 mac_copy_cred(struct ucred *src, struct ucred *dest)
  226 {
  227 
  228         MAC_PERFORM(copy_cred_label, src->cr_label, dest->cr_label);
  229 }
  230 
  231 int
  232 mac_execve_enter(struct image_params *imgp, struct mac *mac_p)
  233 {
  234         struct label *label;
  235         struct mac mac;
  236         char *buffer;
  237         int error;
  238 
  239         if (mac_p == NULL)
  240                 return (0);
  241 
  242         error = copyin(mac_p, &mac, sizeof(mac));
  243         if (error)
  244                 return (error);
  245 
  246         error = mac_check_structmac_consistent(&mac);
  247         if (error)
  248                 return (error);
  249 
  250         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
  251         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
  252         if (error) {
  253                 free(buffer, M_MACTEMP);
  254                 return (error);
  255         }
  256 
  257         label = mac_cred_label_alloc();
  258         error = mac_internalize_cred_label(label, buffer);
  259         free(buffer, M_MACTEMP);
  260         if (error) {
  261                 mac_cred_label_free(label);
  262                 return (error);
  263         }
  264         imgp->execlabel = label;
  265         return (0);
  266 }
  267 
  268 void
  269 mac_execve_exit(struct image_params *imgp)
  270 {
  271         if (imgp->execlabel != NULL) {
  272                 mac_cred_label_free(imgp->execlabel);
  273                 imgp->execlabel = NULL;
  274         }
  275 }
  276 
  277 /*
  278  * When relabeling a process, call out to the policies for the maximum
  279  * permission allowed for each object type we know about in its
  280  * memory space, and revoke access (in the least surprising ways we
  281  * know) when necessary.  The process lock is not held here.
  282  */
  283 void
  284 mac_cred_mmapped_drop_perms(struct thread *td, struct ucred *cred)
  285 {
  286 
  287         /* XXX freeze all other threads */
  288         mac_cred_mmapped_drop_perms_recurse(td, cred,
  289             &td->td_proc->p_vmspace->vm_map);
  290         /* XXX allow other threads to continue */
  291 }
  292 
  293 static __inline const char *
  294 prot2str(vm_prot_t prot)
  295 {
  296 
  297         switch (prot & VM_PROT_ALL) {
  298         case VM_PROT_READ:
  299                 return ("r--");
  300         case VM_PROT_READ | VM_PROT_WRITE:
  301                 return ("rw-");
  302         case VM_PROT_READ | VM_PROT_EXECUTE:
  303                 return ("r-x");
  304         case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
  305                 return ("rwx");
  306         case VM_PROT_WRITE:
  307                 return ("-w-");
  308         case VM_PROT_EXECUTE:
  309                 return ("--x");
  310         case VM_PROT_WRITE | VM_PROT_EXECUTE:
  311                 return ("-wx");
  312         default:
  313                 return ("---");
  314         }
  315 }
  316 
  317 static void
  318 mac_cred_mmapped_drop_perms_recurse(struct thread *td, struct ucred *cred,
  319     struct vm_map *map)
  320 {
  321         struct vm_map_entry *vme;
  322         int result;
  323         vm_prot_t revokeperms;
  324         vm_object_t object;
  325         vm_ooffset_t offset;
  326         struct vnode *vp;
  327 
  328         if (!mac_mmap_revocation)
  329                 return;
  330 
  331         vm_map_lock_read(map);
  332         for (vme = map->header.next; vme != &map->header; vme = vme->next) {
  333                 if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
  334                         mac_cred_mmapped_drop_perms_recurse(td, cred,
  335                             vme->object.sub_map);
  336                         continue;
  337                 }
  338                 /*
  339                  * Skip over entries that obviously are not shared.
  340                  */
  341                 if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
  342                     !vme->max_protection)
  343                         continue;
  344                 /*
  345                  * Drill down to the deepest backing object.
  346                  */
  347                 offset = vme->offset;
  348                 object = vme->object.vm_object;
  349                 if (object == NULL)
  350                         continue;
  351                 while (object->backing_object != NULL) {
  352                         object = object->backing_object;
  353                         offset += object->backing_object_offset;
  354                 }
  355                 /*
  356                  * At the moment, vm_maps and objects aren't considered
  357                  * by the MAC system, so only things with backing by a
  358                  * normal object (read: vnodes) are checked.
  359                  */
  360                 if (object->type != OBJT_VNODE)
  361                         continue;
  362                 vp = (struct vnode *)object->handle;
  363                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  364                 result = vme->max_protection;
  365                 mac_check_vnode_mmap_downgrade(cred, vp, &result);
  366                 VOP_UNLOCK(vp, 0, td);
  367                 /*
  368                  * Find out what maximum protection we may be allowing
  369                  * now but a policy needs to get removed.
  370                  */
  371                 revokeperms = vme->max_protection & ~result;
  372                 if (!revokeperms)
  373                         continue;
  374                 printf("pid %ld: revoking %s perms from %#lx:%ld "
  375                     "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
  376                     prot2str(revokeperms), (u_long)vme->start,
  377                     (long)(vme->end - vme->start),
  378                     prot2str(vme->max_protection), prot2str(vme->protection));
  379                 vm_map_lock_upgrade(map);
  380                 /*
  381                  * This is the really simple case: if a map has more
  382                  * max_protection than is allowed, but it's not being
  383                  * actually used (that is, the current protection is
  384                  * still allowed), we can just wipe it out and do
  385                  * nothing more.
  386                  */
  387                 if ((vme->protection & revokeperms) == 0) {
  388                         vme->max_protection -= revokeperms;
  389                 } else {
  390                         if (revokeperms & VM_PROT_WRITE) {
  391                                 /*
  392                                  * In the more complicated case, flush out all
  393                                  * pending changes to the object then turn it
  394                                  * copy-on-write.
  395                                  */
  396                                 vm_object_reference(object);
  397                                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  398                                 VM_OBJECT_LOCK(object);
  399                                 vm_object_page_clean(object,
  400                                     OFF_TO_IDX(offset),
  401                                     OFF_TO_IDX(offset + vme->end - vme->start +
  402                                         PAGE_MASK),
  403                                     OBJPC_SYNC);
  404                                 VM_OBJECT_UNLOCK(object);
  405                                 VOP_UNLOCK(vp, 0, td);
  406                                 vm_object_deallocate(object);
  407                                 /*
  408                                  * Why bother if there's no read permissions
  409                                  * anymore?  For the rest, we need to leave
  410                                  * the write permissions on for COW, or
  411                                  * remove them entirely if configured to.
  412                                  */
  413                                 if (!mac_mmap_revocation_via_cow) {
  414                                         vme->max_protection &= ~VM_PROT_WRITE;
  415                                         vme->protection &= ~VM_PROT_WRITE;
  416                                 } if ((revokeperms & VM_PROT_READ) == 0)
  417                                         vme->eflags |= MAP_ENTRY_COW |
  418                                             MAP_ENTRY_NEEDS_COPY;
  419                         }
  420                         if (revokeperms & VM_PROT_EXECUTE) {
  421                                 vme->max_protection &= ~VM_PROT_EXECUTE;
  422                                 vme->protection &= ~VM_PROT_EXECUTE;
  423                         }
  424                         if (revokeperms & VM_PROT_READ) {
  425                                 vme->max_protection = 0;
  426                                 vme->protection = 0;
  427                         }
  428                         pmap_protect(map->pmap, vme->start, vme->end,
  429                             vme->protection & ~revokeperms);
  430                         vm_map_simplify_entry(map, vme);
  431                 }
  432                 vm_map_lock_downgrade(map);
  433         }
  434         vm_map_unlock_read(map);
  435 }
  436 
  437 /*
  438  * When the subject's label changes, it may require revocation of privilege
  439  * to mapped objects.  This can't be done on-the-fly later with a unified
  440  * buffer cache.
  441  */
  442 void
  443 mac_relabel_cred(struct ucred *cred, struct label *newlabel)
  444 {
  445 
  446         MAC_PERFORM(relabel_cred, cred, newlabel);
  447 }
  448 
  449 int
  450 mac_check_cred_relabel(struct ucred *cred, struct label *newlabel)
  451 {
  452         int error;
  453 
  454         MAC_CHECK(check_cred_relabel, cred, newlabel);
  455 
  456         return (error);
  457 }
  458 
  459 int
  460 mac_check_cred_visible(struct ucred *u1, struct ucred *u2)
  461 {
  462         int error;
  463 
  464         if (!mac_enforce_process)
  465                 return (0);
  466 
  467         MAC_CHECK(check_cred_visible, u1, u2);
  468 
  469         return (error);
  470 }
  471 
  472 int
  473 mac_check_proc_debug(struct ucred *cred, struct proc *proc)
  474 {
  475         int error;
  476 
  477         PROC_LOCK_ASSERT(proc, MA_OWNED);
  478 
  479         if (!mac_enforce_process)
  480                 return (0);
  481 
  482         MAC_CHECK(check_proc_debug, cred, proc);
  483 
  484         return (error);
  485 }
  486 
  487 int
  488 mac_check_proc_sched(struct ucred *cred, struct proc *proc)
  489 {
  490         int error;
  491 
  492         PROC_LOCK_ASSERT(proc, MA_OWNED);
  493 
  494         if (!mac_enforce_process)
  495                 return (0);
  496 
  497         MAC_CHECK(check_proc_sched, cred, proc);
  498 
  499         return (error);
  500 }
  501 
  502 int
  503 mac_check_proc_signal(struct ucred *cred, struct proc *proc, int signum)
  504 {
  505         int error;
  506 
  507         PROC_LOCK_ASSERT(proc, MA_OWNED);
  508 
  509         if (!mac_enforce_process)
  510                 return (0);
  511 
  512         MAC_CHECK(check_proc_signal, cred, proc, signum);
  513 
  514         return (error);
  515 }

Cache object: cbb5b422d332768d6e70c795012167f8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.