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 */ 70int 71sys_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 150free_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 */ 163int 164sys_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 */ 593int 594sys_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 */ 608int 609sys_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); 638fail: 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 */ 648int 649sys_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 */ 673int 674sys_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); 709fail: 710 PROC_UNLOCK(td->td_proc); 711 crfree(newcred); 712 return (error); 713} 714 715/* ARGSUSED */ 716int 717sys_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 */ 733int 734sys_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); 766fail: 767 PROC_UNLOCK(td->td_proc); 768 crfree(newcred); 769 return (error); 770} 771 772/* 773 * Syscall to manage audit files. 774 */ 775/* ARGSUSED */ 776int 777sys_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, 805 UIO_USERSPACE, uap->path, td); 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(&nd, NDF_ONLY_PNBUF); 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 843int 844sys_audit(struct thread *td, struct audit_args *uap) 845{ 846 847 return (ENOSYS); 848} 849 850int 851sys_auditon(struct thread *td, struct auditon_args *uap) 852{ 853 854 return (ENOSYS); 855} 856 857int 858sys_getauid(struct thread *td, struct getauid_args *uap) 859{ 860 861 return (ENOSYS); 862} 863 864int 865sys_setauid(struct thread *td, struct setauid_args *uap) 866{ 867 868 return (ENOSYS); 869} 870 871int 872sys_getaudit(struct thread *td, struct getaudit_args *uap) 873{ 874 875 return (ENOSYS); 876} 877 878int 879sys_setaudit(struct thread *td, struct setaudit_args *uap) 880{ 881 882 return (ENOSYS); 883} 884 885int 886sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 887{ 888 889 return (ENOSYS); 890} 891 892int 893sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 894{ 895 896 return (ENOSYS); 897} 898 899int 900sys_auditctl(struct thread *td, struct auditctl_args *uap) 901{ 902 903 return (ENOSYS); 904} 905#endif /* AUDIT */ 906