1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1999-2009 Apple Inc. 5 * Copyright (c) 2005, 2016-2017 Robert N. M. Watson 6 * All rights reserved. 7 * 8 * Portions of this software were developed by BAE Systems, the University of 9 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 10 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 11 * Computing (TC) research program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 22 * its contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 29 * 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, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/param.h> 42 #include <sys/capsicum.h> 43 #include <sys/fcntl.h> 44 #include <sys/filedesc.h> 45 #include <sys/libkern.h> 46 #include <sys/malloc.h> 47 #include <sys/mount.h> 48 #include <sys/proc.h> 49 #include <sys/rwlock.h> 50 #include <sys/sem.h> 51 #include <sys/sbuf.h> 52 #include <sys/sx.h> 53 #include <sys/syscall.h> 54 #include <sys/sysctl.h> 55 #include <sys/sysent.h> 56 #include <sys/vnode.h> 57 58 #include <bsm/audit.h> 59 #include <bsm/audit_kevents.h> 60 #include <security/audit/audit.h> 61 #include <security/audit/audit_private.h> 62 63 struct aue_open_event { 64 int aoe_flags; 65 au_event_t aoe_event; 66 }; 67 68 static const struct aue_open_event aue_open[] = { 69 { O_RDONLY, AUE_OPEN_R }, 70 { (O_RDONLY | O_CREAT), AUE_OPEN_RC }, 71 { (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPEN_RTC }, 72 { (O_RDONLY | O_TRUNC), AUE_OPEN_RT }, 73 { O_RDWR, AUE_OPEN_RW }, 74 { (O_RDWR | O_CREAT), AUE_OPEN_RWC }, 75 { (O_RDWR | O_CREAT | O_TRUNC), AUE_OPEN_RWTC }, 76 { (O_RDWR | O_TRUNC), AUE_OPEN_RWT }, 77 { O_WRONLY, AUE_OPEN_W }, 78 { (O_WRONLY | O_CREAT), AUE_OPEN_WC }, 79 { (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPEN_WTC }, 80 { (O_WRONLY | O_TRUNC), AUE_OPEN_WT }, 81 }; 82 83 static const struct aue_open_event aue_openat[] = { 84 { O_RDONLY, AUE_OPENAT_R }, 85 { (O_RDONLY | O_CREAT), AUE_OPENAT_RC }, 86 { (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPENAT_RTC }, 87 { (O_RDONLY | O_TRUNC), AUE_OPENAT_RT }, 88 { O_RDWR, AUE_OPENAT_RW }, 89 { (O_RDWR | O_CREAT), AUE_OPENAT_RWC }, 90 { (O_RDWR | O_CREAT | O_TRUNC), AUE_OPENAT_RWTC }, 91 { (O_RDWR | O_TRUNC), AUE_OPENAT_RWT }, 92 { O_WRONLY, AUE_OPENAT_W }, 93 { (O_WRONLY | O_CREAT), AUE_OPENAT_WC }, 94 { (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPENAT_WTC }, 95 { (O_WRONLY | O_TRUNC), AUE_OPENAT_WT }, 96 }; 97 98 static const int aue_msgsys[] = { 99 /* 0 */ AUE_MSGCTL, 100 /* 1 */ AUE_MSGGET, 101 /* 2 */ AUE_MSGSND, 102 /* 3 */ AUE_MSGRCV, 103 }; 104 static const int aue_msgsys_count = sizeof(aue_msgsys) / sizeof(int); 105 106 static const int aue_semsys[] = { 107 /* 0 */ AUE_SEMCTL, 108 /* 1 */ AUE_SEMGET, 109 /* 2 */ AUE_SEMOP, 110 }; 111 static const int aue_semsys_count = sizeof(aue_semsys) / sizeof(int); 112 113 static const int aue_shmsys[] = { 114 /* 0 */ AUE_SHMAT, 115 /* 1 */ AUE_SHMDT, 116 /* 2 */ AUE_SHMGET, 117 /* 3 */ AUE_SHMCTL, 118 }; 119 static const int aue_shmsys_count = sizeof(aue_shmsys) / sizeof(int); 120 121 /* 122 * Check whether an event is auditable by comparing the mask of classes this 123 * event is part of against the given mask. 124 */ 125 int 126 au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf) 127 { 128 au_class_t effmask = 0; 129 130 if (mask_p == NULL) 131 return (-1); 132 133 /* 134 * Perform the actual check of the masks against the event. 135 */ 136 if (sorf & AU_PRS_SUCCESS) 137 effmask |= (mask_p->am_success & class); 138 139 if (sorf & AU_PRS_FAILURE) 140 effmask |= (mask_p->am_failure & class); 141 142 if (effmask) 143 return (1); 144 else 145 return (0); 146 } 147 148 /* 149 * Convert sysctl names and present arguments to events. 150 */ 151 au_event_t 152 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg) 153 { 154 155 /* can't parse it - so return the worst case */ 156 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) 157 return (AUE_SYSCTL); 158 159 switch (name[0]) { 160 /* non-admin "lookups" treat them special */ 161 case KERN_OSTYPE: 162 case KERN_OSRELEASE: 163 case KERN_OSREV: 164 case KERN_VERSION: 165 case KERN_ARGMAX: 166 case KERN_CLOCKRATE: 167 case KERN_BOOTTIME: 168 case KERN_POSIX1: 169 case KERN_NGROUPS: 170 case KERN_JOB_CONTROL: 171 case KERN_SAVED_IDS: 172 case KERN_OSRELDATE: 173 case KERN_DUMMY: 174 return (AUE_SYSCTL_NONADMIN); 175 176 /* only treat the changeable controls as admin */ 177 case KERN_MAXVNODES: 178 case KERN_MAXPROC: 179 case KERN_MAXFILES: 180 case KERN_MAXPROCPERUID: 181 case KERN_MAXFILESPERPROC: 182 case KERN_HOSTID: 183 case KERN_SECURELVL: 184 case KERN_HOSTNAME: 185 case KERN_VNODE: 186 case KERN_PROC: 187 case KERN_FILE: 188 case KERN_PROF: 189 case KERN_NISDOMAINNAME: 190 case KERN_UPDATEINTERVAL: 191 case KERN_NTP_PLL: 192 case KERN_BOOTFILE: 193 case KERN_DUMPDEV: 194 case KERN_IPC: 195 case KERN_PS_STRINGS: 196 case KERN_USRSTACK: 197 case KERN_LOGSIGEXIT: 198 case KERN_IOV_MAX: 199 return ((valid_arg & ARG_VALUE) ? 200 AUE_SYSCTL : AUE_SYSCTL_NONADMIN); 201 202 default: 203 return (AUE_SYSCTL); 204 } 205 /* NOTREACHED */ 206 } 207 208 /* 209 * Convert an open flags specifier into a specific type of open event for 210 * auditing purposes. 211 */ 212 au_event_t 213 audit_flags_and_error_to_openevent(int oflags, int error) 214 { 215 int i; 216 217 /* 218 * Need to check only those flags we care about. 219 */ 220 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 221 for (i = 0; i < nitems(aue_open); i++) { 222 if (aue_open[i].aoe_flags == oflags) 223 return (aue_open[i].aoe_event); 224 } 225 return (AUE_OPEN); 226 } 227 228 au_event_t 229 audit_flags_and_error_to_openatevent(int oflags, int error) 230 { 231 int i; 232 233 /* 234 * Need to check only those flags we care about. 235 */ 236 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 237 for (i = 0; i < nitems(aue_openat); i++) { 238 if (aue_openat[i].aoe_flags == oflags) 239 return (aue_openat[i].aoe_event); 240 } 241 return (AUE_OPENAT); 242 } 243 244 /* 245 * Convert a MSGCTL command to a specific event. 246 */ 247 au_event_t 248 audit_msgctl_to_event(int cmd) 249 { 250 251 switch (cmd) { 252 case IPC_RMID: 253 return (AUE_MSGCTL_RMID); 254 255 case IPC_SET: 256 return (AUE_MSGCTL_SET); 257 258 case IPC_STAT: 259 return (AUE_MSGCTL_STAT); 260 261 default: 262 /* We will audit a bad command. */ 263 return (AUE_MSGCTL); 264 } 265 } 266 267 /* 268 * Convert a SEMCTL command to a specific event. 269 */ 270 au_event_t 271 audit_semctl_to_event(int cmd) 272 { 273 274 switch (cmd) { 275 case GETALL: 276 return (AUE_SEMCTL_GETALL); 277 278 case GETNCNT: 279 return (AUE_SEMCTL_GETNCNT); 280 281 case GETPID: 282 return (AUE_SEMCTL_GETPID); 283 284 case GETVAL: 285 return (AUE_SEMCTL_GETVAL); 286 287 case GETZCNT: 288 return (AUE_SEMCTL_GETZCNT); 289 290 case IPC_RMID: 291 return (AUE_SEMCTL_RMID); 292 293 case IPC_SET: 294 return (AUE_SEMCTL_SET); 295 296 case SETALL: 297 return (AUE_SEMCTL_SETALL); 298 299 case SETVAL: 300 return (AUE_SEMCTL_SETVAL); 301 302 case IPC_STAT: 303 return (AUE_SEMCTL_STAT); 304 305 default: 306 /* We will audit a bad command. */ 307 return (AUE_SEMCTL); 308 } 309 } 310 311 /* 312 * Convert msgsys(2), semsys(2), and shmsys(2) system-call variations into 313 * audit events, if possible. 314 */ 315 au_event_t 316 audit_msgsys_to_event(int which) 317 { 318 319 if ((which >= 0) && (which < aue_msgsys_count)) 320 return (aue_msgsys[which]); 321 322 /* Audit a bad command. */ 323 return (AUE_MSGSYS); 324 } 325 326 au_event_t 327 audit_semsys_to_event(int which) 328 { 329 330 if ((which >= 0) && (which < aue_semsys_count)) 331 return (aue_semsys[which]); 332 333 /* Audit a bad command. */ 334 return (AUE_SEMSYS); 335 } 336 337 au_event_t 338 audit_shmsys_to_event(int which) 339 { 340 341 if ((which >= 0) && (which < aue_shmsys_count)) 342 return (aue_shmsys[which]); 343 344 /* Audit a bad command. */ 345 return (AUE_SHMSYS); 346 } 347 348 /* 349 * Convert a command for the auditon() system call to a audit event. 350 */ 351 au_event_t 352 auditon_command_event(int cmd) 353 { 354 355 switch(cmd) { 356 case A_GETPOLICY: 357 return (AUE_AUDITON_GPOLICY); 358 359 case A_SETPOLICY: 360 return (AUE_AUDITON_SPOLICY); 361 362 case A_GETKMASK: 363 return (AUE_AUDITON_GETKMASK); 364 365 case A_SETKMASK: 366 return (AUE_AUDITON_SETKMASK); 367 368 case A_GETQCTRL: 369 return (AUE_AUDITON_GQCTRL); 370 371 case A_SETQCTRL: 372 return (AUE_AUDITON_SQCTRL); 373 374 case A_GETCWD: 375 return (AUE_AUDITON_GETCWD); 376 377 case A_GETCAR: 378 return (AUE_AUDITON_GETCAR); 379 380 case A_GETSTAT: 381 return (AUE_AUDITON_GETSTAT); 382 383 case A_SETSTAT: 384 return (AUE_AUDITON_SETSTAT); 385 386 case A_SETUMASK: 387 return (AUE_AUDITON_SETUMASK); 388 389 case A_SETSMASK: 390 return (AUE_AUDITON_SETSMASK); 391 392 case A_GETCOND: 393 return (AUE_AUDITON_GETCOND); 394 395 case A_SETCOND: 396 return (AUE_AUDITON_SETCOND); 397 398 case A_GETCLASS: 399 return (AUE_AUDITON_GETCLASS); 400 401 case A_SETCLASS: 402 return (AUE_AUDITON_SETCLASS); 403 404 case A_GETPINFO: 405 case A_SETPMASK: 406 case A_SETFSIZE: 407 case A_GETFSIZE: 408 case A_GETPINFO_ADDR: 409 case A_GETKAUDIT: 410 case A_SETKAUDIT: 411 default: 412 return (AUE_AUDITON); /* No special record */ 413 } 414 } 415 416 /* 417 * Create a canonical path from given path by prefixing either the root 418 * directory, or the current working directory. If the process working 419 * directory is NULL, we could use 'rootvnode' to obtain the root directory, 420 * but this results in a volfs name written to the audit log. So we will 421 * leave the filename starting with '/' in the audit log in this case. 422 */ 423 void 424 audit_canon_path_vp(struct thread *td, struct vnode *rdir, struct vnode *cdir, 425 char *path, char *cpath) 426 { 427 struct vnode *vp; 428 char *rbuf, *fbuf, *copy; 429 struct sbuf sbf; 430 int error; 431 432 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d", 433 __func__, __FILE__, __LINE__); 434 435 copy = path; 436 if (*path == '/') { 437 vp = rdir; 438 } else { 439 if (cdir == NULL) { 440 cpath[0] = '\0'; 441 return; 442 } 443 vp = cdir; 444 } 445 MPASS(vp != NULL); 446 /* 447 * NB: We require that the supplied array be at least MAXPATHLEN bytes 448 * long. If this is not the case, then we can run into serious trouble. 449 */ 450 (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN); 451 /* 452 * Strip leading forward slashes. 453 * 454 * Note this does nothing to fully canonicalize the path. 455 */ 456 while (*copy == '/') 457 copy++; 458 /* 459 * Make sure we handle chroot(2) and prepend the global path to these 460 * environments. 461 * 462 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9) 463 * on Darwin. As a result, this may need some additional attention 464 * in the future. 465 */ 466 error = vn_fullpath_global(vp, &rbuf, &fbuf); 467 if (error) { 468 cpath[0] = '\0'; 469 return; 470 } 471 (void) sbuf_cat(&sbf, rbuf); 472 /* 473 * We are going to concatenate the resolved path with the passed path 474 * with all slashes removed and we want them glued with a single slash. 475 * However, if the directory is /, the slash is already there. 476 */ 477 if (rbuf[1] != '\0') 478 (void) sbuf_putc(&sbf, '/'); 479 free(fbuf, M_TEMP); 480 /* 481 * Now that we have processed any alternate root and relative path 482 * names, add the supplied pathname. 483 */ 484 (void) sbuf_cat(&sbf, copy); 485 /* 486 * One or more of the previous sbuf operations could have resulted in 487 * the supplied buffer being overflowed. Check to see if this is the 488 * case. 489 */ 490 if (sbuf_error(&sbf) != 0) { 491 cpath[0] = '\0'; 492 return; 493 } 494 sbuf_finish(&sbf); 495 } 496 497 void 498 audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath) 499 { 500 struct vnode *cdir, *rdir; 501 struct pwd *pwd; 502 cap_rights_t rights; 503 int error; 504 bool vrele_cdir; 505 506 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d", 507 __func__, __FILE__, __LINE__); 508 509 pwd = pwd_hold(td); 510 rdir = pwd->pwd_rdir; 511 cdir = NULL; 512 vrele_cdir = false; 513 if (*path != '/') { 514 if (dirfd == AT_FDCWD) { 515 cdir = pwd->pwd_cdir; 516 } else { 517 error = fgetvp(td, dirfd, cap_rights_init(&rights), &cdir); 518 if (error != 0) { 519 cpath[0] = '\0'; 520 pwd_drop(pwd); 521 return; 522 } 523 vrele_cdir = true; 524 } 525 } 526 527 audit_canon_path_vp(td, rdir, cdir, path, cpath); 528 529 pwd_drop(pwd); 530 if (vrele_cdir) 531 vrele(cdir); 532 } 533