1/*- 2 * Copyright (c) 1999-2009 Apple Inc. 3 * Copyright (c) 2005 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * @APPLE_BSD_LICENSE_HEADER_START@ 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * @APPLE_BSD_LICENSE_HEADER_END@ 33 */ 34/* 35 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 36 * support for mandatory and extensible security protections. This notice 37 * is included in support of clause 2.2 (b) of the Apple Public License, 38 * Version 2.0. 39 */ 40 41#include <sys/systm.h> 42#include <sys/sysent.h> 43#include <sys/types.h> 44#include <sys/proc_internal.h> 45#include <sys/vnode_internal.h> 46#include <sys/fcntl.h> 47#include <sys/filedesc.h> 48#include <sys/sem.h> 49 50#include <bsm/audit.h> 51#include <bsm/audit_kevents.h> 52#include <security/audit/audit.h> 53#include <security/audit/audit_bsd.h> 54#include <security/audit/audit_private.h> 55 56#if CONFIG_AUDIT 57/* 58 * Hash table functions for the audit event number to event class mask 59 * mapping. 60 */ 61#define EVCLASSMAP_HASH_TABLE_SIZE 251 62struct evclass_elem { 63 au_event_t event; 64 au_class_t class; 65 LIST_ENTRY(evclass_elem) entry; 66}; 67struct evclass_list { 68 LIST_HEAD(, evclass_elem) head; 69}; 70 71static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class"); 72static struct rwlock evclass_lock; 73static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; 74 75#define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock") 76#define EVCLASS_RLOCK() rw_rlock(&evclass_lock) 77#define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock) 78#define EVCLASS_WLOCK() rw_wlock(&evclass_lock) 79#define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock) 80 81/* 82 * Look up the class for an audit event in the class mapping table. 83 */ 84au_class_t 85au_event_class(au_event_t event) 86{ 87 struct evclass_list *evcl; 88 struct evclass_elem *evc; 89 au_class_t class; 90 91 EVCLASS_RLOCK(); 92 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 93 class = 0; 94 LIST_FOREACH(evc, &evcl->head, entry) { 95 if (evc->event == event) { 96 class = evc->class; 97 goto out; 98 } 99 } 100out: 101 EVCLASS_RUNLOCK(); 102 return (class); 103} 104 105/* 106 * Insert a event to class mapping. If the event already exists in the 107 * mapping, then replace the mapping with the new one. 108 * 109 * XXX There is currently no constraints placed on the number of mappings. 110 * May want to either limit to a number, or in terms of memory usage. 111 */ 112void 113au_evclassmap_insert(au_event_t event, au_class_t class) 114{ 115 struct evclass_list *evcl; 116 struct evclass_elem *evc, *evc_new; 117 118 /* 119 * If this event requires auditing a system call then add it to our 120 * audit kernel event mask. We use audit_kevent_mask to check to see 121 * if the audit syscalls flag needs to be set when preselection masks 122 * are set. 123 */ 124 if (AUE_IS_A_KEVENT(event)) 125 audit_kevent_mask |= class; 126 127 /* 128 * Pessimistically, always allocate storage before acquiring mutex. 129 * Free if there is already a mapping for this event. 130 */ 131 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK); 132 133 EVCLASS_WLOCK(); 134 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 135 LIST_FOREACH(evc, &evcl->head, entry) { 136 if (evc->event == event) { 137 evc->class = class; 138 EVCLASS_WUNLOCK(); 139 free(evc_new, M_AUDITEVCLASS); 140 return; 141 } 142 } 143 evc = evc_new; 144 evc->event = event; 145 evc->class = class; 146 LIST_INSERT_HEAD(&evcl->head, evc, entry); 147 EVCLASS_WUNLOCK(); 148} 149 150void 151au_evclassmap_init(void) 152{ 153 int i; 154 155 EVCLASS_LOCK_INIT(); 156 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) 157 LIST_INIT(&evclass_hash[i].head); 158 159 /* 160 * Set up the initial event to class mapping for system calls. 161 */ 162 for (i = 0; i < NUM_SYSENT; i++) { 163 if (sys_au_event[i] != AUE_NULL) 164 au_evclassmap_insert(sys_au_event[i], 0); 165 166 } 167 168 /* 169 * Add the Mach system call events. These are not in sys_au_event[]. 170 */ 171 au_evclassmap_insert(AUE_TASKFORPID, 0); 172 au_evclassmap_insert(AUE_PIDFORTASK, 0); 173 au_evclassmap_insert(AUE_SWAPON, 0); 174 au_evclassmap_insert(AUE_SWAPOFF, 0); 175 au_evclassmap_insert(AUE_MAPFD, 0); 176 au_evclassmap_insert(AUE_INITPROCESS, 0); 177} 178 179/* 180 * Check whether an event is aditable by comparing the mask of classes this 181 * event is part of against the given mask. 182 */ 183int 184au_preselect(__unused au_event_t event, au_class_t class, au_mask_t *mask_p, 185 int sorf) 186{ 187 au_class_t effmask = 0; 188 189 if (mask_p == NULL) 190 return (-1); 191 192 /* 193 * Perform the actual check of the masks against the event. 194 */ 195 if (sorf & AU_PRS_SUCCESS) 196 effmask |= (mask_p->am_success & class); 197 198 if (sorf & AU_PRS_FAILURE) 199 effmask |= (mask_p->am_failure & class); 200 201 if (effmask) 202 return (1); 203 else 204 return (0); 205} 206 207/* 208 * Convert sysctl names and present arguments to events. 209 */ 210au_event_t 211audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg) 212{ 213 214 /* can't parse it - so return the worst case */ 215 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) 216 return (AUE_SYSCTL); 217 218 switch (name[0]) { 219 /* non-admin "lookups" treat them special */ 220 case KERN_OSTYPE: 221 case KERN_OSRELEASE: 222 case KERN_OSREV: 223 case KERN_VERSION: 224 case KERN_ARGMAX: 225 case KERN_CLOCKRATE: 226 case KERN_BOOTTIME: 227 case KERN_POSIX1: 228 case KERN_NGROUPS: 229 case KERN_JOB_CONTROL: 230 case KERN_SAVED_IDS: 231 case KERN_OSRELDATE: 232 case KERN_NETBOOT: 233 case KERN_SYMFILE: 234 case KERN_SHREG_PRIVATIZABLE: 235 case KERN_OSVERSION: 236 return (AUE_SYSCTL_NONADMIN); 237 238 /* only treat the changeable controls as admin */ 239 case KERN_MAXVNODES: 240 case KERN_MAXPROC: 241 case KERN_MAXFILES: 242 case KERN_MAXPROCPERUID: 243 case KERN_MAXFILESPERPROC: 244 case KERN_HOSTID: 245 case KERN_AIOMAX: 246 case KERN_AIOPROCMAX: 247 case KERN_AIOTHREADS: 248 case KERN_COREDUMP: 249 case KERN_SUGID_COREDUMP: 250 case KERN_NX_PROTECTION: 251 return ((valid_arg & ARG_VALUE32) ? 252 AUE_SYSCTL : AUE_SYSCTL_NONADMIN); 253 254 default: 255 return (AUE_SYSCTL); 256 } 257 /* NOTREACHED */ 258} 259 260/* 261 * Convert an open flags specifier into a specific type of open event for 262 * auditing purposes. 263 */ 264au_event_t 265audit_flags_and_error_to_openevent(int oflags, int error) 266{ 267 au_event_t aevent; 268 269 /* 270 * Need to check only those flags we care about. 271 */ 272 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 273 274 /* 275 * These checks determine what flags are on with the condition that 276 * ONLY that combination is on, and no other flags are on. 277 */ 278 switch (oflags) { 279 case O_RDONLY: 280 aevent = AUE_OPEN_R; 281 break; 282 283 case (O_RDONLY | O_CREAT): 284 aevent = AUE_OPEN_RC; 285 break; 286 287 case (O_RDONLY | O_CREAT | O_TRUNC): 288 aevent = AUE_OPEN_RTC; 289 break; 290 291 case (O_RDONLY | O_TRUNC): 292 aevent = AUE_OPEN_RT; 293 break; 294 295 case O_RDWR: 296 aevent = AUE_OPEN_RW; 297 break; 298 299 case (O_RDWR | O_CREAT): 300 aevent = AUE_OPEN_RWC; 301 break; 302 303 case (O_RDWR | O_CREAT | O_TRUNC): 304 aevent = AUE_OPEN_RWTC; 305 break; 306 307 case (O_RDWR | O_TRUNC): 308 aevent = AUE_OPEN_RWT; 309 break; 310 311 case O_WRONLY: 312 aevent = AUE_OPEN_W; 313 break; 314 315 case (O_WRONLY | O_CREAT): 316 aevent = AUE_OPEN_WC; 317 break; 318 319 case (O_WRONLY | O_CREAT | O_TRUNC): 320 aevent = AUE_OPEN_WTC; 321 break; 322 323 case (O_WRONLY | O_TRUNC): 324 aevent = AUE_OPEN_WT; 325 break; 326 327 default: 328 aevent = AUE_OPEN; 329 break; 330 } 331 332 /* 333 * Convert chatty errors to better matching events. Failures to 334 * find a file are really just attribute events -- so recast them as 335 * such. 336 * 337 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it 338 * is just a placeholder. However, in Darwin we return that in 339 * preference to other events. 340 * 341 * XXXRW: This behavior differs from FreeBSD, so possibly revise this 342 * code or this comment. 343 */ 344 switch (aevent) { 345 case AUE_OPEN_R: 346 case AUE_OPEN_RT: 347 case AUE_OPEN_RW: 348 case AUE_OPEN_RWT: 349 case AUE_OPEN_W: 350 case AUE_OPEN_WT: 351 if (error == ENOENT) 352 aevent = AUE_OPEN; 353 } 354 return (aevent); 355} 356 357/* 358 * Convert an open flags specifier into a specific type of open_extended event 359 * for auditing purposes. 360 */ 361au_event_t 362audit_flags_and_error_to_openextendedevent(int oflags, int error) 363{ 364 au_event_t aevent; 365 366 /* 367 * Need to check only those flags we care about. 368 */ 369 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 370 371 /* 372 * These checks determine what flags are on with the condition that 373 * ONLY that combination is on, and no other flags are on. 374 */ 375 switch (oflags) { 376 case O_RDONLY: 377 aevent = AUE_OPEN_EXTENDED_R; 378 break; 379 380 case (O_RDONLY | O_CREAT): 381 aevent = AUE_OPEN_EXTENDED_RC; 382 break; 383 384 case (O_RDONLY | O_CREAT | O_TRUNC): 385 aevent = AUE_OPEN_EXTENDED_RTC; 386 break; 387 388 case (O_RDONLY | O_TRUNC): 389 aevent = AUE_OPEN_EXTENDED_RT; 390 break; 391 392 case O_RDWR: 393 aevent = AUE_OPEN_EXTENDED_RW; 394 break; 395 396 case (O_RDWR | O_CREAT): 397 aevent = AUE_OPEN_EXTENDED_RWC; 398 break; 399 400 case (O_RDWR | O_CREAT | O_TRUNC): 401 aevent = AUE_OPEN_EXTENDED_RWTC; 402 break; 403 404 case (O_RDWR | O_TRUNC): 405 aevent = AUE_OPEN_EXTENDED_RWT; 406 break; 407 408 case O_WRONLY: 409 aevent = AUE_OPEN_EXTENDED_W; 410 break; 411 412 case (O_WRONLY | O_CREAT): 413 aevent = AUE_OPEN_EXTENDED_WC; 414 break; 415 416 case (O_WRONLY | O_CREAT | O_TRUNC): 417 aevent = AUE_OPEN_EXTENDED_WTC; 418 break; 419 420 case (O_WRONLY | O_TRUNC): 421 aevent = AUE_OPEN_EXTENDED_WT; 422 break; 423 424 default: 425 aevent = AUE_OPEN_EXTENDED; 426 break; 427 } 428 429 /* 430 * Convert chatty errors to better matching events. Failures to 431 * find a file are really just attribute events -- so recast them as 432 * such. 433 * 434 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it 435 * is just a placeholder. However, in Darwin we return that in 436 * preference to other events. 437 * 438 * XXXRW: This behavior differs from FreeBSD, so possibly revise this 439 * code or this comment. 440 */ 441 switch (aevent) { 442 case AUE_OPEN_EXTENDED_R: 443 case AUE_OPEN_EXTENDED_RT: 444 case AUE_OPEN_EXTENDED_RW: 445 case AUE_OPEN_EXTENDED_RWT: 446 case AUE_OPEN_EXTENDED_W: 447 case AUE_OPEN_EXTENDED_WT: 448 if (error == ENOENT) 449 aevent = AUE_OPEN_EXTENDED; 450 } 451 return (aevent); 452} 453 454/* 455 * Convert a MSGCTL command to a specific event. 456 */ 457au_event_t 458audit_msgctl_to_event(int cmd) 459{ 460 461 switch (cmd) { 462 case IPC_RMID: 463 return (AUE_MSGCTL_RMID); 464 465 case IPC_SET: 466 return (AUE_MSGCTL_SET); 467 468 case IPC_STAT: 469 return (AUE_MSGCTL_STAT); 470 471 default: 472 /* We will audit a bad command. */ 473 return (AUE_MSGCTL); 474 } 475} 476 477/* 478 * Convert a SEMCTL command to a specific event. 479 */ 480au_event_t 481audit_semctl_to_event(int cmd) 482{ 483 484 switch (cmd) { 485 case GETALL: 486 return (AUE_SEMCTL_GETALL); 487 488 case GETNCNT: 489 return (AUE_SEMCTL_GETNCNT); 490 491 case GETPID: 492 return (AUE_SEMCTL_GETPID); 493 494 case GETVAL: 495 return (AUE_SEMCTL_GETVAL); 496 497 case GETZCNT: 498 return (AUE_SEMCTL_GETZCNT); 499 500 case IPC_RMID: 501 return (AUE_SEMCTL_RMID); 502 503 case IPC_SET: 504 return (AUE_SEMCTL_SET); 505 506 case SETALL: 507 return (AUE_SEMCTL_SETALL); 508 509 case SETVAL: 510 return (AUE_SEMCTL_SETVAL); 511 512 case IPC_STAT: 513 return (AUE_SEMCTL_STAT); 514 515 default: 516 /* We will audit a bad command. */ 517 return (AUE_SEMCTL); 518 } 519} 520 521/* 522 * Convert a command for the auditon() system call to a audit event. 523 */ 524au_event_t 525auditon_command_event(int cmd) 526{ 527 528 switch(cmd) { 529 case A_GETPOLICY: 530 return (AUE_AUDITON_GPOLICY); 531 532 case A_SETPOLICY: 533 return (AUE_AUDITON_SPOLICY); 534 535 case A_GETKMASK: 536 return (AUE_AUDITON_GETKMASK); 537 538 case A_SETKMASK: 539 return (AUE_AUDITON_SETKMASK); 540 541 case A_GETQCTRL: 542 return (AUE_AUDITON_GQCTRL); 543 544 case A_SETQCTRL: 545 return (AUE_AUDITON_SQCTRL); 546 547 case A_GETCWD: 548 return (AUE_AUDITON_GETCWD); 549 550 case A_GETCAR: 551 return (AUE_AUDITON_GETCAR); 552 553 case A_GETSTAT: 554 return (AUE_AUDITON_GETSTAT); 555 556 case A_SETSTAT: 557 return (AUE_AUDITON_SETSTAT); 558 559 case A_SETUMASK: 560 return (AUE_AUDITON_SETUMASK); 561 562 case A_SETSMASK: 563 return (AUE_AUDITON_SETSMASK); 564 565 case A_GETCOND: 566 return (AUE_AUDITON_GETCOND); 567 568 case A_SETCOND: 569 return (AUE_AUDITON_SETCOND); 570 571 case A_GETCLASS: 572 return (AUE_AUDITON_GETCLASS); 573 574 case A_SETCLASS: 575 return (AUE_AUDITON_SETCLASS); 576 577 case A_GETPINFO: 578 case A_SETPMASK: 579 case A_SETFSIZE: 580 case A_GETFSIZE: 581 case A_GETPINFO_ADDR: 582 case A_GETKAUDIT: 583 case A_SETKAUDIT: 584 case A_GETSINFO_ADDR: 585 default: 586 return (AUE_AUDITON); /* No special record */ 587 } 588} 589 590/* 591 * For darwin we rewrite events generated by fcntl(F_OPENFROM,...) and 592 * fcntl(F_UNLINKFROM,...) system calls to AUE_OPENAT_* and AUE_UNLINKAT audit 593 * events. 594 */ 595au_event_t 596audit_fcntl_command_event(int cmd, int oflags, int error) 597{ 598 au_event_t aevent; 599 600 switch(cmd) { 601 case F_OPENFROM: 602 /* 603 * Need to check only those flags we care about. 604 */ 605 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | 606 O_WRONLY); 607 608 /* 609 * These checks determine what flags are on with the condition 610 * that ONLY that combination is on, and no other flags are on. 611 */ 612 switch (oflags) { 613 case O_RDONLY: 614 aevent = AUE_OPENAT_R; 615 break; 616 617 case (O_RDONLY | O_CREAT): 618 aevent = AUE_OPENAT_RC; 619 break; 620 621 case (O_RDONLY | O_CREAT | O_TRUNC): 622 aevent = AUE_OPENAT_RTC; 623 break; 624 625 case (O_RDONLY | O_TRUNC): 626 aevent = AUE_OPENAT_RT; 627 break; 628 629 case O_RDWR: 630 aevent = AUE_OPENAT_RW; 631 break; 632 633 case (O_RDWR | O_CREAT): 634 aevent = AUE_OPENAT_RWC; 635 break; 636 637 case (O_RDWR | O_CREAT | O_TRUNC): 638 aevent = AUE_OPENAT_RWTC; 639 break; 640 641 case (O_RDWR | O_TRUNC): 642 aevent = AUE_OPENAT_RWT; 643 break; 644 645 case O_WRONLY: 646 aevent = AUE_OPENAT_W; 647 break; 648 649 case (O_WRONLY | O_CREAT): 650 aevent = AUE_OPENAT_WC; 651 break; 652 653 case (O_WRONLY | O_CREAT | O_TRUNC): 654 aevent = AUE_OPENAT_WTC; 655 break; 656 657 case (O_WRONLY | O_TRUNC): 658 aevent = AUE_OPENAT_WT; 659 break; 660 661 default: 662 aevent = AUE_OPENAT; 663 break; 664 } 665 666 /* 667 * Convert chatty errors to better matching events. Failures to 668 * find a file are really just attribute events -- so recast 669 * them as such. 670 */ 671 switch (aevent) { 672 case AUE_OPENAT_R: 673 case AUE_OPENAT_RT: 674 case AUE_OPENAT_RW: 675 case AUE_OPENAT_RWT: 676 case AUE_OPENAT_W: 677 case AUE_OPENAT_WT: 678 if (error == ENOENT) 679 aevent = AUE_OPENAT; 680 } 681 682 return (aevent); 683 684 case F_UNLINKFROM: 685 return (AUE_UNLINKAT); 686 687 default: 688 return (AUE_FCNTL); /* Don't change from AUE_FCNTL. */ 689 } 690} 691 692/* 693 * Create a canonical path from given path by prefixing either the root 694 * directory, or the current working directory. 695 */ 696int 697audit_canon_path(struct vnode *cwd_vp, char *path, char *cpath) 698{ 699 int len; 700 int ret; 701 char *bufp = path; 702 703 /* 704 * Convert multiple leading '/' into a single '/' if the cwd_vp is 705 * NULL (i.e. an absolute path), and strip them entirely if the 706 * cwd_vp represents a chroot directory (i.e. the caller checked for 707 * an initial '/' character itself, saw one, and passed fdp->fd_rdir). 708 * Somewhat complicated, but it places the onus for locking structs 709 * involved on the caller, and makes proxy operations explicit rather 710 * than implicit. 711 */ 712 if (*(path) == '/') { 713 while (*(bufp) == '/') 714 bufp++; /* skip leading '/'s */ 715 if (cwd_vp == NULL) 716 bufp--; /* restore one '/' */ 717 } 718 if (cwd_vp != NULL) { 719 len = MAXPATHLEN; 720 ret = vn_getpath(cwd_vp, cpath, &len); 721 if (ret != 0) { 722 cpath[0] = '\0'; 723 return (ret); 724 } 725 if (len < MAXPATHLEN) 726 cpath[len-1] = '/'; 727 strlcpy(cpath + len, bufp, MAXPATHLEN - len); 728 } else { 729 strlcpy(cpath, bufp, MAXPATHLEN); 730 } 731 return (0); 732} 733#endif /* CONFIG_AUDIT */ 734