audit_syscalls.c revision 165624
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 165624 2006-12-29 10:49:13Z rwatson $ 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 */ 61int 62audit(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 135free_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 */ 150int 151auditon(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 * XXX Need to implement these commands by accessing the global 197 * values associated with the commands. 198 * 199 * XXXAUDIT: Locking? 200 */ 201 switch (uap->cmd) { 202 case A_GETPOLICY: 203 if (!audit_fail_stop) 204 udata.au_policy |= AUDIT_CNT; 205 if (audit_panic_on_write_fail) 206 udata.au_policy |= AUDIT_AHLT; 207 if (audit_argv) 208 udata.au_policy |= AUDIT_ARGV; 209 if (audit_arge) 210 udata.au_policy |= AUDIT_ARGE; 211 break; 212 213 case A_SETPOLICY: 214 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 215 AUDIT_ARGE)) 216 return (EINVAL); 217 /* 218 * XXX - Need to wake up waiters if the policy relaxes? 219 */ 220 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 221 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 222 audit_argv = (udata.au_policy & AUDIT_ARGV); 223 audit_arge = (udata.au_policy & AUDIT_ARGE); 224 break; 225 226 case A_GETKMASK: 227 udata.au_mask = audit_nae_mask; 228 break; 229 230 case A_SETKMASK: 231 audit_nae_mask = udata.au_mask; 232 break; 233 234 case A_GETQCTRL: 235 udata.au_qctrl = audit_qctrl; 236 break; 237 238 case A_SETQCTRL: 239 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 240 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 241 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 242 (udata.au_qctrl.aq_minfree < 0) || 243 (udata.au_qctrl.aq_minfree > 100)) 244 return (EINVAL); 245 246 audit_qctrl = udata.au_qctrl; 247 /* XXX The queue delay value isn't used with the kernel. */ 248 audit_qctrl.aq_delay = -1; 249 break; 250 251 case A_GETCWD: 252 return (ENOSYS); 253 break; 254 255 case A_GETCAR: 256 return (ENOSYS); 257 break; 258 259 case A_GETSTAT: 260 return (ENOSYS); 261 break; 262 263 case A_SETSTAT: 264 return (ENOSYS); 265 break; 266 267 case A_SETUMASK: 268 return (ENOSYS); 269 break; 270 271 case A_SETSMASK: 272 return (ENOSYS); 273 break; 274 275 case A_GETCOND: 276 if (audit_enabled && !audit_suspended) 277 udata.au_cond = AUC_AUDITING; 278 else 279 udata.au_cond = AUC_NOAUDIT; 280 break; 281 282 case A_SETCOND: 283 if (udata.au_cond == AUC_NOAUDIT) 284 audit_suspended = 1; 285 if (udata.au_cond == AUC_AUDITING) 286 audit_suspended = 0; 287 if (udata.au_cond == AUC_DISABLED) { 288 audit_suspended = 1; 289 audit_shutdown(NULL, 0); 290 } 291 break; 292 293 case A_GETCLASS: 294 udata.au_evclass.ec_class = au_event_class( 295 udata.au_evclass.ec_number); 296 break; 297 298 case A_SETCLASS: 299 au_evclassmap_insert(udata.au_evclass.ec_number, 300 udata.au_evclass.ec_class); 301 break; 302 303 case A_GETPINFO: 304 if (udata.au_aupinfo.ap_pid < 1) 305 return (EINVAL); 306 307 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 308 return (EINVAL); 309 if (p_cansee(td, tp) != 0) { 310 PROC_UNLOCK(tp); 311 return (EINVAL); 312 } 313 314 udata.au_aupinfo.ap_auid = tp->p_au->ai_auid; 315 udata.au_aupinfo.ap_mask.am_success = 316 tp->p_au->ai_mask.am_success; 317 udata.au_aupinfo.ap_mask.am_failure = 318 tp->p_au->ai_mask.am_failure; 319 udata.au_aupinfo.ap_termid.machine = 320 tp->p_au->ai_termid.machine; 321 udata.au_aupinfo.ap_termid.port = tp->p_au->ai_termid.port; 322 udata.au_aupinfo.ap_asid = tp->p_au->ai_asid; 323 PROC_UNLOCK(tp); 324 break; 325 326 case A_SETPMASK: 327 if (udata.au_aupinfo.ap_pid < 1) 328 return (EINVAL); 329 330 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 331 return (EINVAL); 332 if (p_cansee(td, tp) != 0) { 333 PROC_UNLOCK(tp); 334 return (EINVAL); 335 } 336 337 tp->p_au->ai_mask.am_success = 338 udata.au_aupinfo.ap_mask.am_success; 339 tp->p_au->ai_mask.am_failure = 340 udata.au_aupinfo.ap_mask.am_failure; 341 PROC_UNLOCK(tp); 342 break; 343 344 case A_SETFSIZE: 345 if ((udata.au_fstat.af_filesz != 0) && 346 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 347 return (EINVAL); 348 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 349 break; 350 351 case A_GETFSIZE: 352 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 353 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 354 break; 355 356 case A_GETPINFO_ADDR: 357 return (ENOSYS); 358 break; 359 360 case A_GETKAUDIT: 361 return (ENOSYS); 362 break; 363 364 case A_SETKAUDIT: 365 return (ENOSYS); 366 break; 367 368 case A_SENDTRIGGER: 369 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 370 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 371 return (EINVAL); 372 return (send_trigger(udata.au_trigger)); 373 } 374 375 /* 376 * Copy data back to userspace for the GET comands. 377 */ 378 switch (uap->cmd) { 379 case A_GETPOLICY: 380 case A_GETKMASK: 381 case A_GETQCTRL: 382 case A_GETCWD: 383 case A_GETCAR: 384 case A_GETSTAT: 385 case A_GETCOND: 386 case A_GETCLASS: 387 case A_GETPINFO: 388 case A_GETFSIZE: 389 case A_GETPINFO_ADDR: 390 case A_GETKAUDIT: 391 error = copyout((void *)&udata, uap->data, uap->length); 392 if (error) 393 return (error); 394 break; 395 } 396 397 return (0); 398} 399 400/* 401 * MPSAFE 402 * 403 * System calls to manage the user audit information. 404 */ 405/* ARGSUSED */ 406int 407getauid(struct thread *td, struct getauid_args *uap) 408{ 409 int error; 410 au_id_t id; 411 412 if (jailed(td->td_ucred)) 413 return (ENOSYS); 414 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 415 if (error) 416 return (error); 417 418 /* 419 * XXX: Integer read on static pointer dereference: doesn't need 420 * locking? 421 */ 422 PROC_LOCK(td->td_proc); 423 id = td->td_proc->p_au->ai_auid; 424 PROC_UNLOCK(td->td_proc); 425 return copyout(&id, uap->auid, sizeof(id)); 426} 427 428/* MPSAFE */ 429/* ARGSUSED */ 430int 431setauid(struct thread *td, struct setauid_args *uap) 432{ 433 int error; 434 au_id_t id; 435 436 if (jailed(td->td_ucred)) 437 return (ENOSYS); 438 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 439 if (error) 440 return (error); 441 442 error = copyin(uap->auid, &id, sizeof(id)); 443 if (error) 444 return (error); 445 446 audit_arg_auid(id); 447 448 /* 449 * XXX: Integer write on static pointer dereference: doesn't need 450 * locking? 451 * 452 * XXXAUDIT: Might need locking to serialize audit events in the same 453 * order as change events? Or maybe that's an under-solveable 454 * problem. 455 * 456 * XXXRW: Test privilege while holding the proc lock? 457 */ 458 PROC_LOCK(td->td_proc); 459 td->td_proc->p_au->ai_auid = id; 460 PROC_UNLOCK(td->td_proc); 461 462 return (0); 463} 464 465/* 466 * MPSAFE 467 * System calls to get and set process audit information. 468 */ 469/* ARGSUSED */ 470int 471getaudit(struct thread *td, struct getaudit_args *uap) 472{ 473 struct auditinfo ai; 474 int error; 475 476 if (jailed(td->td_ucred)) 477 return (ENOSYS); 478 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 479 if (error) 480 return (error); 481 482 PROC_LOCK(td->td_proc); 483 ai = *td->td_proc->p_au; 484 PROC_UNLOCK(td->td_proc); 485 486 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 487} 488 489/* MPSAFE */ 490/* ARGSUSED */ 491int 492setaudit(struct thread *td, struct setaudit_args *uap) 493{ 494 struct auditinfo ai; 495 int error; 496 497 if (jailed(td->td_ucred)) 498 return (ENOSYS); 499 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 500 if (error) 501 return (error); 502 503 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 504 if (error) 505 return (error); 506 507 audit_arg_auditinfo(&ai); 508 509 /* 510 * XXXRW: Test privilege while holding the proc lock? 511 */ 512 PROC_LOCK(td->td_proc); 513 *td->td_proc->p_au = ai; 514 PROC_UNLOCK(td->td_proc); 515 516 return (0); 517} 518 519/* MPSAFE */ 520/* ARGSUSED */ 521int 522getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 523{ 524 int error; 525 526 if (jailed(td->td_ucred)) 527 return (ENOSYS); 528 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 529 if (error) 530 return (error); 531 return (ENOSYS); 532} 533 534/* MPSAFE */ 535/* ARGSUSED */ 536int 537setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 538{ 539 int error; 540 541 if (jailed(td->td_ucred)) 542 return (ENOSYS); 543 error = priv_check(td, PRIV_AUDIT_SETAUDIT); 544 if (error) 545 return (error); 546 return (ENOSYS); 547} 548 549/* 550 * MPSAFE 551 * Syscall to manage audit files. 552 * 553 * XXX: Should generate an audit event. 554 */ 555/* ARGSUSED */ 556int 557auditctl(struct thread *td, struct auditctl_args *uap) 558{ 559 struct nameidata nd; 560 struct ucred *cred; 561 struct vnode *vp; 562 int error = 0; 563 int flags, vfslocked; 564 565 if (jailed(td->td_ucred)) 566 return (ENOSYS); 567 error = priv_check(td, PRIV_AUDIT_CONTROL); 568 if (error) 569 return (error); 570 571 vp = NULL; 572 cred = NULL; 573 574 /* 575 * If a path is specified, open the replacement vnode, perform 576 * validity checks, and grab another reference to the current 577 * credential. 578 * 579 * On Darwin, a NULL path argument is also used to disable audit. 580 */ 581 if (uap->path == NULL) 582 return (EINVAL); 583 584 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 585 UIO_USERSPACE, uap->path, td); 586 flags = AUDIT_OPEN_FLAGS; 587 error = vn_open(&nd, &flags, 0, -1); 588 if (error) 589 return (error); 590 vfslocked = NDHASGIANT(&nd); 591 vp = nd.ni_vp; 592 VOP_UNLOCK(vp, 0, td); 593 NDFREE(&nd, NDF_ONLY_PNBUF); 594 if (vp->v_type != VREG) { 595 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 596 VFS_UNLOCK_GIANT(vfslocked); 597 return (EINVAL); 598 } 599 VFS_UNLOCK_GIANT(vfslocked); 600 cred = td->td_ucred; 601 crhold(cred); 602 603 /* 604 * XXXAUDIT: Should audit_suspended actually be cleared by 605 * audit_worker? 606 */ 607 audit_suspended = 0; 608 609 audit_rotate_vnode(cred, vp); 610 611 return (error); 612} 613 614#else /* !AUDIT */ 615 616int 617audit(struct thread *td, struct audit_args *uap) 618{ 619 620 return (ENOSYS); 621} 622 623int 624auditon(struct thread *td, struct auditon_args *uap) 625{ 626 627 return (ENOSYS); 628} 629 630int 631getauid(struct thread *td, struct getauid_args *uap) 632{ 633 634 return (ENOSYS); 635} 636 637int 638setauid(struct thread *td, struct setauid_args *uap) 639{ 640 641 return (ENOSYS); 642} 643 644int 645getaudit(struct thread *td, struct getaudit_args *uap) 646{ 647 648 return (ENOSYS); 649} 650 651int 652setaudit(struct thread *td, struct setaudit_args *uap) 653{ 654 655 return (ENOSYS); 656} 657 658int 659getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 660{ 661 662 return (ENOSYS); 663} 664 665int 666setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 667{ 668 669 return (ENOSYS); 670} 671 672int 673auditctl(struct thread *td, struct auditctl_args *uap) 674{ 675 676 return (ENOSYS); 677} 678 679void 680audit_proc_init(struct proc *p) 681{ 682 683} 684 685void 686audit_proc_fork(struct proc *parent, struct proc *child) 687{ 688 689} 690 691void 692audit_proc_free(struct proc *p) 693{ 694 695} 696 697#endif /* AUDIT */ 698