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