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