1 /* 2 * Copyright (c) 1999-2009 Apple Inc. 3 * Copyright (c) 2005 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/fcntl.h> 36 #include <sys/filedesc.h> 37 #include <sys/libkern.h> 38 #include <sys/malloc.h> 39 #include <sys/mount.h> 40 #include <sys/proc.h> 41 #include <sys/rwlock.h> 42 #include <sys/sem.h> 43 #include <sys/sbuf.h> 44 #include <sys/syscall.h> 45 #include <sys/sysctl.h> 46 #include <sys/sysent.h> 47 #include <sys/vnode.h> 48 49 #include <bsm/audit.h> 50 #include <bsm/audit_kevents.h> 51 #include <security/audit/audit.h> 52 #include <security/audit/audit_private.h> 53 54 /* 55 * Hash table functions for the audit event number to event class mask 56 * mapping. 57 */ 58 #define EVCLASSMAP_HASH_TABLE_SIZE 251 59 struct evclass_elem { 60 au_event_t event; 61 au_class_t class; 62 LIST_ENTRY(evclass_elem) entry; 63 }; 64 struct evclass_list { 65 LIST_HEAD(, evclass_elem) head; 66 }; 67 68 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class"); 69 static struct rwlock evclass_lock; 70 static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; 71 72 #define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock") 73 #define EVCLASS_RLOCK() rw_rlock(&evclass_lock) 74 #define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock) 75 #define EVCLASS_WLOCK() rw_wlock(&evclass_lock) 76 #define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock) 77 78 /* 79 * Look up the class for an audit event in the class mapping table. 80 */ 81 au_class_t 82 au_event_class(au_event_t event) 83 { 84 struct evclass_list *evcl; 85 struct evclass_elem *evc; 86 au_class_t class; 87 88 EVCLASS_RLOCK(); 89 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 90 class = 0; 91 LIST_FOREACH(evc, &evcl->head, entry) { 92 if (evc->event == event) { 93 class = evc->class; 94 goto out; 95 } 96 } 97 out: 98 EVCLASS_RUNLOCK(); 99 return (class); 100 } 101 102 /* 103 * Insert a event to class mapping. If the event already exists in the 104 * mapping, then replace the mapping with the new one. 105 * 106 * XXX There is currently no constraints placed on the number of mappings. 107 * May want to either limit to a number, or in terms of memory usage. 108 */ 109 void 110 au_evclassmap_insert(au_event_t event, au_class_t class) 111 { 112 struct evclass_list *evcl; 113 struct evclass_elem *evc, *evc_new; 114 115 /* 116 * Pessimistically, always allocate storage before acquiring mutex. 117 * Free if there is already a mapping for this event. 118 */ 119 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK); 120 121 EVCLASS_WLOCK(); 122 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 123 LIST_FOREACH(evc, &evcl->head, entry) { 124 if (evc->event == event) { 125 evc->class = class; 126 EVCLASS_WUNLOCK(); 127 free(evc_new, M_AUDITEVCLASS); 128 return; 129 } 130 } 131 evc = evc_new; 132 evc->event = event; 133 evc->class = class; 134 LIST_INSERT_HEAD(&evcl->head, evc, entry); 135 EVCLASS_WUNLOCK(); 136 } 137 138 void 139 au_evclassmap_init(void) 140 { 141 int i; 142 143 EVCLASS_LOCK_INIT(); 144 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) 145 LIST_INIT(&evclass_hash[i].head); 146 147 /* 148 * Set up the initial event to class mapping for system calls. 149 * 150 * XXXRW: Really, this should walk all possible audit events, not all 151 * native ABI system calls, as there may be audit events reachable 152 * only through non-native system calls. It also seems a shame to 153 * frob the mutex this early. 154 */ 155 for (i = 0; i < SYS_MAXSYSCALL; i++) { 156 if (sysent[i].sy_auevent != AUE_NULL) 157 au_evclassmap_insert(sysent[i].sy_auevent, 0); 158 } 159 } 160 161 /* 162 * Check whether an event is aditable by comparing the mask of classes this 163 * event is part of against the given mask. 164 */ 165 int 166 au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf) 167 { 168 au_class_t effmask = 0; 169 170 if (mask_p == NULL) 171 return (-1); 172 173 /* 174 * Perform the actual check of the masks against the event. 175 */ 176 if (sorf & AU_PRS_SUCCESS) 177 effmask |= (mask_p->am_success & class); 178 179 if (sorf & AU_PRS_FAILURE) 180 effmask |= (mask_p->am_failure & class); 181 182 if (effmask) 183 return (1); 184 else 185 return (0); 186 } 187 188 /* 189 * Convert sysctl names and present arguments to events. 190 */ 191 au_event_t 192 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg) 193 { 194 195 /* can't parse it - so return the worst case */ 196 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) 197 return (AUE_SYSCTL); 198 199 switch (name[0]) { 200 /* non-admin "lookups" treat them special */ 201 case KERN_OSTYPE: 202 case KERN_OSRELEASE: 203 case KERN_OSREV: 204 case KERN_VERSION: 205 case KERN_ARGMAX: 206 case KERN_CLOCKRATE: 207 case KERN_BOOTTIME: 208 case KERN_POSIX1: 209 case KERN_NGROUPS: 210 case KERN_JOB_CONTROL: 211 case KERN_SAVED_IDS: 212 case KERN_OSRELDATE: 213 case KERN_DUMMY: 214 return (AUE_SYSCTL_NONADMIN); 215 216 /* only treat the changeable controls as admin */ 217 case KERN_MAXVNODES: 218 case KERN_MAXPROC: 219 case KERN_MAXFILES: 220 case KERN_MAXPROCPERUID: 221 case KERN_MAXFILESPERPROC: 222 case KERN_HOSTID: 223 case KERN_SECURELVL: 224 case KERN_HOSTNAME: 225 case KERN_VNODE: 226 case KERN_PROC: 227 case KERN_FILE: 228 case KERN_PROF: 229 case KERN_NISDOMAINNAME: 230 case KERN_UPDATEINTERVAL: 231 case KERN_NTP_PLL: 232 case KERN_BOOTFILE: 233 case KERN_DUMPDEV: 234 case KERN_IPC: 235 case KERN_PS_STRINGS: 236 case KERN_USRSTACK: 237 case KERN_LOGSIGEXIT: 238 case KERN_IOV_MAX: 239 case KERN_MAXID: 240 return ((valid_arg & ARG_VALUE) ? 241 AUE_SYSCTL : AUE_SYSCTL_NONADMIN); 242 243 default: 244 return (AUE_SYSCTL); 245 } 246 /* NOTREACHED */ 247 } 248 249 /* 250 * Convert an open flags specifier into a specific type of open event for 251 * auditing purposes. 252 */ 253 au_event_t 254 audit_flags_and_error_to_openevent(int oflags, int error) 255 { 256 au_event_t aevent; 257 258 /* 259 * Need to check only those flags we care about. 260 */ 261 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 262 263 /* 264 * These checks determine what flags are on with the condition that 265 * ONLY that combination is on, and no other flags are on. 266 */ 267 switch (oflags) { 268 case O_RDONLY: 269 aevent = AUE_OPEN_R; 270 break; 271 272 case (O_RDONLY | O_CREAT): 273 aevent = AUE_OPEN_RC; 274 break; 275 276 case (O_RDONLY | O_CREAT | O_TRUNC): 277 aevent = AUE_OPEN_RTC; 278 break; 279 280 case (O_RDONLY | O_TRUNC): 281 aevent = AUE_OPEN_RT; 282 break; 283 284 case O_RDWR: 285 aevent = AUE_OPEN_RW; 286 break; 287 288 case (O_RDWR | O_CREAT): 289 aevent = AUE_OPEN_RWC; 290 break; 291 292 case (O_RDWR | O_CREAT | O_TRUNC): 293 aevent = AUE_OPEN_RWTC; 294 break; 295 296 case (O_RDWR | O_TRUNC): 297 aevent = AUE_OPEN_RWT; 298 break; 299 300 case O_WRONLY: 301 aevent = AUE_OPEN_W; 302 break; 303 304 case (O_WRONLY | O_CREAT): 305 aevent = AUE_OPEN_WC; 306 break; 307 308 case (O_WRONLY | O_CREAT | O_TRUNC): 309 aevent = AUE_OPEN_WTC; 310 break; 311 312 case (O_WRONLY | O_TRUNC): 313 aevent = AUE_OPEN_WT; 314 break; 315 316 default: 317 aevent = AUE_OPEN; 318 break; 319 } 320 321 #if 0 322 /* 323 * Convert chatty errors to better matching events. Failures to 324 * find a file are really just attribute events -- so recast them as 325 * such. 326 * 327 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it 328 * is just a placeholder. However, in Darwin we return that in 329 * preference to other events. For now, comment this out as we don't 330 * have a BSM conversion routine for AUE_OPEN. 331 */ 332 switch (aevent) { 333 case AUE_OPEN_R: 334 case AUE_OPEN_RT: 335 case AUE_OPEN_RW: 336 case AUE_OPEN_RWT: 337 case AUE_OPEN_W: 338 case AUE_OPEN_WT: 339 if (error == ENOENT) 340 aevent = AUE_OPEN; 341 } 342 #endif 343 return (aevent); 344 } 345 346 /* 347 * Convert a MSGCTL command to a specific event. 348 */ 349 au_event_t 350 audit_msgctl_to_event(int cmd) 351 { 352 353 switch (cmd) { 354 case IPC_RMID: 355 return (AUE_MSGCTL_RMID); 356 357 case IPC_SET: 358 return (AUE_MSGCTL_SET); 359 360 case IPC_STAT: 361 return (AUE_MSGCTL_STAT); 362 363 default: 364 /* We will audit a bad command. */ 365 return (AUE_MSGCTL); 366 } 367 } 368 369 /* 370 * Convert a SEMCTL command to a specific event. 371 */ 372 au_event_t 373 audit_semctl_to_event(int cmd) 374 { 375 376 switch (cmd) { 377 case GETALL: 378 return (AUE_SEMCTL_GETALL); 379 380 case GETNCNT: 381 return (AUE_SEMCTL_GETNCNT); 382 383 case GETPID: 384 return (AUE_SEMCTL_GETPID); 385 386 case GETVAL: 387 return (AUE_SEMCTL_GETVAL); 388 389 case GETZCNT: 390 return (AUE_SEMCTL_GETZCNT); 391 392 case IPC_RMID: 393 return (AUE_SEMCTL_RMID); 394 395 case IPC_SET: 396 return (AUE_SEMCTL_SET); 397 398 case SETALL: 399 return (AUE_SEMCTL_SETALL); 400 401 case SETVAL: 402 return (AUE_SEMCTL_SETVAL); 403 404 case IPC_STAT: 405 return (AUE_SEMCTL_STAT); 406 407 default: 408 /* We will audit a bad command. */ 409 return (AUE_SEMCTL); 410 } 411 } 412 413 /* 414 * Convert a command for the auditon() system call to a audit event. 415 */ 416 au_event_t 417 auditon_command_event(int cmd) 418 { 419 420 switch(cmd) { 421 case A_GETPOLICY: 422 return (AUE_AUDITON_GPOLICY); 423 424 case A_SETPOLICY: 425 return (AUE_AUDITON_SPOLICY); 426 427 case A_GETKMASK: 428 return (AUE_AUDITON_GETKMASK); 429 430 case A_SETKMASK: 431 return (AUE_AUDITON_SETKMASK); 432 433 case A_GETQCTRL: 434 return (AUE_AUDITON_GQCTRL); 435 436 case A_SETQCTRL: 437 return (AUE_AUDITON_SQCTRL); 438 439 case A_GETCWD: 440 return (AUE_AUDITON_GETCWD); 441 442 case A_GETCAR: 443 return (AUE_AUDITON_GETCAR); 444 445 case A_GETSTAT: 446 return (AUE_AUDITON_GETSTAT); 447 448 case A_SETSTAT: 449 return (AUE_AUDITON_SETSTAT); 450 451 case A_SETUMASK: 452 return (AUE_AUDITON_SETUMASK); 453 454 case A_SETSMASK: 455 return (AUE_AUDITON_SETSMASK); 456 457 case A_GETCOND: 458 return (AUE_AUDITON_GETCOND); 459 460 case A_SETCOND: 461 return (AUE_AUDITON_SETCOND); 462 463 case A_GETCLASS: 464 return (AUE_AUDITON_GETCLASS); 465 466 case A_SETCLASS: 467 return (AUE_AUDITON_SETCLASS); 468 469 case A_GETPINFO: 470 case A_SETPMASK: 471 case A_SETFSIZE: 472 case A_GETFSIZE: 473 case A_GETPINFO_ADDR: 474 case A_GETKAUDIT: 475 case A_SETKAUDIT: 476 default: 477 return (AUE_AUDITON); /* No special record */ 478 } 479 } 480 481 /* 482 * Create a canonical path from given path by prefixing either the root 483 * directory, or the current working directory. If the process working 484 * directory is NULL, we could use 'rootvnode' to obtain the root directory, 485 * but this results in a volfs name written to the audit log. So we will 486 * leave the filename starting with '/' in the audit log in this case. 487 */ 488 void 489 audit_canon_path(struct thread *td, char *path, char *cpath) 490 { 491 struct vnode *cvnp, *rvnp; 492 char *rbuf, *fbuf, *copy; 493 struct filedesc *fdp; 494 struct sbuf sbf; 495 int error, cwir; 496 497 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d", 498 __func__, __FILE__, __LINE__); 499 500 copy = path; 501 rvnp = cvnp = NULL; 502 fdp = td->td_proc->p_fd; 503 FILEDESC_SLOCK(fdp); 504 /* 505 * Make sure that we handle the chroot(2) case. If there is an 506 * alternate root directory, prepend it to the audited pathname. 507 */ 508 if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) { 509 rvnp = fdp->fd_rdir; 510 vhold(rvnp); 511 } 512 /* 513 * If the supplied path is relative, make sure we capture the current 514 * working directory so we can prepend it to the supplied relative 515 * path. 516 */ 517 if (*path != '/') { 518 cvnp = fdp->fd_cdir; 519 vhold(cvnp); 520 } 521 cwir = (fdp->fd_rdir == fdp->fd_cdir); 522 FILEDESC_SUNLOCK(fdp); 523 /* 524 * NB: We require that the supplied array be at least MAXPATHLEN bytes 525 * long. If this is not the case, then we can run into serious trouble. 526 */ 527 (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN); 528 /* 529 * Strip leading forward slashes. 530 */ 531 while (*copy == '/') 532 copy++; 533 /* 534 * Make sure we handle chroot(2) and prepend the global path to these 535 * environments. 536 * 537 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9) 538 * on Darwin. As a result, this may need some additional attention 539 * in the future. 540 */ 541 if (rvnp != NULL) { 542 error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf); 543 vdrop(rvnp); 544 if (error) { 545 cpath[0] = '\0'; 546 if (cvnp != NULL) 547 vdrop(cvnp); 548 return; 549 } 550 (void) sbuf_cat(&sbf, rbuf); 551 free(fbuf, M_TEMP); 552 } 553 if (cvnp != NULL) { 554 error = vn_fullpath(td, cvnp, &rbuf, &fbuf); 555 vdrop(cvnp); 556 if (error) { 557 cpath[0] = '\0'; 558 return; 559 } 560 (void) sbuf_cat(&sbf, rbuf); 561 free(fbuf, M_TEMP); 562 } 563 if (cwir == 0 || (cwir != 0 && cvnp == NULL)) 564 (void) sbuf_putc(&sbf, '/'); 565 /* 566 * Now that we have processed any alternate root and relative path 567 * names, add the supplied pathname. 568 */ 569 (void) sbuf_cat(&sbf, copy); 570 /* 571 * One or more of the previous sbuf operations could have resulted in 572 * the supplied buffer being overflowed. Check to see if this is the 573 * case. 574 */ 575 if (sbuf_overflowed(&sbf) != 0) { 576 cpath[0] = '\0'; 577 return; 578 } 579 sbuf_finish(&sbf); 580 } 581