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$"); 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 69 static int mac_mmap_revocation = 1; 70 SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW, 71 &mac_mmap_revocation, 0, "Revoke mmap access to files on subject " 72 "relabel"); 73 74 static int mac_mmap_revocation_via_cow = 0; 75 SYSCTL_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 79 static void mac_cred_mmapped_drop_perms_recurse(struct thread *td, 80 struct ucred *cred, struct vm_map *map); 81 82 struct label * 83 mac_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 92 void 93 mac_init_cred(struct ucred *cred) 94 { 95 96 cred->cr_label = mac_cred_label_alloc(); 97 } 98 99 static struct label * 100 mac_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 109 void 110 mac_init_proc(struct proc *p) 111 { 112 113 p->p_label = mac_proc_label_alloc(); 114 } 115 116 void 117 mac_cred_label_free(struct label *label) 118 { 119 120 MAC_PERFORM(destroy_cred_label, label); 121 mac_labelzone_free(label); 122 } 123 124 void 125 mac_destroy_cred(struct ucred *cred) 126 { 127 128 mac_cred_label_free(cred->cr_label); 129 cred->cr_label = NULL; 130 } 131 132 static void 133 mac_proc_label_free(struct label *label) 134 { 135 136 MAC_PERFORM(destroy_proc_label, label); 137 mac_labelzone_free(label); 138 } 139 140 void 141 mac_destroy_proc(struct proc *p) 142 { 143 144 mac_proc_label_free(p->p_label); 145 p->p_label = NULL; 146 } 147 148 int 149 mac_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 159 int 160 mac_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 */ 173 void 174 mac_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 */ 184 void 185 mac_create_proc1(struct ucred *cred) 186 { 187 188 MAC_PERFORM(create_proc1, cred); 189 } 190 191 void 192 mac_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 */ 203 void 204 mac_copy_cred(struct ucred *src, struct ucred *dest) 205 { 206 207 MAC_PERFORM(copy_cred_label, src->cr_label, dest->cr_label); 208 } 209 210 int 211 mac_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 247 void 248 mac_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 */ 262 void 263 mac_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 272 static __inline const char * 273 prot2str(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 296 static void 297 mac_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 */ 431 void 432 mac_relabel_cred(struct ucred *cred, struct label *newlabel) 433 { 434 435 MAC_PERFORM(relabel_cred, cred, newlabel); 436 } 437 438 int 439 mac_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 448 int 449 mac_check_cred_visible(struct ucred *cr1, struct ucred *cr2) 450 { 451 int error; 452 453 MAC_CHECK(check_cred_visible, cr1, cr2); 454 455 return (error); 456 } 457 458 int 459 mac_check_proc_debug(struct ucred *cred, struct proc *p) 460 { 461 int error; 462 463 PROC_LOCK_ASSERT(p, MA_OWNED); 464 465 MAC_CHECK(check_proc_debug, cred, p); 466 467 return (error); 468 } 469 470 int 471 mac_check_proc_sched(struct ucred *cred, struct proc *p) 472 { 473 int error; 474 475 PROC_LOCK_ASSERT(p, MA_OWNED); 476 477 MAC_CHECK(check_proc_sched, cred, p); 478 479 return (error); 480 } 481 482 int 483 mac_check_proc_signal(struct ucred *cred, struct proc *p, int signum) 484 { 485 int error; 486 487 PROC_LOCK_ASSERT(p, MA_OWNED); 488 489 MAC_CHECK(check_proc_signal, cred, p, signum); 490 491 return (error); 492 } 493 494 int 495 mac_check_proc_setuid(struct proc *p, struct ucred *cred, uid_t uid) 496 { 497 int error; 498 499 PROC_LOCK_ASSERT(p, MA_OWNED); 500 501 MAC_CHECK(check_proc_setuid, cred, uid); 502 return (error); 503 } 504 505 int 506 mac_check_proc_seteuid(struct proc *p, struct ucred *cred, uid_t euid) 507 { 508 int error; 509 510 PROC_LOCK_ASSERT(p, MA_OWNED); 511 512 MAC_CHECK(check_proc_seteuid, cred, euid); 513 return (error); 514 } 515 516 int 517 mac_check_proc_setgid(struct proc *p, struct ucred *cred, gid_t gid) 518 { 519 int error; 520 521 PROC_LOCK_ASSERT(p, MA_OWNED); 522 523 MAC_CHECK(check_proc_setgid, cred, gid); 524 525 return (error); 526 } 527 528 int 529 mac_check_proc_setegid(struct proc *p, struct ucred *cred, gid_t egid) 530 { 531 int error; 532 533 PROC_LOCK_ASSERT(p, MA_OWNED); 534 535 MAC_CHECK(check_proc_setegid, cred, egid); 536 537 return (error); 538 } 539 540 int 541 mac_check_proc_setgroups(struct proc *p, struct ucred *cred, int ngroups, 542 gid_t *gidset) 543 { 544 int error; 545 546 PROC_LOCK_ASSERT(p, MA_OWNED); 547 548 MAC_CHECK(check_proc_setgroups, cred, ngroups, gidset); 549 return (error); 550 } 551 552 int 553 mac_check_proc_setreuid(struct proc *p, struct ucred *cred, uid_t ruid, 554 uid_t euid) 555 { 556 int error; 557 558 PROC_LOCK_ASSERT(p, MA_OWNED); 559 560 MAC_CHECK(check_proc_setreuid, cred, ruid, euid); 561 562 return (error); 563 } 564 565 int 566 mac_check_proc_setregid(struct proc *proc, struct ucred *cred, gid_t rgid, 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 578 int 579 mac_check_proc_setresuid(struct proc *p, struct ucred *cred, uid_t ruid, 580 uid_t euid, uid_t suid) 581 { 582 int error; 583 584 PROC_LOCK_ASSERT(p, MA_OWNED); 585 586 MAC_CHECK(check_proc_setresuid, cred, ruid, euid, suid); 587 return (error); 588 } 589 590 int 591 mac_check_proc_setresgid(struct proc *p, struct ucred *cred, gid_t rgid, 592 gid_t egid, gid_t sgid) 593 { 594 int error; 595 596 PROC_LOCK_ASSERT(p, MA_OWNED); 597 598 MAC_CHECK(check_proc_setresgid, cred, rgid, egid, sgid); 599 600 return (error); 601 } 602 603 int 604 mac_check_proc_wait(struct ucred *cred, struct proc *p) 605 { 606 int error; 607 608 PROC_LOCK_ASSERT(p, MA_OWNED); 609 610 MAC_CHECK(check_proc_wait, cred, p); 611 612 return (error); 613 } 614