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