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