1/*- 2 * Copyright (c) 1999-2010, Apple Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * NOTICE: This file was modified by McAfee Research in 2004 to introduce 31 * support for mandatory and extensible security protections. This notice 32 * is included in support of clause 2.2 (b) of the Apple Public License, 33 * Version 2.0. 34 */ 35 36#include <sys/param.h> 37#include <sys/fcntl.h> 38#include <sys/kernel.h> 39#include <sys/lock.h> 40#include <sys/namei.h> 41#include <sys/proc_internal.h> 42#include <sys/kauth.h> 43#include <sys/queue.h> 44#include <sys/systm.h> 45#include <sys/time.h> 46#include <sys/ucred.h> 47#include <sys/uio.h> 48#include <sys/unistd.h> 49#include <sys/file_internal.h> 50#include <sys/vnode_internal.h> 51#include <sys/user.h> 52#include <sys/syscall.h> 53#include <sys/malloc.h> 54#include <sys/un.h> 55#include <sys/sysent.h> 56#include <sys/sysproto.h> 57#include <sys/vfs_context.h> 58#include <sys/domain.h> 59#include <sys/protosw.h> 60#include <sys/socketvar.h> 61 62#include <bsm/audit.h> 63#include <bsm/audit_kevents.h> 64 65#include <security/audit/audit.h> 66#include <security/audit/audit_bsd.h> 67#include <security/audit/audit_private.h> 68 69#include <mach/host_priv.h> 70#include <mach/host_special_ports.h> 71#include <mach/audit_triggers_server.h> 72 73#include <kern/host.h> 74#include <kern/kalloc.h> 75#include <kern/zalloc.h> 76#include <kern/wait_queue.h> 77#include <kern/sched_prim.h> 78 79#if CONFIG_MACF 80#include <bsm/audit_record.h> 81#include <security/mac.h> 82#include <security/mac_framework.h> 83#include <security/mac_policy.h> 84#endif 85 86#include <net/route.h> 87 88#include <netinet/in.h> 89#include <netinet/in_pcb.h> 90 91#if CONFIG_AUDIT 92 93#define IS_NOT_VALID_PID(p) ((p) < 1 || (p) > PID_MAX) 94 95#ifdef AUDIT_API_WARNINGS 96/* 97 * Macro to warn about auditinfo_addr_t/auditpinfo_addr_t changing sizes 98 * to encourage the userland code to be recompiled and updated. 99 */ 100#define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \ 101 if ((size_t)(sz1) != (size_t)(sz2)) { \ 102 char pn[MAXCOMLEN + 1]; \ 103 \ 104 proc_selfname(pn, MAXCOMLEN + 1); \ 105 printf("Size of %s used by %s in %s is different from " \ 106 "kernel's. Please recompile %s.\n", (tp), \ 107 (scall), pn, pn); \ 108 } \ 109} while (0) 110 111/* 112 * Macro to warn about using ASID's outside the range [1 to PID_MAX] to 113 * encourage userland code changes. 114 */ 115#define WARN_IF_BAD_ASID(asid, scall) do { \ 116 if (((asid) < 1 || (asid) > PID_MAX) && \ 117 (asid) != AU_ASSIGN_ASID) { \ 118 char pn[MAXCOMLEN + 1]; \ 119 \ 120 proc_selfname(pn, MAXCOMLEN + 1); \ 121 printf("%s in %s is using an ASID (%u) outside the " \ 122 "range [1 to %d]. Please change %s to use an ASID "\ 123 "within this range or use AU_ASSIGN_ASID.\n", \ 124 (scall), pn, (uint32_t)(asid), PID_MAX, pn); \ 125 } \ 126} while (0) 127 128#else /* ! AUDIT_API_WARNINGS */ 129 130#define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \ 131} while (0) 132 133#define WARN_IF_BAD_ASID(asid, scall) do { \ 134} while (0) 135 136#endif /* AUDIT_API_WARNINGS */ 137 138/* 139 * System call to allow a user space application to submit a BSM audit record 140 * to the kernel for inclusion in the audit log. This function does little 141 * verification on the audit record that is submitted. 142 * 143 * XXXAUDIT: Audit preselection for user records does not currently work, 144 * since we pre-select only based on the AUE_audit event type, not the event 145 * type submitted as part of the user audit data. 146 */ 147/* ARGSUSED */ 148int 149audit(proc_t p, struct audit_args *uap, __unused int32_t *retval) 150{ 151 int error; 152 void * rec; 153 struct kaudit_record *ar; 154 struct uthread *uthr; 155 156 error = suser(kauth_cred_get(), &p->p_acflag); 157 if (error) 158 return (error); 159 160 mtx_lock(&audit_mtx); 161 if ((uap->length <= 0) || (uap->length > (int)audit_qctrl.aq_bufsz)) { 162 mtx_unlock(&audit_mtx); 163 return (EINVAL); 164 } 165 mtx_unlock(&audit_mtx); 166 167 ar = currecord(); 168 169 /* 170 * If there's no current audit record (audit() itself not audited) 171 * commit the user audit record. 172 */ 173 if (ar == NULL) { 174 uthr = curthread(); 175 if (uthr == NULL) /* can this happen? */ 176 return (ENOTSUP); 177 178 /* 179 * This is not very efficient; we're required to allocate a 180 * complete kernel audit record just so the user record can 181 * tag along. 182 */ 183 uthr->uu_ar = audit_new(AUE_NULL, p, uthr); 184 if (uthr->uu_ar == NULL) 185 return (ENOTSUP); 186 ar = uthr->uu_ar; 187 } 188 189 if (uap->length > MAX_AUDIT_RECORD_SIZE) 190 return (EINVAL); 191 192 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 193 194 error = copyin(uap->record, rec, uap->length); 195 if (error) 196 goto free_out; 197 198#if CONFIG_MACF 199 error = mac_system_check_audit(kauth_cred_get(), rec, uap->length); 200 if (error) 201 goto free_out; 202#endif 203 204 /* Verify the record. */ 205 if (bsm_rec_verify(rec) == 0) { 206 error = EINVAL; 207 goto free_out; 208 } 209 210 /* 211 * Attach the user audit record to the kernel audit record. Because 212 * this system call is an auditable event, we will write the user 213 * record along with the record for this audit event. 214 * 215 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 216 * k_ar_commit & AR_COMMIT_USER? 217 */ 218 ar->k_udata = rec; 219 ar->k_ulen = uap->length; 220 ar->k_ar_commit |= AR_COMMIT_USER; 221 222 /* 223 * Currently we assume that all preselection has been performed in 224 * userspace. We unconditionally set these masks so that the records 225 * get committed both to the trail and pipe. In the future we will 226 * want to setup kernel based preselection. 227 */ 228 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 229 return (0); 230 231free_out: 232 /* 233 * audit_syscall_exit() will free the audit record on the thread even 234 * if we allocated it above. 235 */ 236 free(rec, M_AUDITDATA); 237 return (error); 238} 239 240/* 241 * System call to manipulate auditing. 242 */ 243/* ARGSUSED */ 244int 245auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval) 246{ 247 kauth_cred_t scred; 248 int error = 0; 249 union auditon_udata udata; 250 proc_t tp = PROC_NULL; 251 struct auditinfo_addr aia; 252 253 AUDIT_ARG(cmd, uap->cmd); 254 255#if CONFIG_MACF 256 error = mac_system_check_auditon(kauth_cred_get(), uap->cmd); 257 if (error) 258 return (error); 259#endif 260 261 if ((uap->length <= 0) || (uap->length > 262 (int)sizeof(union auditon_udata))) 263 return (EINVAL); 264 265 memset((void *)&udata, 0, sizeof(udata)); 266 267 /* 268 * Some of the GET commands use the arguments too. 269 */ 270 switch (uap->cmd) { 271 case A_SETPOLICY: 272 case A_OLDSETPOLICY: 273 case A_SETKMASK: 274 case A_SETQCTRL: 275 case A_OLDSETQCTRL: 276 case A_SETSTAT: 277 case A_SETUMASK: 278 case A_SETSMASK: 279 case A_SETCOND: 280 case A_OLDSETCOND: 281 case A_SETCLASS: 282 case A_SETPMASK: 283 case A_SETFSIZE: 284 case A_SETKAUDIT: 285 case A_GETCLASS: 286 case A_GETPINFO: 287 case A_GETPINFO_ADDR: 288 case A_SENDTRIGGER: 289 case A_GETSINFO_ADDR: 290 case A_GETSFLAGS: 291 case A_SETSFLAGS: 292 error = copyin(uap->data, (void *)&udata, uap->length); 293 if (error) 294 return (error); 295 AUDIT_ARG(auditon, &udata); 296 AUDIT_ARG(len, uap->length); 297 break; 298 } 299 300 /* Check appropriate privilege. */ 301 switch (uap->cmd) { 302 /* 303 * A_GETSINFO doesn't require priviledge but only superuser 304 * gets to see the audit masks. 305 */ 306 case A_GETSINFO_ADDR: 307 if ((sizeof(udata.au_kau_info) != uap->length) || 308 (audit_session_lookup(udata.au_kau_info.ai_asid, 309 &udata.au_kau_info) != 0)) 310 error = EINVAL; 311 else if (!kauth_cred_issuser(kauth_cred_get())) { 312 udata.au_kau_info.ai_mask.am_success = ~0; 313 udata.au_kau_info.ai_mask.am_failure = ~0; 314 } 315 break; 316 case A_GETSFLAGS: 317 case A_SETSFLAGS: 318 /* Getting one's own audit session flags requires no 319 * privilege. Setting the flags is subject to access 320 * control implemented in audit_session_setaia(). 321 */ 322 break; 323 default: 324 error = suser(kauth_cred_get(), &p->p_acflag); 325 break; 326 } 327 if (error) 328 return (error); 329 330 /* 331 * XXX Need to implement these commands by accessing the global 332 * values associated with the commands. 333 */ 334 switch (uap->cmd) { 335 case A_OLDGETPOLICY: 336 case A_GETPOLICY: 337 if (sizeof(udata.au_policy64) == uap->length) { 338 mtx_lock(&audit_mtx); 339 if (!audit_fail_stop) 340 udata.au_policy64 |= AUDIT_CNT; 341 if (audit_panic_on_write_fail) 342 udata.au_policy64 |= AUDIT_AHLT; 343 if (audit_argv) 344 udata.au_policy64 |= AUDIT_ARGV; 345 if (audit_arge) 346 udata.au_policy64 |= AUDIT_ARGE; 347 mtx_unlock(&audit_mtx); 348 break; 349 } 350 if (sizeof(udata.au_policy) != uap->length) 351 return (EINVAL); 352 mtx_lock(&audit_mtx); 353 if (!audit_fail_stop) 354 udata.au_policy |= AUDIT_CNT; 355 if (audit_panic_on_write_fail) 356 udata.au_policy |= AUDIT_AHLT; 357 if (audit_argv) 358 udata.au_policy |= AUDIT_ARGV; 359 if (audit_arge) 360 udata.au_policy |= AUDIT_ARGE; 361 mtx_unlock(&audit_mtx); 362 break; 363 364 case A_OLDSETPOLICY: 365 case A_SETPOLICY: 366 if (sizeof(udata.au_policy64) == uap->length) { 367 if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT| 368 AUDIT_ARGV|AUDIT_ARGE)) 369 return (EINVAL); 370 mtx_lock(&audit_mtx); 371 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == 372 0); 373 audit_panic_on_write_fail = (udata.au_policy64 & 374 AUDIT_AHLT); 375 audit_argv = (udata.au_policy64 & AUDIT_ARGV); 376 audit_arge = (udata.au_policy64 & AUDIT_ARGE); 377 mtx_unlock(&audit_mtx); 378 break; 379 } 380 if ((sizeof(udata.au_policy) != uap->length) || 381 (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 382 AUDIT_ARGE))) 383 return (EINVAL); 384 /* 385 * XXX - Need to wake up waiters if the policy relaxes? 386 */ 387 mtx_lock(&audit_mtx); 388 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 389 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 390 audit_argv = (udata.au_policy & AUDIT_ARGV); 391 audit_arge = (udata.au_policy & AUDIT_ARGE); 392 mtx_unlock(&audit_mtx); 393 break; 394 395 case A_GETKMASK: 396 if (sizeof(udata.au_mask) != uap->length) 397 return (EINVAL); 398 mtx_lock(&audit_mtx); 399 udata.au_mask = audit_nae_mask; 400 mtx_unlock(&audit_mtx); 401 break; 402 403 case A_SETKMASK: 404 if (sizeof(udata.au_mask) != uap->length) 405 return (EINVAL); 406 mtx_lock(&audit_mtx); 407 audit_nae_mask = udata.au_mask; 408 AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask); 409 mtx_unlock(&audit_mtx); 410 break; 411 412 case A_OLDGETQCTRL: 413 case A_GETQCTRL: 414 if (sizeof(udata.au_qctrl64) == uap->length) { 415 mtx_lock(&audit_mtx); 416 udata.au_qctrl64.aq64_hiwater = 417 (u_int64_t)audit_qctrl.aq_hiwater; 418 udata.au_qctrl64.aq64_lowater = 419 (u_int64_t)audit_qctrl.aq_lowater; 420 udata.au_qctrl64.aq64_bufsz = 421 (u_int64_t)audit_qctrl.aq_bufsz; 422 udata.au_qctrl64.aq64_delay = 423 (u_int64_t)audit_qctrl.aq_delay; 424 udata.au_qctrl64.aq64_minfree = 425 (int64_t)audit_qctrl.aq_minfree; 426 mtx_unlock(&audit_mtx); 427 break; 428 } 429 if (sizeof(udata.au_qctrl) != uap->length) 430 return (EINVAL); 431 mtx_lock(&audit_mtx); 432 udata.au_qctrl = audit_qctrl; 433 mtx_unlock(&audit_mtx); 434 break; 435 436 case A_OLDSETQCTRL: 437 case A_SETQCTRL: 438 if (sizeof(udata.au_qctrl64) == uap->length) { 439 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || 440 (udata.au_qctrl64.aq64_lowater >= 441 udata.au_qctrl64.aq64_hiwater) || 442 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || 443 (udata.au_qctrl64.aq64_minfree < 0) || 444 (udata.au_qctrl64.aq64_minfree > 100)) 445 return (EINVAL); 446 mtx_lock(&audit_mtx); 447 audit_qctrl.aq_hiwater = 448 (int)udata.au_qctrl64.aq64_hiwater; 449 audit_qctrl.aq_lowater = 450 (int)udata.au_qctrl64.aq64_lowater; 451 audit_qctrl.aq_bufsz = 452 (int)udata.au_qctrl64.aq64_bufsz; 453 audit_qctrl.aq_minfree = 454 (int)udata.au_qctrl64.aq64_minfree; 455 audit_qctrl.aq_delay = -1; /* Not used. */ 456 mtx_unlock(&audit_mtx); 457 break; 458 } 459 if ((sizeof(udata.au_qctrl) != uap->length) || 460 (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 461 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 462 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 463 (udata.au_qctrl.aq_minfree < 0) || 464 (udata.au_qctrl.aq_minfree > 100)) 465 return (EINVAL); 466 467 mtx_lock(&audit_mtx); 468 audit_qctrl = udata.au_qctrl; 469 /* XXX The queue delay value isn't used with the kernel. */ 470 audit_qctrl.aq_delay = -1; 471 mtx_unlock(&audit_mtx); 472 break; 473 474 case A_GETCWD: 475 return (ENOSYS); 476 477 case A_GETCAR: 478 return (ENOSYS); 479 480 case A_GETSTAT: 481 return (ENOSYS); 482 483 case A_SETSTAT: 484 return (ENOSYS); 485 486 case A_SETUMASK: 487 return (ENOSYS); 488 489 case A_SETSMASK: 490 return (ENOSYS); 491 492 case A_OLDGETCOND: 493 case A_GETCOND: 494 if (sizeof(udata.au_cond64) == uap->length) { 495 mtx_lock(&audit_mtx); 496 if (audit_enabled && !audit_suspended) 497 udata.au_cond64 = AUC_AUDITING; 498 else 499 udata.au_cond64 = AUC_NOAUDIT; 500 mtx_unlock(&audit_mtx); 501 break; 502 } 503 if (sizeof(udata.au_cond) != uap->length) 504 return (EINVAL); 505 mtx_lock(&audit_mtx); 506 if (audit_enabled && !audit_suspended) 507 udata.au_cond = AUC_AUDITING; 508 else 509 udata.au_cond = AUC_NOAUDIT; 510 mtx_unlock(&audit_mtx); 511 break; 512 513 case A_OLDSETCOND: 514 case A_SETCOND: 515 if (sizeof(udata.au_cond64) == uap->length) { 516 mtx_lock(&audit_mtx); 517 if (udata.au_cond64 == AUC_NOAUDIT) 518 audit_suspended = 1; 519 if (udata.au_cond64 == AUC_AUDITING) 520 audit_suspended = 0; 521 if (udata.au_cond64 == AUC_DISABLED) { 522 audit_suspended = 1; 523 mtx_unlock(&audit_mtx); 524 audit_shutdown(); 525 break; 526 } 527 mtx_unlock(&audit_mtx); 528 break; 529 } 530 if (sizeof(udata.au_cond) != uap->length) { 531 return (EINVAL); 532 } 533 mtx_lock(&audit_mtx); 534 if (udata.au_cond == AUC_NOAUDIT) 535 audit_suspended = 1; 536 if (udata.au_cond == AUC_AUDITING) 537 audit_suspended = 0; 538 if (udata.au_cond == AUC_DISABLED) { 539 audit_suspended = 1; 540 mtx_unlock(&audit_mtx); 541 audit_shutdown(); 542 break; 543 } 544 mtx_unlock(&audit_mtx); 545 break; 546 547 case A_GETCLASS: 548 if (sizeof(udata.au_evclass) != uap->length) 549 return (EINVAL); 550 udata.au_evclass.ec_class = au_event_class( 551 udata.au_evclass.ec_number); 552 break; 553 554 case A_SETCLASS: 555 if (sizeof(udata.au_evclass) != uap->length) 556 return (EINVAL); 557 au_evclassmap_insert(udata.au_evclass.ec_number, 558 udata.au_evclass.ec_class); 559 break; 560 561 case A_GETPINFO: 562 if ((sizeof(udata.au_aupinfo) != uap->length) || 563 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) 564 return (EINVAL); 565 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) 566 return (ESRCH); 567 568 scred = kauth_cred_proc_ref(tp); 569 if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) { 570 kauth_cred_unref(&scred); 571 proc_rele(tp); 572 return (EINVAL); 573 } 574 575 udata.au_aupinfo.ap_auid = 576 scred->cr_audit.as_aia_p->ai_auid; 577 udata.au_aupinfo.ap_mask.am_success = 578 scred->cr_audit.as_mask.am_success; 579 udata.au_aupinfo.ap_mask.am_failure = 580 scred->cr_audit.as_mask.am_failure; 581 udata.au_aupinfo.ap_termid.machine = 582 scred->cr_audit.as_aia_p->ai_termid.at_addr[0]; 583 udata.au_aupinfo.ap_termid.port = 584 scred->cr_audit.as_aia_p->ai_termid.at_port; 585 udata.au_aupinfo.ap_asid = 586 scred->cr_audit.as_aia_p->ai_asid; 587 kauth_cred_unref(&scred); 588 proc_rele(tp); 589 tp = PROC_NULL; 590 break; 591 592 case A_SETPMASK: 593 if ((sizeof(udata.au_aupinfo) != uap->length) || 594 IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) 595 return (EINVAL); 596 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) 597 return (ESRCH); 598 scred = kauth_cred_proc_ref(tp); 599 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); 600 kauth_cred_unref(&scred); 601 aia.ai_mask.am_success = 602 udata.au_aupinfo.ap_mask.am_success; 603 aia.ai_mask.am_failure = 604 udata.au_aupinfo.ap_mask.am_failure; 605 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); 606 error = audit_session_setaia(tp, &aia); 607 proc_rele(tp); 608 tp = PROC_NULL; 609 if (error) 610 return (error); 611 break; 612 613 case A_SETFSIZE: 614 if ((sizeof(udata.au_fstat) != uap->length) || 615 ((udata.au_fstat.af_filesz != 0) && 616 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))) 617 return (EINVAL); 618 mtx_lock(&audit_mtx); 619 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 620 mtx_unlock(&audit_mtx); 621 break; 622 623 case A_GETFSIZE: 624 if (sizeof(udata.au_fstat) != uap->length) 625 return (EINVAL); 626 mtx_lock(&audit_mtx); 627 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 628 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 629 mtx_unlock(&audit_mtx); 630 break; 631 632 case A_GETPINFO_ADDR: 633 if ((sizeof(udata.au_aupinfo_addr) != uap->length) || 634 IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid)) 635 return (EINVAL); 636 if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) 637 return (ESRCH); 638 WARN_IF_AINFO_ADDR_CHANGED(uap->length, 639 sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)", 640 "auditpinfo_addr_t"); 641 scred = kauth_cred_proc_ref(tp); 642 udata.au_aupinfo_addr.ap_auid = 643 scred->cr_audit.as_aia_p->ai_auid; 644 udata.au_aupinfo_addr.ap_asid = 645 scred->cr_audit.as_aia_p->ai_asid; 646 udata.au_aupinfo_addr.ap_mask.am_success = 647 scred->cr_audit.as_mask.am_success; 648 udata.au_aupinfo_addr.ap_mask.am_failure = 649 scred->cr_audit.as_mask.am_failure; 650 bcopy(&scred->cr_audit.as_aia_p->ai_termid, 651 &udata.au_aupinfo_addr.ap_termid, 652 sizeof(au_tid_addr_t)); 653 udata.au_aupinfo_addr.ap_flags = 654 scred->cr_audit.as_aia_p->ai_flags; 655 kauth_cred_unref(&scred); 656 proc_rele(tp); 657 tp = PROC_NULL; 658 break; 659 660 case A_GETKAUDIT: 661 if (sizeof(udata.au_kau_info) != uap->length) 662 return (EINVAL); 663 audit_get_kinfo(&udata.au_kau_info); 664 break; 665 666 case A_SETKAUDIT: 667 if ((sizeof(udata.au_kau_info) != uap->length) || 668 (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && 669 udata.au_kau_info.ai_termid.at_type != AU_IPv6)) 670 return (EINVAL); 671 audit_set_kinfo(&udata.au_kau_info); 672 break; 673 674 case A_SENDTRIGGER: 675 if ((sizeof(udata.au_trigger) != uap->length) || 676 (udata.au_trigger < AUDIT_TRIGGER_MIN) || 677 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 678 return (EINVAL); 679 return (audit_send_trigger(udata.au_trigger)); 680 681 case A_GETSINFO_ADDR: 682 /* Handled above before switch(). */ 683 break; 684 685 case A_GETSFLAGS: 686 if (sizeof(udata.au_flags) != uap->length) 687 return (EINVAL); 688 bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags), 689 &udata.au_flags, sizeof(udata.au_flags)); 690 break; 691 692 case A_SETSFLAGS: 693 if (sizeof(udata.au_flags) != uap->length) 694 return (EINVAL); 695 bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia)); 696 aia.ai_flags = udata.au_flags; 697 error = audit_session_setaia(p, &aia); 698 if (error) 699 return (error); 700 break; 701 702 default: 703 return (EINVAL); 704 } 705 706 /* 707 * Copy data back to userspace for the GET comands. 708 */ 709 switch (uap->cmd) { 710 case A_GETPOLICY: 711 case A_OLDGETPOLICY: 712 case A_GETKMASK: 713 case A_GETQCTRL: 714 case A_OLDGETQCTRL: 715 case A_GETCWD: 716 case A_GETCAR: 717 case A_GETSTAT: 718 case A_GETCOND: 719 case A_OLDGETCOND: 720 case A_GETCLASS: 721 case A_GETPINFO: 722 case A_GETFSIZE: 723 case A_GETPINFO_ADDR: 724 case A_GETKAUDIT: 725 case A_GETSINFO_ADDR: 726 case A_GETSFLAGS: 727 error = copyout((void *)&udata, uap->data, uap->length); 728 if (error) 729 return (ENOSYS); 730 break; 731 } 732 733 return (0); 734} 735 736/* 737 * System calls to manage the user audit information. 738 */ 739/* ARGSUSED */ 740int 741getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval) 742{ 743 au_id_t id; 744 int error; 745 kauth_cred_t scred; 746 747#if CONFIG_MACF 748 error = mac_proc_check_getauid(p); 749 if (error) 750 return (error); 751#endif 752 scred = kauth_cred_proc_ref(p); 753 id = scred->cr_audit.as_aia_p->ai_auid; 754 kauth_cred_unref(&scred); 755 756 error = copyout((void *)&id, uap->auid, sizeof(id)); 757 if (error) 758 return (error); 759 760 return (0); 761} 762 763/* ARGSUSED */ 764int 765setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval) 766{ 767 int error; 768 au_id_t id; 769 kauth_cred_t scred; 770 struct auditinfo_addr aia; 771 772 error = copyin(uap->auid, &id, sizeof(id)); 773 if (error) 774 return (error); 775 AUDIT_ARG(auid, id); 776 777#if CONFIG_MACF 778 error = mac_proc_check_setauid(p, id); 779 if (error) 780 return (error); 781#endif 782 783 scred = kauth_cred_proc_ref(p); 784 error = suser(scred, &p->p_acflag); 785 if (error) { 786 kauth_cred_unref(&scred); 787 return (error); 788 } 789 790 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); 791 if (aia.ai_asid == AU_DEFAUDITSID) { 792 aia.ai_asid = AU_ASSIGN_ASID; 793 } 794 bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t)); 795 kauth_cred_unref(&scred); 796 aia.ai_auid = id; 797 error = audit_session_setaia(p, &aia); 798 799 return (error); 800} 801 802static int 803getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length) 804{ 805 kauth_cred_t scred; 806 auditinfo_addr_t aia; 807 808 scred = kauth_cred_proc_ref(p); 809 bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t)); 810 /* 811 * Only superuser gets to see the real mask. 812 */ 813 if (suser(scred, &p->p_acflag)) { 814 aia.ai_mask.am_success = ~0; 815 aia.ai_mask.am_failure = ~0; 816 } 817 kauth_cred_unref(&scred); 818 819 return (copyout(&aia, user_addr, min(sizeof(aia), length))); 820} 821 822/* ARGSUSED */ 823int 824getaudit_addr(proc_t p, struct getaudit_addr_args *uap, 825 __unused int32_t *retval) 826{ 827#if CONFIG_MACF 828 int error = mac_proc_check_getaudit(p); 829 830 if (error) 831 return (error); 832#endif /* CONFIG_MACF */ 833 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t), 834 "getaudit_addr(2)", "auditinfo_addr_t"); 835 836 return (getaudit_addr_internal(p, uap->auditinfo_addr, uap->length)); 837} 838 839/* ARGSUSED */ 840int 841setaudit_addr(proc_t p, struct setaudit_addr_args *uap, 842 __unused int32_t *retval) 843{ 844 struct auditinfo_addr aia; 845 kauth_cred_t scred; 846 int error; 847 848 bzero(&aia, sizeof(auditinfo_addr_t)); 849 error = copyin(uap->auditinfo_addr, &aia, 850 min(sizeof(aia), uap->length)); 851 if (error) 852 return (error); 853 AUDIT_ARG(auditinfo_addr, &aia); 854 if (aia.ai_termid.at_type != AU_IPv6 && 855 aia.ai_termid.at_type != AU_IPv4) 856 return (EINVAL); 857 if (aia.ai_asid != AU_ASSIGN_ASID && 858 (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX) 859 return (EINVAL); 860 861#if CONFIG_MACF 862 error = mac_proc_check_setaudit(p, &aia); 863 if (error) 864 return (error); 865#endif 866 867 scred = kauth_cred_proc_ref(p); 868 error = suser(scred, &p->p_acflag); 869 if (error) { 870 kauth_cred_unref(&scred); 871 return (error); 872 } 873 874 WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t), 875 "setaudit_addr(2)", "auditinfo_addr_t"); 876 WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)"); 877 kauth_cred_unref(&scred); 878 879 AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); 880 if (aia.ai_asid == AU_DEFAUDITSID) 881 aia.ai_asid = AU_ASSIGN_ASID; 882 883 error = audit_session_setaia(p, &aia); 884 if (error) 885 return (error); 886 887 /* 888 * If asked to assign an ASID then let the user know what the ASID is 889 * by copying the auditinfo_addr struct back out. 890 */ 891 if (aia.ai_asid == AU_ASSIGN_ASID) 892 error = getaudit_addr_internal(p, uap->auditinfo_addr, 893 uap->length); 894 895 return (error); 896} 897 898/* 899 * Syscall to manage audit files. 900 * 901 */ 902/* ARGSUSED */ 903int 904auditctl(proc_t p, struct auditctl_args *uap, __unused int32_t *retval) 905{ 906 struct nameidata nd; 907 kauth_cred_t cred; 908 struct vnode *vp; 909 int error = 0; 910 911 error = suser(kauth_cred_get(), &p->p_acflag); 912 if (error) 913 return (error); 914 915 vp = NULL; 916 cred = NULL; 917 918 /* 919 * If a path is specified, open the replacement vnode, perform 920 * validity checks, and grab another reference to the current 921 * credential. 922 * 923 * XXX Changes API slightly. NULL path no longer disables audit but 924 * returns EINVAL. 925 */ 926 if (uap->path == USER_ADDR_NULL) 927 return (EINVAL); 928 929 NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1, 930 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : 931 UIO_USERSPACE32), uap->path, vfs_context_current()); 932 error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0); 933 if (error) 934 return (error); 935 vp = nd.ni_vp; 936#if CONFIG_MACF 937 /* 938 * Accessibility of the vnode was determined in vn_open; the 939 * mac_system_check_auditctl should only determine whether that vnode 940 * is appropriate for storing audit data, or that the caller was 941 * permitted to control the auditing system at all. For example, a 942 * confidentiality policy may want to ensure that audit files are 943 * always high sensitivity. 944 */ 945 error = mac_system_check_auditctl(kauth_cred_get(), vp); 946 if (error) { 947 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current()); 948 vnode_put(vp); 949 return (error); 950 } 951#endif 952 if (vp->v_type != VREG) { 953 vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current()); 954 vnode_put(vp); 955 return (EINVAL); 956 } 957 mtx_lock(&audit_mtx); 958 /* 959 * XXXAUDIT: Should audit_suspended actually be cleared by 960 * audit_worker? 961 */ 962 audit_suspended = 0; 963 mtx_unlock(&audit_mtx); 964 965 /* 966 * The following gets unreferenced in audit_rotate_vnode() 967 * after the rotation and it is no longer needed. 968 */ 969 cred = kauth_cred_get_with_ref(); 970 audit_rotate_vnode(cred, vp); 971 vnode_put(vp); 972 973 return (error); 974} 975 976#else /* !CONFIG_AUDIT */ 977 978int 979audit(proc_t p, struct audit_args *uap, int32_t *retval) 980{ 981#pragma unused(p, uap, retval) 982 983 return (ENOSYS); 984} 985 986int 987auditon(proc_t p, struct auditon_args *uap, int32_t *retval) 988{ 989#pragma unused(p, uap, retval) 990 991 return (ENOSYS); 992} 993 994int 995getauid(proc_t p, struct getauid_args *uap, int32_t *retval) 996{ 997#pragma unused(p, uap, retval) 998 999 return (ENOSYS); 1000} 1001 1002int 1003setauid(proc_t p, struct setauid_args *uap, int32_t *retval) 1004{ 1005#pragma unused(p, uap, retval) 1006 1007 return (ENOSYS); 1008} 1009 1010int 1011getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval) 1012{ 1013#pragma unused(p, uap, retval) 1014 1015 return (ENOSYS); 1016} 1017 1018int 1019setaudit_addr(proc_t p, struct setaudit_addr_args *uap, int32_t *retval) 1020{ 1021#pragma unused(p, uap, retval) 1022 1023 return (ENOSYS); 1024} 1025 1026int 1027auditctl(proc_t p, struct auditctl_args *uap, int32_t *retval) 1028{ 1029#pragma unused(p, uap, retval) 1030 1031 return (ENOSYS); 1032} 1033 1034#endif /* CONFIG_AUDIT */ 1035