1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1999-2009 Apple Inc. 5 * Copyright (c) 2016, 2018 Robert N. M. Watson 6 * All rights reserved. 7 * 8 * Portions of this software were developed by BAE Systems, the University of 9 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 10 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 11 * Computing (TC) research program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 22 * its contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/mount.h> 40 #include <sys/namei.h> 41 #include <sys/priv.h> 42 #include <sys/proc.h> 43 #include <sys/sysproto.h> 44 #include <sys/systm.h> 45 #include <sys/vnode.h> 46 #include <sys/jail.h> 47 48 #include <bsm/audit.h> 49 #include <bsm/audit_kevents.h> 50 51 #include <security/audit/audit.h> 52 #include <security/audit/audit_private.h> 53 #include <security/mac/mac_framework.h> 54 55 #ifdef AUDIT 56 57 static int 58 audit_priv_check_cred(struct ucred *cred, int priv) 59 { 60 int error; 61 62 error = priv_check_cred(cred, priv); 63 if (error == EPERM && jailed(cred)) { 64 /* 65 * The audit system calls historically returned ENOSYS when 66 * invoked from within a jail, and some userspace applications 67 * handle that case specially. Thus, convert the error here. 68 */ 69 error = ENOSYS; 70 } 71 return (error); 72 } 73 74 static int 75 audit_priv_check(struct thread *td, int priv) 76 { 77 return (audit_priv_check_cred(td->td_ucred, priv)); 78 } 79 80 /* 81 * System call to allow a user space application to submit a BSM audit record 82 * to the kernel for inclusion in the audit log. This function does little 83 * verification on the audit record that is submitted. 84 * 85 * XXXAUDIT: Audit preselection for user records does not currently work, 86 * since we pre-select only based on the AUE_audit event type, not the event 87 * type submitted as part of the user audit data. 88 */ 89 /* ARGSUSED */ 90 int 91 sys_audit(struct thread *td, struct audit_args *uap) 92 { 93 int error; 94 void * rec; 95 struct kaudit_record *ar; 96 97 if (jailed(td->td_ucred)) 98 return (ENOSYS); 99 error = priv_check(td, PRIV_AUDIT_SUBMIT); 100 if (error) 101 return (error); 102 103 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) 104 return (EINVAL); 105 106 ar = currecord(); 107 108 /* 109 * If there's no current audit record (audit() itself not audited) 110 * commit the user audit record. 111 */ 112 if (ar == NULL) { 113 /* 114 * This is not very efficient; we're required to allocate a 115 * complete kernel audit record just so the user record can 116 * tag along. 117 * 118 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and 119 * special pre-select handling? 120 */ 121 td->td_ar = audit_new(AUE_NULL, td); 122 if (td->td_ar == NULL) 123 return (ENOTSUP); 124 td->td_pflags |= TDP_AUDITREC; 125 ar = td->td_ar; 126 } 127 128 if (uap->length > MAX_AUDIT_RECORD_SIZE) 129 return (EINVAL); 130 131 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 132 133 error = copyin(uap->record, rec, uap->length); 134 if (error) 135 goto free_out; 136 137 /* Verify the record. */ 138 if (bsm_rec_verify(rec) == 0) { 139 error = EINVAL; 140 goto free_out; 141 } 142 143 #ifdef MAC 144 error = mac_system_check_audit(td->td_ucred, rec, uap->length); 145 if (error) 146 goto free_out; 147 #endif 148 149 /* 150 * Attach the user audit record to the kernel audit record. Because 151 * this system call is an auditable event, we will write the user 152 * record along with the record for this audit event. 153 * 154 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 155 * k_ar_commit & AR_COMMIT_USER? 156 */ 157 ar->k_udata = rec; 158 ar->k_ulen = uap->length; 159 ar->k_ar_commit |= AR_COMMIT_USER; 160 161 /* 162 * Currently we assume that all preselection has been performed in 163 * userspace. We unconditionally set these masks so that the records 164 * get committed both to the trail and pipe. In the future we will 165 * want to setup kernel based preselection. 166 */ 167 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 168 return (0); 169 170 free_out: 171 /* 172 * audit_syscall_exit() will free the audit record on the thread even 173 * if we allocated it above. 174 */ 175 free(rec, M_AUDITDATA); 176 return (error); 177 } 178 179 /* 180 * System call to manipulate auditing. 181 */ 182 /* ARGSUSED */ 183 int 184 sys_auditon(struct thread *td, struct auditon_args *uap) 185 { 186 struct ucred *cred, *newcred, *oldcred; 187 int error; 188 union auditon_udata udata; 189 struct proc *tp; 190 191 if (jailed(td->td_ucred)) 192 return (ENOSYS); 193 AUDIT_ARG_CMD(uap->cmd); 194 195 #ifdef MAC 196 error = mac_system_check_auditon(td->td_ucred, uap->cmd); 197 if (error) 198 return (error); 199 #endif 200 201 error = priv_check(td, PRIV_AUDIT_CONTROL); 202 if (error) 203 return (error); 204 205 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) 206 return (EINVAL); 207 208 memset((void *)&udata, 0, sizeof(udata)); 209 210 /* 211 * Some of the GET commands use the arguments too. 212 */ 213 switch (uap->cmd) { 214 case A_SETPOLICY: 215 case A_OLDSETPOLICY: 216 case A_SETKMASK: 217 case A_SETQCTRL: 218 case A_OLDSETQCTRL: 219 case A_SETSTAT: 220 case A_SETUMASK: 221 case A_SETSMASK: 222 case A_SETCOND: 223 case A_OLDSETCOND: 224 case A_SETCLASS: 225 case A_SETEVENT: 226 case A_SETPMASK: 227 case A_SETFSIZE: 228 case A_SETKAUDIT: 229 case A_GETCLASS: 230 case A_GETEVENT: 231 case A_GETPINFO: 232 case A_GETPINFO_ADDR: 233 case A_SENDTRIGGER: 234 error = copyin(uap->data, (void *)&udata, uap->length); 235 if (error) 236 return (error); 237 AUDIT_ARG_AUDITON(&udata); 238 break; 239 } 240 241 /* 242 * XXXAUDIT: Locking? 243 */ 244 switch (uap->cmd) { 245 case A_OLDGETPOLICY: 246 case A_GETPOLICY: 247 if (uap->length == sizeof(udata.au_policy64)) { 248 if (!audit_fail_stop) 249 udata.au_policy64 |= AUDIT_CNT; 250 if (audit_panic_on_write_fail) 251 udata.au_policy64 |= AUDIT_AHLT; 252 if (audit_argv) 253 udata.au_policy64 |= AUDIT_ARGV; 254 if (audit_arge) 255 udata.au_policy64 |= AUDIT_ARGE; 256 break; 257 } 258 if (uap->length != sizeof(udata.au_policy)) 259 return (EINVAL); 260 if (!audit_fail_stop) 261 udata.au_policy |= AUDIT_CNT; 262 if (audit_panic_on_write_fail) 263 udata.au_policy |= AUDIT_AHLT; 264 if (audit_argv) 265 udata.au_policy |= AUDIT_ARGV; 266 if (audit_arge) 267 udata.au_policy |= AUDIT_ARGE; 268 break; 269 270 case A_OLDSETPOLICY: 271 case A_SETPOLICY: 272 if (uap->length == sizeof(udata.au_policy64)) { 273 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT| 274 AUDIT_ARGV|AUDIT_ARGE)) 275 return (EINVAL); 276 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == 277 0); 278 audit_panic_on_write_fail = (udata.au_policy64 & 279 AUDIT_AHLT); 280 audit_argv = (udata.au_policy64 & AUDIT_ARGV); 281 audit_arge = (udata.au_policy64 & AUDIT_ARGE); 282 break; 283 } 284 if (uap->length != sizeof(udata.au_policy)) 285 return (EINVAL); 286 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 287 AUDIT_ARGE)) 288 return (EINVAL); 289 /* 290 * XXX - Need to wake up waiters if the policy relaxes? 291 */ 292 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 293 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 294 audit_argv = (udata.au_policy & AUDIT_ARGV); 295 audit_arge = (udata.au_policy & AUDIT_ARGE); 296 break; 297 298 case A_GETKMASK: 299 if (uap->length != sizeof(udata.au_mask)) 300 return (EINVAL); 301 udata.au_mask = audit_nae_mask; 302 break; 303 304 case A_SETKMASK: 305 if (uap->length != sizeof(udata.au_mask)) 306 return (EINVAL); 307 audit_nae_mask = udata.au_mask; 308 break; 309 310 case A_OLDGETQCTRL: 311 case A_GETQCTRL: 312 if (uap->length == sizeof(udata.au_qctrl64)) { 313 udata.au_qctrl64.aq64_hiwater = 314 (u_int64_t)audit_qctrl.aq_hiwater; 315 udata.au_qctrl64.aq64_lowater = 316 (u_int64_t)audit_qctrl.aq_lowater; 317 udata.au_qctrl64.aq64_bufsz = 318 (u_int64_t)audit_qctrl.aq_bufsz; 319 udata.au_qctrl64.aq64_minfree = 320 (u_int64_t)audit_qctrl.aq_minfree; 321 break; 322 } 323 if (uap->length != sizeof(udata.au_qctrl)) 324 return (EINVAL); 325 udata.au_qctrl = audit_qctrl; 326 break; 327 328 case A_OLDSETQCTRL: 329 case A_SETQCTRL: 330 if (uap->length == sizeof(udata.au_qctrl64)) { 331 /* NB: aq64_minfree is unsigned unlike aq_minfree. */ 332 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || 333 (udata.au_qctrl64.aq64_lowater >= 334 udata.au_qctrl.aq_hiwater) || 335 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || 336 (udata.au_qctrl64.aq64_minfree > 100)) 337 return (EINVAL); 338 audit_qctrl.aq_hiwater = 339 (int)udata.au_qctrl64.aq64_hiwater; 340 audit_qctrl.aq_lowater = 341 (int)udata.au_qctrl64.aq64_lowater; 342 audit_qctrl.aq_bufsz = 343 (int)udata.au_qctrl64.aq64_bufsz; 344 audit_qctrl.aq_minfree = 345 (int)udata.au_qctrl64.aq64_minfree; 346 audit_qctrl.aq_delay = -1; /* Not used. */ 347 break; 348 } 349 if (uap->length != sizeof(udata.au_qctrl)) 350 return (EINVAL); 351 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 352 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 353 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 354 (udata.au_qctrl.aq_minfree < 0) || 355 (udata.au_qctrl.aq_minfree > 100)) 356 return (EINVAL); 357 358 audit_qctrl = udata.au_qctrl; 359 /* XXX The queue delay value isn't used with the kernel. */ 360 audit_qctrl.aq_delay = -1; 361 break; 362 363 case A_GETCWD: 364 return (ENOSYS); 365 break; 366 367 case A_GETCAR: 368 return (ENOSYS); 369 break; 370 371 case A_GETSTAT: 372 return (ENOSYS); 373 break; 374 375 case A_SETSTAT: 376 return (ENOSYS); 377 break; 378 379 case A_SETUMASK: 380 return (ENOSYS); 381 break; 382 383 case A_SETSMASK: 384 return (ENOSYS); 385 break; 386 387 case A_OLDGETCOND: 388 case A_GETCOND: 389 if (uap->length == sizeof(udata.au_cond64)) { 390 if (audit_trail_enabled && !audit_trail_suspended) 391 udata.au_cond64 = AUC_AUDITING; 392 else 393 udata.au_cond64 = AUC_NOAUDIT; 394 break; 395 } 396 if (uap->length != sizeof(udata.au_cond)) 397 return (EINVAL); 398 if (audit_trail_enabled && !audit_trail_suspended) 399 udata.au_cond = AUC_AUDITING; 400 else 401 udata.au_cond = AUC_NOAUDIT; 402 break; 403 404 case A_OLDSETCOND: 405 case A_SETCOND: 406 if (uap->length == sizeof(udata.au_cond64)) { 407 if (udata.au_cond64 == AUC_NOAUDIT) 408 audit_trail_suspended = 1; 409 if (udata.au_cond64 == AUC_AUDITING) 410 audit_trail_suspended = 0; 411 if (udata.au_cond64 == AUC_DISABLED) { 412 audit_trail_suspended = 1; 413 audit_shutdown(NULL, 0); 414 } 415 audit_syscalls_enabled_update(); 416 break; 417 } 418 if (uap->length != sizeof(udata.au_cond)) 419 return (EINVAL); 420 if (udata.au_cond == AUC_NOAUDIT) 421 audit_trail_suspended = 1; 422 if (udata.au_cond == AUC_AUDITING) 423 audit_trail_suspended = 0; 424 if (udata.au_cond == AUC_DISABLED) { 425 audit_trail_suspended = 1; 426 audit_shutdown(NULL, 0); 427 } 428 audit_syscalls_enabled_update(); 429 break; 430 431 case A_GETCLASS: 432 if (uap->length != sizeof(udata.au_evclass)) 433 return (EINVAL); 434 udata.au_evclass.ec_class = au_event_class( 435 udata.au_evclass.ec_number); 436 break; 437 438 case A_GETEVENT: 439 if (uap->length != sizeof(udata.au_evname)) 440 return (EINVAL); 441 error = au_event_name(udata.au_evname.en_number, 442 udata.au_evname.en_name); 443 if (error != 0) 444 return (error); 445 break; 446 447 case A_SETCLASS: 448 if (uap->length != sizeof(udata.au_evclass)) 449 return (EINVAL); 450 au_evclassmap_insert(udata.au_evclass.ec_number, 451 udata.au_evclass.ec_class); 452 break; 453 454 case A_SETEVENT: 455 if (uap->length != sizeof(udata.au_evname)) 456 return (EINVAL); 457 458 /* Ensure nul termination from userspace. */ 459 udata.au_evname.en_name[sizeof(udata.au_evname.en_name) - 1] 460 = 0; 461 au_evnamemap_insert(udata.au_evname.en_number, 462 udata.au_evname.en_name); 463 break; 464 465 case A_GETPINFO: 466 if (uap->length != sizeof(udata.au_aupinfo)) 467 return (EINVAL); 468 if (udata.au_aupinfo.ap_pid < 1) 469 return (ESRCH); 470 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 471 return (ESRCH); 472 if ((error = p_cansee(td, tp)) != 0) { 473 PROC_UNLOCK(tp); 474 return (error); 475 } 476 cred = tp->p_ucred; 477 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) { 478 PROC_UNLOCK(tp); 479 return (EINVAL); 480 } 481 udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid; 482 udata.au_aupinfo.ap_mask.am_success = 483 cred->cr_audit.ai_mask.am_success; 484 udata.au_aupinfo.ap_mask.am_failure = 485 cred->cr_audit.ai_mask.am_failure; 486 udata.au_aupinfo.ap_termid.machine = 487 cred->cr_audit.ai_termid.at_addr[0]; 488 udata.au_aupinfo.ap_termid.port = 489 (dev_t)cred->cr_audit.ai_termid.at_port; 490 udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid; 491 PROC_UNLOCK(tp); 492 break; 493 494 case A_SETPMASK: 495 if (uap->length != sizeof(udata.au_aupinfo)) 496 return (EINVAL); 497 if (udata.au_aupinfo.ap_pid < 1) 498 return (ESRCH); 499 newcred = crget(); 500 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { 501 crfree(newcred); 502 return (ESRCH); 503 } 504 if ((error = p_cansee(td, tp)) != 0) { 505 PROC_UNLOCK(tp); 506 crfree(newcred); 507 return (error); 508 } 509 oldcred = tp->p_ucred; 510 crcopy(newcred, oldcred); 511 newcred->cr_audit.ai_mask.am_success = 512 udata.au_aupinfo.ap_mask.am_success; 513 newcred->cr_audit.ai_mask.am_failure = 514 udata.au_aupinfo.ap_mask.am_failure; 515 proc_set_cred(tp, newcred); 516 PROC_UNLOCK(tp); 517 crfree(oldcred); 518 break; 519 520 case A_SETFSIZE: 521 if (uap->length != sizeof(udata.au_fstat)) 522 return (EINVAL); 523 if ((udata.au_fstat.af_filesz != 0) && 524 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 525 return (EINVAL); 526 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 527 break; 528 529 case A_GETFSIZE: 530 if (uap->length != sizeof(udata.au_fstat)) 531 return (EINVAL); 532 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 533 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 534 break; 535 536 case A_GETPINFO_ADDR: 537 if (uap->length != sizeof(udata.au_aupinfo_addr)) 538 return (EINVAL); 539 if (udata.au_aupinfo_addr.ap_pid < 1) 540 return (ESRCH); 541 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 542 return (ESRCH); 543 cred = tp->p_ucred; 544 udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid; 545 udata.au_aupinfo_addr.ap_mask.am_success = 546 cred->cr_audit.ai_mask.am_success; 547 udata.au_aupinfo_addr.ap_mask.am_failure = 548 cred->cr_audit.ai_mask.am_failure; 549 udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid; 550 udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid; 551 PROC_UNLOCK(tp); 552 break; 553 554 case A_GETKAUDIT: 555 if (uap->length != sizeof(udata.au_kau_info)) 556 return (EINVAL); 557 audit_get_kinfo(&udata.au_kau_info); 558 break; 559 560 case A_SETKAUDIT: 561 if (uap->length != sizeof(udata.au_kau_info)) 562 return (EINVAL); 563 if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && 564 udata.au_kau_info.ai_termid.at_type != AU_IPv6) 565 return (EINVAL); 566 audit_set_kinfo(&udata.au_kau_info); 567 break; 568 569 case A_SENDTRIGGER: 570 if (uap->length != sizeof(udata.au_trigger)) 571 return (EINVAL); 572 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 573 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 574 return (EINVAL); 575 return (audit_send_trigger(udata.au_trigger)); 576 577 default: 578 return (EINVAL); 579 } 580 581 /* 582 * Copy data back to userspace for the GET comands. 583 */ 584 switch (uap->cmd) { 585 case A_GETPOLICY: 586 case A_OLDGETPOLICY: 587 case A_GETKMASK: 588 case A_GETQCTRL: 589 case A_OLDGETQCTRL: 590 case A_GETCWD: 591 case A_GETCAR: 592 case A_GETSTAT: 593 case A_GETCOND: 594 case A_OLDGETCOND: 595 case A_GETCLASS: 596 case A_GETPINFO: 597 case A_GETFSIZE: 598 case A_GETPINFO_ADDR: 599 case A_GETKAUDIT: 600 error = copyout((void *)&udata, uap->data, uap->length); 601 if (error) 602 return (error); 603 break; 604 } 605 606 return (0); 607 } 608 609 /* 610 * System calls to manage the user audit information. 611 */ 612 /* ARGSUSED */ 613 int 614 sys_getauid(struct thread *td, struct getauid_args *uap) 615 { 616 int error; 617 618 error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT); 619 if (error) 620 return (error); 621 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, 622 sizeof(td->td_ucred->cr_audit.ai_auid))); 623 } 624 625 /* ARGSUSED */ 626 int 627 sys_setauid(struct thread *td, struct setauid_args *uap) 628 { 629 struct ucred *newcred, *oldcred; 630 au_id_t id; 631 int error; 632 633 error = copyin(uap->auid, &id, sizeof(id)); 634 if (error) 635 return (error); 636 audit_arg_auid(id); 637 newcred = crget(); 638 PROC_LOCK(td->td_proc); 639 oldcred = td->td_proc->p_ucred; 640 crcopy(newcred, oldcred); 641 #ifdef MAC 642 error = mac_cred_check_setauid(oldcred, id); 643 if (error) 644 goto fail; 645 #endif 646 error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT); 647 if (error) 648 goto fail; 649 newcred->cr_audit.ai_auid = id; 650 proc_set_cred(td->td_proc, newcred); 651 PROC_UNLOCK(td->td_proc); 652 crfree(oldcred); 653 return (0); 654 fail: 655 PROC_UNLOCK(td->td_proc); 656 crfree(newcred); 657 return (error); 658 } 659 660 /* 661 * System calls to get and set process audit information. 662 */ 663 /* ARGSUSED */ 664 int 665 sys_getaudit(struct thread *td, struct getaudit_args *uap) 666 { 667 struct auditinfo ai; 668 struct ucred *cred; 669 int error; 670 671 cred = td->td_ucred; 672 error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT); 673 if (error) 674 return (error); 675 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) 676 return (E2BIG); 677 bzero(&ai, sizeof(ai)); 678 ai.ai_auid = cred->cr_audit.ai_auid; 679 ai.ai_mask = cred->cr_audit.ai_mask; 680 ai.ai_asid = cred->cr_audit.ai_asid; 681 ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0]; 682 ai.ai_termid.port = cred->cr_audit.ai_termid.at_port; 683 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 684 } 685 686 /* ARGSUSED */ 687 int 688 sys_setaudit(struct thread *td, struct setaudit_args *uap) 689 { 690 struct ucred *newcred, *oldcred; 691 struct auditinfo ai; 692 int error; 693 694 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 695 if (error) 696 return (error); 697 audit_arg_auditinfo(&ai); 698 newcred = crget(); 699 PROC_LOCK(td->td_proc); 700 oldcred = td->td_proc->p_ucred; 701 crcopy(newcred, oldcred); 702 #ifdef MAC 703 error = mac_cred_check_setaudit(oldcred, &ai); 704 if (error) 705 goto fail; 706 #endif 707 error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT); 708 if (error) 709 goto fail; 710 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); 711 newcred->cr_audit.ai_auid = ai.ai_auid; 712 newcred->cr_audit.ai_mask = ai.ai_mask; 713 newcred->cr_audit.ai_asid = ai.ai_asid; 714 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; 715 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; 716 newcred->cr_audit.ai_termid.at_type = AU_IPv4; 717 proc_set_cred(td->td_proc, newcred); 718 PROC_UNLOCK(td->td_proc); 719 crfree(oldcred); 720 return (0); 721 fail: 722 PROC_UNLOCK(td->td_proc); 723 crfree(newcred); 724 return (error); 725 } 726 727 /* ARGSUSED */ 728 int 729 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 730 { 731 int error; 732 733 if (uap->length < sizeof(*uap->auditinfo_addr)) 734 return (EOVERFLOW); 735 error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT); 736 if (error) 737 return (error); 738 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, 739 sizeof(*uap->auditinfo_addr))); 740 } 741 742 /* ARGSUSED */ 743 int 744 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 745 { 746 struct ucred *newcred, *oldcred; 747 struct auditinfo_addr aia; 748 int error; 749 750 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 751 if (error) 752 return (error); 753 audit_arg_auditinfo_addr(&aia); 754 if (aia.ai_termid.at_type != AU_IPv6 && 755 aia.ai_termid.at_type != AU_IPv4) 756 return (EINVAL); 757 newcred = crget(); 758 PROC_LOCK(td->td_proc); 759 oldcred = td->td_proc->p_ucred; 760 crcopy(newcred, oldcred); 761 #ifdef MAC 762 error = mac_cred_check_setaudit_addr(oldcred, &aia); 763 if (error) 764 goto fail; 765 #endif 766 error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT); 767 if (error) 768 goto fail; 769 newcred->cr_audit = aia; 770 proc_set_cred(td->td_proc, newcred); 771 PROC_UNLOCK(td->td_proc); 772 crfree(oldcred); 773 return (0); 774 fail: 775 PROC_UNLOCK(td->td_proc); 776 crfree(newcred); 777 return (error); 778 } 779 780 /* 781 * Syscall to manage audit files. 782 */ 783 /* ARGSUSED */ 784 int 785 sys_auditctl(struct thread *td, struct auditctl_args *uap) 786 { 787 struct nameidata nd; 788 struct ucred *cred; 789 struct vnode *vp; 790 int error = 0; 791 int flags; 792 793 if (jailed(td->td_ucred)) 794 return (ENOSYS); 795 error = priv_check(td, PRIV_AUDIT_CONTROL); 796 if (error) 797 return (error); 798 799 vp = NULL; 800 cred = NULL; 801 802 /* 803 * If a path is specified, open the replacement vnode, perform 804 * validity checks, and grab another reference to the current 805 * credential. 806 * 807 * On Darwin, a NULL path argument is also used to disable audit. 808 */ 809 if (uap->path == NULL) 810 return (EINVAL); 811 812 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, 813 uap->path); 814 flags = AUDIT_OPEN_FLAGS; 815 error = vn_open(&nd, &flags, 0, NULL); 816 if (error) 817 return (error); 818 vp = nd.ni_vp; 819 #ifdef MAC 820 error = mac_system_check_auditctl(td->td_ucred, vp); 821 VOP_UNLOCK(vp); 822 if (error) { 823 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 824 return (error); 825 } 826 #else 827 VOP_UNLOCK(vp); 828 #endif 829 NDFREE_PNBUF(&nd); 830 if (vp->v_type != VREG) { 831 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 832 return (EINVAL); 833 } 834 cred = td->td_ucred; 835 crhold(cred); 836 837 /* 838 * XXXAUDIT: Should audit_trail_suspended actually be cleared by 839 * audit_worker? 840 */ 841 audit_trail_suspended = 0; 842 audit_syscalls_enabled_update(); 843 844 audit_rotate_vnode(cred, vp); 845 846 return (error); 847 } 848 849 #else /* !AUDIT */ 850 851 int 852 sys_audit(struct thread *td, struct audit_args *uap) 853 { 854 855 return (ENOSYS); 856 } 857 858 int 859 sys_auditon(struct thread *td, struct auditon_args *uap) 860 { 861 862 return (ENOSYS); 863 } 864 865 int 866 sys_getauid(struct thread *td, struct getauid_args *uap) 867 { 868 869 return (ENOSYS); 870 } 871 872 int 873 sys_setauid(struct thread *td, struct setauid_args *uap) 874 { 875 876 return (ENOSYS); 877 } 878 879 int 880 sys_getaudit(struct thread *td, struct getaudit_args *uap) 881 { 882 883 return (ENOSYS); 884 } 885 886 int 887 sys_setaudit(struct thread *td, struct setaudit_args *uap) 888 { 889 890 return (ENOSYS); 891 } 892 893 int 894 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 895 { 896 897 return (ENOSYS); 898 } 899 900 int 901 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 902 { 903 904 return (ENOSYS); 905 } 906 907 int 908 sys_auditctl(struct thread *td, struct auditctl_args *uap) 909 { 910 911 return (ENOSYS); 912 } 913 #endif /* AUDIT */ 914