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