audit_syscalls.c revision 168688
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: head/sys/security/audit/audit_syscalls.c 168688 2007-04-13 14:55:19Z csjp $ 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 */ 59int 60audit(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 133free_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 */ 146int 147auditon(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 if (tp->p_au->ai_termid.at_type == AU_IPv6) { 308 PROC_UNLOCK(tp); 309 return (EINVAL); 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.at_addr[0]; 318 udata.au_aupinfo.ap_termid.port = 319 (dev_t)tp->p_au->ai_termid.at_port; 320 udata.au_aupinfo.ap_asid = tp->p_au->ai_asid; 321 PROC_UNLOCK(tp); 322 break; 323 324 case A_SETPMASK: 325 if (udata.au_aupinfo.ap_pid < 1) 326 return (EINVAL); 327 328 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 329 return (EINVAL); 330 if (p_cansee(td, tp) != 0) { 331 PROC_UNLOCK(tp); 332 return (EINVAL); 333 } 334 335 tp->p_au->ai_mask.am_success = 336 udata.au_aupinfo.ap_mask.am_success; 337 tp->p_au->ai_mask.am_failure = 338 udata.au_aupinfo.ap_mask.am_failure; 339 PROC_UNLOCK(tp); 340 break; 341 342 case A_SETFSIZE: 343 if ((udata.au_fstat.af_filesz != 0) && 344 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 345 return (EINVAL); 346 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 347 break; 348 349 case A_GETFSIZE: 350 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 351 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 352 break; 353 354 case A_GETPINFO_ADDR: 355 if (udata.au_aupinfo_addr.ap_pid < 1) 356 return (EINVAL); 357 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 358 return (EINVAL); 359 udata.au_aupinfo_addr.ap_auid = tp->p_au->ai_auid; 360 udata.au_aupinfo_addr.ap_mask.am_success = 361 tp->p_au->ai_mask.am_success; 362 udata.au_aupinfo_addr.ap_mask.am_failure = 363 tp->p_au->ai_mask.am_failure; 364 udata.au_aupinfo_addr.ap_termid = tp->p_au->ai_termid; 365 udata.au_aupinfo_addr.ap_asid = tp->p_au->ai_asid; 366 PROC_UNLOCK(tp); 367 break; 368 369 case A_GETKAUDIT: 370 return (ENOSYS); 371 break; 372 373 case A_SETKAUDIT: 374 return (ENOSYS); 375 break; 376 377 case A_SENDTRIGGER: 378 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 379 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 380 return (EINVAL); 381 return (send_trigger(udata.au_trigger)); 382 } 383 384 /* 385 * Copy data back to userspace for the GET comands. 386 */ 387 switch (uap->cmd) { 388 case A_GETPOLICY: 389 case A_GETKMASK: 390 case A_GETQCTRL: 391 case A_GETCWD: 392 case A_GETCAR: 393 case A_GETSTAT: 394 case A_GETCOND: 395 case A_GETCLASS: 396 case A_GETPINFO: 397 case A_GETFSIZE: 398 case A_GETPINFO_ADDR: 399 case A_GETKAUDIT: 400 error = copyout((void *)&udata, uap->data, uap->length); 401 if (error) 402 return (error); 403 break; 404 } 405 406 return (0); 407} 408 409/* 410 * System calls to manage the user audit information. 411 */ 412/* ARGSUSED */ 413int 414getauid(struct thread *td, struct getauid_args *uap) 415{ 416 int error; 417 au_id_t id; 418 419 if (jailed(td->td_ucred)) 420 return (ENOSYS); 421 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 422 if (error) 423 return (error); 424 425 /* 426 * XXX: Integer read on static pointer dereference: doesn't need 427 * locking? 428 */ 429 PROC_LOCK(td->td_proc); 430 id = td->td_proc->p_au->ai_auid; 431 PROC_UNLOCK(td->td_proc); 432 return copyout(&id, uap->auid, sizeof(id)); 433} 434 435/* ARGSUSED */ 436int 437setauid(struct thread *td, struct setauid_args *uap) 438{ 439 int error; 440 au_id_t id; 441 442 if (jailed(td->td_ucred)) 443 return (ENOSYS); 444 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 445 if (error) 446 return (error); 447 448 error = copyin(uap->auid, &id, sizeof(id)); 449 if (error) 450 return (error); 451 452 audit_arg_auid(id); 453 454 /* 455 * XXX: Integer write on static pointer dereference: doesn't need 456 * locking? 457 * 458 * XXXAUDIT: Might need locking to serialize audit events in the same 459 * order as change events? Or maybe that's an under-solveable 460 * problem. 461 * 462 * XXXRW: Test privilege while holding the proc lock? 463 */ 464 PROC_LOCK(td->td_proc); 465 td->td_proc->p_au->ai_auid = id; 466 PROC_UNLOCK(td->td_proc); 467 468 return (0); 469} 470 471/* 472 * System calls to get and set process audit information. 473 */ 474/* ARGSUSED */ 475int 476getaudit(struct thread *td, struct getaudit_args *uap) 477{ 478 struct auditinfo ai; 479 int error; 480 481 if (jailed(td->td_ucred)) 482 return (ENOSYS); 483 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 484 if (error) 485 return (error); 486 487 PROC_LOCK(td->td_proc); 488 if (td->td_proc->p_au->ai_termid.at_type == AU_IPv6) { 489 PROC_UNLOCK(td->td_proc); 490 return (E2BIG); 491 } 492 bzero(&ai, sizeof(ai)); 493 ai.ai_auid = td->td_proc->p_au->ai_auid; 494 ai.ai_mask = td->td_proc->p_au->ai_mask; 495 ai.ai_asid = td->td_proc->p_au->ai_asid; 496 ai.ai_termid.machine = td->td_proc->p_au->ai_termid.at_addr[0]; 497 ai.ai_termid.port = td->td_proc->p_au->ai_termid.at_port; 498 PROC_UNLOCK(td->td_proc); 499 500 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 501} 502 503/* ARGSUSED */ 504int 505setaudit(struct thread *td, struct setaudit_args *uap) 506{ 507 struct auditinfo ai; 508 int error; 509 510 if (jailed(td->td_ucred)) 511 return (ENOSYS); 512 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 513 if (error) 514 return (error); 515 516 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 517 if (error) 518 return (error); 519 520 audit_arg_auditinfo(&ai); 521 522 /* 523 * XXXRW: Test privilege while holding the proc lock? 524 */ 525 PROC_LOCK(td->td_proc); 526 bzero(td->td_proc->p_au, sizeof(struct auditinfo_addr)); 527 td->td_proc->p_au->ai_auid = ai.ai_auid; 528 td->td_proc->p_au->ai_mask = ai.ai_mask; 529 td->td_proc->p_au->ai_asid = ai.ai_asid; 530 td->td_proc->p_au->ai_termid.at_addr[0] = ai.ai_termid.machine; 531 td->td_proc->p_au->ai_termid.at_port = ai.ai_termid.port; 532 td->td_proc->p_au->ai_termid.at_type = AU_IPv4; 533 PROC_UNLOCK(td->td_proc); 534 535 return (0); 536} 537 538/* ARGSUSED */ 539int 540getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 541{ 542 struct auditinfo_addr aia; 543 int error; 544 545 if (jailed(td->td_ucred)) 546 return (ENOSYS); 547 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 548 if (error) 549 return (error); 550 if (uap->length < sizeof(aia)) 551 return (EOVERFLOW); 552 PROC_LOCK(td->td_proc); 553 aia = *td->td_proc->p_au; 554 PROC_UNLOCK(td->td_proc); 555 return (copyout(&aia, uap->auditinfo_addr, sizeof(aia))); 556} 557 558/* ARGSUSED */ 559int 560setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 561{ 562 struct auditinfo_addr aia; 563 int error; 564 565 if (jailed(td->td_ucred)) 566 return (ENOSYS); 567 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 568 if (error) 569 return (error); 570 571 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 572 if (error) 573 return (error); 574 PROC_LOCK(td->td_proc); 575 *td->td_proc->p_au = aia; 576 PROC_UNLOCK(td->td_proc); 577 return (error); 578} 579 580/* 581 * Syscall to manage audit files. 582 */ 583/* ARGSUSED */ 584int 585auditctl(struct thread *td, struct auditctl_args *uap) 586{ 587 struct nameidata nd; 588 struct ucred *cred; 589 struct vnode *vp; 590 int error = 0; 591 int flags, vfslocked; 592 593 if (jailed(td->td_ucred)) 594 return (ENOSYS); 595 error = priv_check(td, PRIV_AUDIT_CONTROL); 596 if (error) 597 return (error); 598 599 vp = NULL; 600 cred = NULL; 601 602 /* 603 * If a path is specified, open the replacement vnode, perform 604 * validity checks, and grab another reference to the current 605 * credential. 606 * 607 * On Darwin, a NULL path argument is also used to disable audit. 608 */ 609 if (uap->path == NULL) 610 return (EINVAL); 611 612 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 613 UIO_USERSPACE, uap->path, td); 614 flags = AUDIT_OPEN_FLAGS; 615 error = vn_open(&nd, &flags, 0, -1); 616 if (error) 617 return (error); 618 vfslocked = NDHASGIANT(&nd); 619 vp = nd.ni_vp; 620 VOP_UNLOCK(vp, 0, td); 621 NDFREE(&nd, NDF_ONLY_PNBUF); 622 if (vp->v_type != VREG) { 623 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 624 VFS_UNLOCK_GIANT(vfslocked); 625 return (EINVAL); 626 } 627 VFS_UNLOCK_GIANT(vfslocked); 628 cred = td->td_ucred; 629 crhold(cred); 630 631 /* 632 * XXXAUDIT: Should audit_suspended actually be cleared by 633 * audit_worker? 634 */ 635 audit_suspended = 0; 636 637 audit_rotate_vnode(cred, vp); 638 639 return (error); 640} 641 642#else /* !AUDIT */ 643 644int 645audit(struct thread *td, struct audit_args *uap) 646{ 647 648 return (ENOSYS); 649} 650 651int 652auditon(struct thread *td, struct auditon_args *uap) 653{ 654 655 return (ENOSYS); 656} 657 658int 659getauid(struct thread *td, struct getauid_args *uap) 660{ 661 662 return (ENOSYS); 663} 664 665int 666setauid(struct thread *td, struct setauid_args *uap) 667{ 668 669 return (ENOSYS); 670} 671 672int 673getaudit(struct thread *td, struct getaudit_args *uap) 674{ 675 676 return (ENOSYS); 677} 678 679int 680setaudit(struct thread *td, struct setaudit_args *uap) 681{ 682 683 return (ENOSYS); 684} 685 686int 687getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 688{ 689 690 return (ENOSYS); 691} 692 693int 694setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 695{ 696 697 return (ENOSYS); 698} 699 700int 701auditctl(struct thread *td, struct auditctl_args *uap) 702{ 703 704 return (ENOSYS); 705} 706 707void 708audit_proc_init(struct proc *p) 709{ 710 711} 712 713void 714audit_proc_fork(struct proc *parent, struct proc *child) 715{ 716 717} 718 719void 720audit_proc_free(struct proc *p) 721{ 722 723} 724 725#endif /* AUDIT */ 726