1 /* 2 * Copyright (c) 1999-2005 Apple Computer, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/mount.h> 34 #include <sys/namei.h> 35 #include <sys/priv.h> 36 #include <sys/proc.h> 37 #include <sys/sysproto.h> 38 #include <sys/systm.h> 39 #include <sys/vnode.h> 40 #include <sys/jail.h> 41 42 #include <bsm/audit.h> 43 #include <bsm/audit_kevents.h> 44 #include <security/audit/audit.h> 45 #include <security/audit/audit_private.h> 46 47 #ifdef AUDIT 48 49 /* 50 * System call to allow a user space application to submit a BSM audit record 51 * to the kernel for inclusion in the audit log. This function does little 52 * verification on the audit record that is submitted. 53 * 54 * XXXAUDIT: Audit preselection for user records does not currently work, 55 * since we pre-select only based on the AUE_audit event type, not the event 56 * type submitted as part of the user audit data. 57 */ 58 /* ARGSUSED */ 59 int 60 audit(struct thread *td, struct audit_args *uap) 61 { 62 int error; 63 void * rec; 64 struct kaudit_record *ar; 65 66 if (jailed(td->td_ucred)) 67 return (ENOSYS); 68 error = priv_check(td, PRIV_AUDIT_SUBMIT); 69 if (error) 70 return (error); 71 72 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) 73 return (EINVAL); 74 75 ar = currecord(); 76 77 /* 78 * If there's no current audit record (audit() itself not audited) 79 * commit the user audit record. 80 */ 81 if (ar == NULL) { 82 83 /* 84 * This is not very efficient; we're required to allocate a 85 * complete kernel audit record just so the user record can 86 * tag along. 87 * 88 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and 89 * special pre-select handling? 90 */ 91 td->td_ar = audit_new(AUE_NULL, td); 92 if (td->td_ar == NULL) 93 return (ENOTSUP); 94 ar = td->td_ar; 95 } 96 97 if (uap->length > MAX_AUDIT_RECORD_SIZE) 98 return (EINVAL); 99 100 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 101 102 error = copyin(uap->record, rec, uap->length); 103 if (error) 104 goto free_out; 105 106 /* Verify the record. */ 107 if (bsm_rec_verify(rec) == 0) { 108 error = EINVAL; 109 goto free_out; 110 } 111 112 /* 113 * Attach the user audit record to the kernel audit record. Because 114 * this system call is an auditable event, we will write the user 115 * record along with the record for this audit event. 116 * 117 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 118 * k_ar_commit & AR_COMMIT_USER? 119 */ 120 ar->k_udata = rec; 121 ar->k_ulen = uap->length; 122 ar->k_ar_commit |= AR_COMMIT_USER; 123 124 /* 125 * Currently we assume that all preselection has been performed in 126 * userspace. We unconditionally set these masks so that the records 127 * get committed both to the trail and pipe. In the future we will 128 * want to setup kernel based preselection. 129 */ 130 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 131 return (0); 132 133 free_out: 134 /* 135 * audit_syscall_exit() will free the audit record on the thread even 136 * if we allocated it above. 137 */ 138 free(rec, M_AUDITDATA); 139 return (error); 140 } 141 142 /* 143 * System call to manipulate auditing. 144 */ 145 /* ARGSUSED */ 146 int 147 auditon(struct thread *td, struct auditon_args *uap) 148 { 149 int error; 150 union auditon_udata udata; 151 struct proc *tp; 152 153 if (jailed(td->td_ucred)) 154 return (ENOSYS); 155 AUDIT_ARG(cmd, uap->cmd); 156 error = priv_check(td, PRIV_AUDIT_CONTROL); 157 if (error) 158 return (error); 159 160 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) 161 return (EINVAL); 162 163 memset((void *)&udata, 0, sizeof(udata)); 164 165 /* 166 * Some of the GET commands use the arguments too. 167 */ 168 switch (uap->cmd) { 169 case A_SETPOLICY: 170 case A_SETKMASK: 171 case A_SETQCTRL: 172 case A_SETSTAT: 173 case A_SETUMASK: 174 case A_SETSMASK: 175 case A_SETCOND: 176 case A_SETCLASS: 177 case A_SETPMASK: 178 case A_SETFSIZE: 179 case A_SETKAUDIT: 180 case A_GETCLASS: 181 case A_GETPINFO: 182 case A_GETPINFO_ADDR: 183 case A_SENDTRIGGER: 184 error = copyin(uap->data, (void *)&udata, uap->length); 185 if (error) 186 return (error); 187 AUDIT_ARG(auditon, &udata); 188 break; 189 } 190 191 /* 192 * XXXAUDIT: Locking? 193 */ 194 switch (uap->cmd) { 195 case A_GETPOLICY: 196 if (!audit_fail_stop) 197 udata.au_policy |= AUDIT_CNT; 198 if (audit_panic_on_write_fail) 199 udata.au_policy |= AUDIT_AHLT; 200 if (audit_argv) 201 udata.au_policy |= AUDIT_ARGV; 202 if (audit_arge) 203 udata.au_policy |= AUDIT_ARGE; 204 break; 205 206 case A_SETPOLICY: 207 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 208 AUDIT_ARGE)) 209 return (EINVAL); 210 /* 211 * XXX - Need to wake up waiters if the policy relaxes? 212 */ 213 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 214 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 215 audit_argv = (udata.au_policy & AUDIT_ARGV); 216 audit_arge = (udata.au_policy & AUDIT_ARGE); 217 break; 218 219 case A_GETKMASK: 220 udata.au_mask = audit_nae_mask; 221 break; 222 223 case A_SETKMASK: 224 audit_nae_mask = udata.au_mask; 225 break; 226 227 case A_GETQCTRL: 228 udata.au_qctrl = audit_qctrl; 229 break; 230 231 case A_SETQCTRL: 232 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 233 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 234 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 235 (udata.au_qctrl.aq_minfree < 0) || 236 (udata.au_qctrl.aq_minfree > 100)) 237 return (EINVAL); 238 239 audit_qctrl = udata.au_qctrl; 240 /* XXX The queue delay value isn't used with the kernel. */ 241 audit_qctrl.aq_delay = -1; 242 break; 243 244 case A_GETCWD: 245 return (ENOSYS); 246 break; 247 248 case A_GETCAR: 249 return (ENOSYS); 250 break; 251 252 case A_GETSTAT: 253 return (ENOSYS); 254 break; 255 256 case A_SETSTAT: 257 return (ENOSYS); 258 break; 259 260 case A_SETUMASK: 261 return (ENOSYS); 262 break; 263 264 case A_SETSMASK: 265 return (ENOSYS); 266 break; 267 268 case A_GETCOND: 269 if (audit_enabled && !audit_suspended) 270 udata.au_cond = AUC_AUDITING; 271 else 272 udata.au_cond = AUC_NOAUDIT; 273 break; 274 275 case A_SETCOND: 276 if (udata.au_cond == AUC_NOAUDIT) 277 audit_suspended = 1; 278 if (udata.au_cond == AUC_AUDITING) 279 audit_suspended = 0; 280 if (udata.au_cond == AUC_DISABLED) { 281 audit_suspended = 1; 282 audit_shutdown(NULL, 0); 283 } 284 break; 285 286 case A_GETCLASS: 287 udata.au_evclass.ec_class = au_event_class( 288 udata.au_evclass.ec_number); 289 break; 290 291 case A_SETCLASS: 292 au_evclassmap_insert(udata.au_evclass.ec_number, 293 udata.au_evclass.ec_class); 294 break; 295 296 case A_GETPINFO: 297 if (udata.au_aupinfo.ap_pid < 1) 298 return (EINVAL); 299 300 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 301 return (EINVAL); 302 if (p_cansee(td, tp) != 0) { 303 PROC_UNLOCK(tp); 304 return (EINVAL); 305 } 306 307 udata.au_aupinfo.ap_auid = tp->p_au->ai_auid; 308 udata.au_aupinfo.ap_mask.am_success = 309 tp->p_au->ai_mask.am_success; 310 udata.au_aupinfo.ap_mask.am_failure = 311 tp->p_au->ai_mask.am_failure; 312 udata.au_aupinfo.ap_termid.machine = 313 tp->p_au->ai_termid.machine; 314 udata.au_aupinfo.ap_termid.port = tp->p_au->ai_termid.port; 315 udata.au_aupinfo.ap_asid = tp->p_au->ai_asid; 316 PROC_UNLOCK(tp); 317 break; 318 319 case A_SETPMASK: 320 if (udata.au_aupinfo.ap_pid < 1) 321 return (EINVAL); 322 323 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 324 return (EINVAL); 325 if (p_cansee(td, tp) != 0) { 326 PROC_UNLOCK(tp); 327 return (EINVAL); 328 } 329 330 tp->p_au->ai_mask.am_success = 331 udata.au_aupinfo.ap_mask.am_success; 332 tp->p_au->ai_mask.am_failure = 333 udata.au_aupinfo.ap_mask.am_failure; 334 PROC_UNLOCK(tp); 335 break; 336 337 case A_SETFSIZE: 338 if ((udata.au_fstat.af_filesz != 0) && 339 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 340 return (EINVAL); 341 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 342 break; 343 344 case A_GETFSIZE: 345 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 346 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 347 break; 348 349 case A_GETPINFO_ADDR: 350 return (ENOSYS); 351 break; 352 353 case A_GETKAUDIT: 354 return (ENOSYS); 355 break; 356 357 case A_SETKAUDIT: 358 return (ENOSYS); 359 break; 360 361 case A_SENDTRIGGER: 362 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 363 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 364 return (EINVAL); 365 return (send_trigger(udata.au_trigger)); 366 } 367 368 /* 369 * Copy data back to userspace for the GET comands. 370 */ 371 switch (uap->cmd) { 372 case A_GETPOLICY: 373 case A_GETKMASK: 374 case A_GETQCTRL: 375 case A_GETCWD: 376 case A_GETCAR: 377 case A_GETSTAT: 378 case A_GETCOND: 379 case A_GETCLASS: 380 case A_GETPINFO: 381 case A_GETFSIZE: 382 case A_GETPINFO_ADDR: 383 case A_GETKAUDIT: 384 error = copyout((void *)&udata, uap->data, uap->length); 385 if (error) 386 return (error); 387 break; 388 } 389 390 return (0); 391 } 392 393 /* 394 * System calls to manage the user audit information. 395 */ 396 /* ARGSUSED */ 397 int 398 getauid(struct thread *td, struct getauid_args *uap) 399 { 400 int error; 401 au_id_t id; 402 403 if (jailed(td->td_ucred)) 404 return (ENOSYS); 405 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 406 if (error) 407 return (error); 408 409 /* 410 * XXX: Integer read on static pointer dereference: doesn't need 411 * locking? 412 */ 413 PROC_LOCK(td->td_proc); 414 id = td->td_proc->p_au->ai_auid; 415 PROC_UNLOCK(td->td_proc); 416 return copyout(&id, uap->auid, sizeof(id)); 417 } 418 419 /* ARGSUSED */ 420 int 421 setauid(struct thread *td, struct setauid_args *uap) 422 { 423 int error; 424 au_id_t id; 425 426 if (jailed(td->td_ucred)) 427 return (ENOSYS); 428 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 429 if (error) 430 return (error); 431 432 error = copyin(uap->auid, &id, sizeof(id)); 433 if (error) 434 return (error); 435 436 audit_arg_auid(id); 437 438 /* 439 * XXX: Integer write on static pointer dereference: doesn't need 440 * locking? 441 * 442 * XXXAUDIT: Might need locking to serialize audit events in the same 443 * order as change events? Or maybe that's an under-solveable 444 * problem. 445 * 446 * XXXRW: Test privilege while holding the proc lock? 447 */ 448 PROC_LOCK(td->td_proc); 449 td->td_proc->p_au->ai_auid = id; 450 PROC_UNLOCK(td->td_proc); 451 452 return (0); 453 } 454 455 /* 456 * System calls to get and set process audit information. 457 */ 458 /* ARGSUSED */ 459 int 460 getaudit(struct thread *td, struct getaudit_args *uap) 461 { 462 struct auditinfo ai; 463 int error; 464 465 if (jailed(td->td_ucred)) 466 return (ENOSYS); 467 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 468 if (error) 469 return (error); 470 471 PROC_LOCK(td->td_proc); 472 ai = *td->td_proc->p_au; 473 PROC_UNLOCK(td->td_proc); 474 475 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 476 } 477 478 /* ARGSUSED */ 479 int 480 setaudit(struct thread *td, struct setaudit_args *uap) 481 { 482 struct auditinfo ai; 483 int error; 484 485 if (jailed(td->td_ucred)) 486 return (ENOSYS); 487 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 488 if (error) 489 return (error); 490 491 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 492 if (error) 493 return (error); 494 495 audit_arg_auditinfo(&ai); 496 497 /* 498 * XXXRW: Test privilege while holding the proc lock? 499 */ 500 PROC_LOCK(td->td_proc); 501 *td->td_proc->p_au = ai; 502 PROC_UNLOCK(td->td_proc); 503 504 return (0); 505 } 506 507 /* ARGSUSED */ 508 int 509 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 510 { 511 int error; 512 513 if (jailed(td->td_ucred)) 514 return (ENOSYS); 515 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 516 if (error) 517 return (error); 518 return (ENOSYS); 519 } 520 521 /* ARGSUSED */ 522 int 523 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 524 { 525 int error; 526 527 if (jailed(td->td_ucred)) 528 return (ENOSYS); 529 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 530 if (error) 531 return (error); 532 return (ENOSYS); 533 } 534 535 /* 536 * Syscall to manage audit files. 537 */ 538 /* ARGSUSED */ 539 int 540 auditctl(struct thread *td, struct auditctl_args *uap) 541 { 542 struct nameidata nd; 543 struct ucred *cred; 544 struct vnode *vp; 545 int error = 0; 546 int flags, vfslocked; 547 548 if (jailed(td->td_ucred)) 549 return (ENOSYS); 550 error = priv_check(td, PRIV_AUDIT_CONTROL); 551 if (error) 552 return (error); 553 554 vp = NULL; 555 cred = NULL; 556 557 /* 558 * If a path is specified, open the replacement vnode, perform 559 * validity checks, and grab another reference to the current 560 * credential. 561 * 562 * On Darwin, a NULL path argument is also used to disable audit. 563 */ 564 if (uap->path == NULL) 565 return (EINVAL); 566 567 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 568 UIO_USERSPACE, uap->path, td); 569 flags = AUDIT_OPEN_FLAGS; 570 error = vn_open(&nd, &flags, 0, -1); 571 if (error) 572 return (error); 573 vfslocked = NDHASGIANT(&nd); 574 vp = nd.ni_vp; 575 VOP_UNLOCK(vp, 0, td); 576 NDFREE(&nd, NDF_ONLY_PNBUF); 577 if (vp->v_type != VREG) { 578 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 579 VFS_UNLOCK_GIANT(vfslocked); 580 return (EINVAL); 581 } 582 VFS_UNLOCK_GIANT(vfslocked); 583 cred = td->td_ucred; 584 crhold(cred); 585 586 /* 587 * XXXAUDIT: Should audit_suspended actually be cleared by 588 * audit_worker? 589 */ 590 audit_suspended = 0; 591 592 audit_rotate_vnode(cred, vp); 593 594 return (error); 595 } 596 597 #else /* !AUDIT */ 598 599 int 600 audit(struct thread *td, struct audit_args *uap) 601 { 602 603 return (ENOSYS); 604 } 605 606 int 607 auditon(struct thread *td, struct auditon_args *uap) 608 { 609 610 return (ENOSYS); 611 } 612 613 int 614 getauid(struct thread *td, struct getauid_args *uap) 615 { 616 617 return (ENOSYS); 618 } 619 620 int 621 setauid(struct thread *td, struct setauid_args *uap) 622 { 623 624 return (ENOSYS); 625 } 626 627 int 628 getaudit(struct thread *td, struct getaudit_args *uap) 629 { 630 631 return (ENOSYS); 632 } 633 634 int 635 setaudit(struct thread *td, struct setaudit_args *uap) 636 { 637 638 return (ENOSYS); 639 } 640 641 int 642 getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 643 { 644 645 return (ENOSYS); 646 } 647 648 int 649 setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 650 { 651 652 return (ENOSYS); 653 } 654 655 int 656 auditctl(struct thread *td, struct auditctl_args *uap) 657 { 658 659 return (ENOSYS); 660 } 661 662 void 663 audit_proc_init(struct proc *p) 664 { 665 666 } 667 668 void 669 audit_proc_fork(struct proc *parent, struct proc *child) 670 { 671 672 } 673 674 void 675 audit_proc_free(struct proc *p) 676 { 677 678 } 679 680 #endif /* AUDIT */ 681