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