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_PROC: 186 case KERN_FILE: 187 case KERN_PROF: 188 case KERN_NISDOMAINNAME: 189 case KERN_UPDATEINTERVAL: 190 case KERN_NTP_PLL: 191 case KERN_BOOTFILE: 192 case KERN_DUMPDEV: 193 case KERN_IPC: 194 case KERN_PS_STRINGS: 195 case KERN_USRSTACK: 196 case KERN_LOGSIGEXIT: 197 case KERN_IOV_MAX: 198 return ((valid_arg & ARG_VALUE) ? 199 AUE_SYSCTL : AUE_SYSCTL_NONADMIN); 200 201 default: 202 return (AUE_SYSCTL); 203 } 204 /* NOTREACHED */ 205 } 206 207 /* 208 * Convert an open flags specifier into a specific type of open event for 209 * auditing purposes. 210 */ 211 au_event_t 212 audit_flags_and_error_to_openevent(int oflags, int error) 213 { 214 int i; 215 216 /* 217 * Need to check only those flags we care about. 218 */ 219 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 220 for (i = 0; i < nitems(aue_open); i++) { 221 if (aue_open[i].aoe_flags == oflags) 222 return (aue_open[i].aoe_event); 223 } 224 return (AUE_OPEN); 225 } 226 227 au_event_t 228 audit_flags_and_error_to_openatevent(int oflags, int error) 229 { 230 int i; 231 232 /* 233 * Need to check only those flags we care about. 234 */ 235 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 236 for (i = 0; i < nitems(aue_openat); i++) { 237 if (aue_openat[i].aoe_flags == oflags) 238 return (aue_openat[i].aoe_event); 239 } 240 return (AUE_OPENAT); 241 } 242 243 /* 244 * Convert a MSGCTL command to a specific event. 245 */ 246 au_event_t 247 audit_msgctl_to_event(int cmd) 248 { 249 250 switch (cmd) { 251 case IPC_RMID: 252 return (AUE_MSGCTL_RMID); 253 254 case IPC_SET: 255 return (AUE_MSGCTL_SET); 256 257 case IPC_STAT: 258 return (AUE_MSGCTL_STAT); 259 260 default: 261 /* We will audit a bad command. */ 262 return (AUE_MSGCTL); 263 } 264 } 265 266 /* 267 * Convert a SEMCTL command to a specific event. 268 */ 269 au_event_t 270 audit_semctl_to_event(int cmd) 271 { 272 273 switch (cmd) { 274 case GETALL: 275 return (AUE_SEMCTL_GETALL); 276 277 case GETNCNT: 278 return (AUE_SEMCTL_GETNCNT); 279 280 case GETPID: 281 return (AUE_SEMCTL_GETPID); 282 283 case GETVAL: 284 return (AUE_SEMCTL_GETVAL); 285 286 case GETZCNT: 287 return (AUE_SEMCTL_GETZCNT); 288 289 case IPC_RMID: 290 return (AUE_SEMCTL_RMID); 291 292 case IPC_SET: 293 return (AUE_SEMCTL_SET); 294 295 case SETALL: 296 return (AUE_SEMCTL_SETALL); 297 298 case SETVAL: 299 return (AUE_SEMCTL_SETVAL); 300 301 case IPC_STAT: 302 return (AUE_SEMCTL_STAT); 303 304 default: 305 /* We will audit a bad command. */ 306 return (AUE_SEMCTL); 307 } 308 } 309 310 /* 311 * Convert msgsys(2), semsys(2), and shmsys(2) system-call variations into 312 * audit events, if possible. 313 */ 314 au_event_t 315 audit_msgsys_to_event(int which) 316 { 317 318 if ((which >= 0) && (which < aue_msgsys_count)) 319 return (aue_msgsys[which]); 320 321 /* Audit a bad command. */ 322 return (AUE_MSGSYS); 323 } 324 325 au_event_t 326 audit_semsys_to_event(int which) 327 { 328 329 if ((which >= 0) && (which < aue_semsys_count)) 330 return (aue_semsys[which]); 331 332 /* Audit a bad command. */ 333 return (AUE_SEMSYS); 334 } 335 336 au_event_t 337 audit_shmsys_to_event(int which) 338 { 339 340 if ((which >= 0) && (which < aue_shmsys_count)) 341 return (aue_shmsys[which]); 342 343 /* Audit a bad command. */ 344 return (AUE_SHMSYS); 345 } 346 347 /* 348 * Convert a command for the auditon() system call to a audit event. 349 */ 350 au_event_t 351 auditon_command_event(int cmd) 352 { 353 354 switch(cmd) { 355 case A_GETPOLICY: 356 return (AUE_AUDITON_GPOLICY); 357 358 case A_SETPOLICY: 359 return (AUE_AUDITON_SPOLICY); 360 361 case A_GETKMASK: 362 return (AUE_AUDITON_GETKMASK); 363 364 case A_SETKMASK: 365 return (AUE_AUDITON_SETKMASK); 366 367 case A_GETQCTRL: 368 return (AUE_AUDITON_GQCTRL); 369 370 case A_SETQCTRL: 371 return (AUE_AUDITON_SQCTRL); 372 373 case A_GETCWD: 374 return (AUE_AUDITON_GETCWD); 375 376 case A_GETCAR: 377 return (AUE_AUDITON_GETCAR); 378 379 case A_GETSTAT: 380 return (AUE_AUDITON_GETSTAT); 381 382 case A_SETSTAT: 383 return (AUE_AUDITON_SETSTAT); 384 385 case A_SETUMASK: 386 return (AUE_AUDITON_SETUMASK); 387 388 case A_SETSMASK: 389 return (AUE_AUDITON_SETSMASK); 390 391 case A_GETCOND: 392 return (AUE_AUDITON_GETCOND); 393 394 case A_SETCOND: 395 return (AUE_AUDITON_SETCOND); 396 397 case A_GETCLASS: 398 return (AUE_AUDITON_GETCLASS); 399 400 case A_SETCLASS: 401 return (AUE_AUDITON_SETCLASS); 402 403 case A_GETPINFO: 404 case A_SETPMASK: 405 case A_SETFSIZE: 406 case A_GETFSIZE: 407 case A_GETPINFO_ADDR: 408 case A_GETKAUDIT: 409 case A_SETKAUDIT: 410 default: 411 return (AUE_AUDITON); /* No special record */ 412 } 413 } 414 415 /* 416 * Create a canonical path from given path by prefixing either the root 417 * directory, or the current working directory. If the process working 418 * directory is NULL, we could use 'rootvnode' to obtain the root directory, 419 * but this results in a volfs name written to the audit log. So we will 420 * leave the filename starting with '/' in the audit log in this case. 421 */ 422 void 423 audit_canon_path_vp(struct thread *td, struct vnode *rdir, struct vnode *cdir, 424 char *path, char *cpath) 425 { 426 struct vnode *vp; 427 char *rbuf, *fbuf, *copy; 428 struct sbuf sbf; 429 int error; 430 431 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d", 432 __func__, __FILE__, __LINE__); 433 434 copy = path; 435 if (*path == '/') { 436 vp = rdir; 437 } else { 438 if (cdir == NULL) { 439 cpath[0] = '\0'; 440 return; 441 } 442 vp = cdir; 443 } 444 MPASS(vp != NULL); 445 /* 446 * NB: We require that the supplied array be at least MAXPATHLEN bytes 447 * long. If this is not the case, then we can run into serious trouble. 448 */ 449 (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN); 450 /* 451 * Strip leading forward slashes. 452 * 453 * Note this does nothing to fully canonicalize the path. 454 */ 455 while (*copy == '/') 456 copy++; 457 /* 458 * Make sure we handle chroot(2) and prepend the global path to these 459 * environments. 460 * 461 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9) 462 * on Darwin. As a result, this may need some additional attention 463 * in the future. 464 */ 465 error = vn_fullpath_global(vp, &rbuf, &fbuf); 466 if (error) { 467 cpath[0] = '\0'; 468 return; 469 } 470 (void) sbuf_cat(&sbf, rbuf); 471 /* 472 * We are going to concatenate the resolved path with the passed path 473 * with all slashes removed and we want them glued with a single slash. 474 * However, if the directory is /, the slash is already there. 475 */ 476 if (rbuf[1] != '\0') 477 (void) sbuf_putc(&sbf, '/'); 478 free(fbuf, M_TEMP); 479 /* 480 * Now that we have processed any alternate root and relative path 481 * names, add the supplied pathname. 482 */ 483 (void) sbuf_cat(&sbf, copy); 484 /* 485 * One or more of the previous sbuf operations could have resulted in 486 * the supplied buffer being overflowed. Check to see if this is the 487 * case. 488 */ 489 if (sbuf_error(&sbf) != 0) { 490 cpath[0] = '\0'; 491 return; 492 } 493 sbuf_finish(&sbf); 494 } 495 496 void 497 audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath) 498 { 499 struct vnode *cdir, *rdir; 500 struct pwd *pwd; 501 cap_rights_t rights; 502 int error; 503 bool vrele_cdir; 504 505 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d", 506 __func__, __FILE__, __LINE__); 507 508 pwd = pwd_hold(td); 509 rdir = pwd->pwd_rdir; 510 cdir = NULL; 511 vrele_cdir = false; 512 if (*path != '/') { 513 if (dirfd == AT_FDCWD) { 514 cdir = pwd->pwd_cdir; 515 } else { 516 error = fgetvp(td, dirfd, cap_rights_init(&rights), &cdir); 517 if (error != 0) { 518 cpath[0] = '\0'; 519 pwd_drop(pwd); 520 return; 521 } 522 vrele_cdir = true; 523 } 524 } 525 526 audit_canon_path_vp(td, rdir, cdir, path, cpath); 527 528 pwd_drop(pwd); 529 if (vrele_cdir) 530 vrele(cdir); 531 } 532