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