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