1/*- 2 * Copyright (c) 2008-2009 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#include <stdarg.h> 31 32#include <sys/kernel.h> 33#include <sys/fcntl.h> 34#include <sys/kauth.h> 35#include <sys/conf.h> 36#include <sys/poll.h> 37#include <sys/queue.h> 38#include <sys/signalvar.h> 39#include <sys/syscall.h> 40#include <sys/sysent.h> 41#include <sys/sysproto.h> 42#include <sys/systm.h> 43#include <sys/ucred.h> 44#include <sys/user.h> 45 46#include <miscfs/devfs/devfs.h> 47 48#include <libkern/OSAtomic.h> 49 50#include <bsm/audit.h> 51#include <bsm/audit_internal.h> 52#include <bsm/audit_kevents.h> 53 54#include <security/audit/audit.h> 55#include <security/audit/audit_bsd.h> 56#include <security/audit/audit_ioctl.h> 57#include <security/audit/audit_private.h> 58 59#include <vm/vm_protos.h> 60#include <mach/mach_port.h> 61#include <kern/audit_sessionport.h> 62 63#include <libkern/OSDebug.h> 64 65/* 66 * Audit Session Entry. This is treated as an object with public and private 67 * data. The se_auinfo field is the only information that is public and 68 * needs to be the first entry. 69 */ 70struct au_sentry { 71 auditinfo_addr_t se_auinfo; /* Public audit session data. */ 72#define se_asid se_auinfo.ai_asid 73#define se_auid se_auinfo.ai_auid 74#define se_mask se_auinfo.ai_mask 75#define se_termid se_auinfo.ai_termid 76#define se_flags se_auinfo.ai_flags 77 78 long se_refcnt; /* Reference count. */ 79 long se_procnt; /* Processes in session. */ 80 ipc_port_t se_port; /* Session port. */ 81 LIST_ENTRY(au_sentry) se_link; /* Hash bucket link list (1) */ 82}; 83typedef struct au_sentry au_sentry_t; 84 85#define AU_SENTRY_PTR(aia_p) ((au_sentry_t *)(aia_p)) 86 87/* 88 * The default au_sentry/auditinfo_addr entry for ucred. 89 */ 90 91static au_sentry_t audit_default_se = { 92 .se_auinfo = { 93 .ai_auid = AU_DEFAUDITID, 94 .ai_asid = AU_DEFAUDITSID, 95 .ai_termid = { .at_type = AU_IPv4, }, 96 }, 97 .se_refcnt = 1, 98 .se_procnt = 1, 99}; 100 101struct auditinfo_addr *audit_default_aia_p = &audit_default_se.se_auinfo; 102 103kern_return_t ipc_object_copyin(ipc_space_t, mach_port_name_t, 104 mach_msg_type_name_t, ipc_port_t *); 105void ipc_port_release_send(ipc_port_t); 106 107#if CONFIG_AUDIT 108 109 110/* 111 * Currently the hash table is a fixed size. 112 */ 113#define HASH_TABLE_SIZE 97 114#define HASH_ASID(asid) (audit_session_hash(asid) % HASH_TABLE_SIZE) 115 116static struct rwlock se_entry_lck; /* (1) lock for se_link above */ 117 118LIST_HEAD(au_sentry_head, au_sentry); 119static struct au_sentry_head *au_sentry_bucket = NULL; 120 121#define AU_HISTORY_LOGGING 0 122#if AU_HISTORY_LOGGING 123typedef enum au_history_event { 124 AU_HISTORY_EVENT_UNKNOWN = 0, 125 AU_HISTORY_EVENT_REF = 1, 126 AU_HISTORY_EVENT_UNREF = 2, 127 AU_HISTORY_EVENT_BIRTH = 3, 128 AU_HISTORY_EVENT_DEATH = 4, 129 AU_HISTORY_EVENT_FIND = 5 130} au_history_event_t; 131 132#define AU_HISTORY_MAX_STACK_DEPTH 8 133 134struct au_history { 135 struct au_sentry *ptr; 136 struct au_sentry se; 137 void *stack[AU_HISTORY_MAX_STACK_DEPTH]; 138 unsigned int stack_depth; 139 au_history_event_t event; 140}; 141 142static struct au_history *au_history; 143static size_t au_history_size = 65536; 144static unsigned int au_history_index; 145 146static inline unsigned int 147au_history_entries(void) 148{ 149 if (au_history_index >= au_history_size) 150 return au_history_size; 151 else 152 return au_history_index; 153} 154 155static inline void 156au_history_record(au_sentry_t *se, au_history_event_t event) 157{ 158 struct au_history *p; 159 unsigned int i; 160 161 i = OSAddAtomic(1, &au_history_index); 162 p = &au_history[i % au_history_size]; 163 164 bzero(p, sizeof(*p)); 165 p->event = event; 166 bcopy(se, &p->se, sizeof(p->se)); 167 p->stack_depth = OSBacktrace(&p->stack[0], AU_HISTORY_MAX_STACK_DEPTH); 168 p->ptr = se; 169} 170#else 171#define au_history_record(se, event) do {} while (0) 172#endif 173 174MALLOC_DEFINE(M_AU_SESSION, "audit_session", "Audit session data"); 175 176static void audit_ref_session(au_sentry_t *se); 177static void audit_unref_session(au_sentry_t *se); 178 179static void audit_session_event(int event, auditinfo_addr_t *aia_p); 180 181/* 182 * Audit session device. 183 */ 184 185static MALLOC_DEFINE(M_AUDIT_SDEV, "audit_sdev", "Audit sdevs"); 186static MALLOC_DEFINE(M_AUDIT_SDEV_ENTRY, "audit_sdevent", 187 "Audit sdev entries and buffers"); 188 189/* 190 * Default audit sdev buffer parameters. 191 */ 192#define AUDIT_SDEV_QLIMIT_DEFAULT 128 193#define AUDIT_SDEV_QLIMIT_MIN 1 194#define AUDIT_SDEV_QLIMIT_MAX 1024 195 196/* 197 * Entry structure. 198 */ 199struct audit_sdev_entry { 200 void *ase_record; 201 u_int ase_record_len; 202 TAILQ_ENTRY(audit_sdev_entry) ase_queue; 203}; 204 205/* 206 * Per audit sdev structure. 207 */ 208 209struct audit_sdev { 210 int asdev_open; 211 212#define AUDIT_SDEV_ASYNC 0x00000001 213#define AUDIT_SDEV_NBIO 0x00000002 214 215#define AUDIT_SDEV_ALLSESSIONS 0x00010000 216 u_int asdev_flags; 217 218 struct selinfo asdev_selinfo; 219 pid_t asdev_sigio; 220 221 au_id_t asdev_auid; 222 au_asid_t asdev_asid; 223 224 /* Per-sdev mutex for most fields in this struct. */ 225 struct mtx asdev_mtx; 226 227 /* 228 * Per-sdev sleep lock serializing user-generated reads and 229 * flushes. uiomove() is called to copy out the current head 230 * record's data whie the record remains in the queue, so we 231 * prevent other threads from removing it using this lock. 232 */ 233 struct slck asdev_sx; 234 235 /* 236 * Condition variable to signal when data has been delivered to 237 * a sdev. 238 */ 239 struct cv asdev_cv; 240 241 /* Count and bound of records in the queue. */ 242 u_int asdev_qlen; 243 u_int asdev_qlimit; 244 245 /* The number of bytes of data across all records. */ 246 u_int asdev_qbyteslen; 247 248 /* 249 * The amount read so far of the first record in the queue. 250 * (The number of bytes available for reading in the queue is 251 * qbyteslen - qoffset.) 252 */ 253 u_int asdev_qoffset; 254 255 /* 256 * Per-sdev operation statistics. 257 */ 258 u_int64_t asdev_inserts; /* Records added. */ 259 u_int64_t asdev_reads; /* Records read. */ 260 u_int64_t asdev_drops; /* Records dropped. */ 261 262 /* 263 * Current pending record list. This is protected by a 264 * combination of asdev_mtx and asdev_sx. Note that both 265 * locks are required to remove a record from the head of the 266 * queue, as an in-progress read may sleep while copying and, 267 * therefore, cannot hold asdev_mtx. 268 */ 269 TAILQ_HEAD(, audit_sdev_entry) asdev_queue; 270 271 /* Global sdev list. */ 272 TAILQ_ENTRY(audit_sdev) asdev_list; 273}; 274 275#define AUDIT_SDEV_LOCK(asdev) mtx_lock(&(asdev)->asdev_mtx) 276#define AUDIT_SDEV_LOCK_ASSERT(asdev) mtx_assert(&(asdev)->asdev_mtx, \ 277 MA_OWNED) 278#define AUDIT_SDEV_LOCK_DESTROY(asdev) mtx_destroy(&(asdev)->asdev_mtx) 279#define AUDIT_SDEV_LOCK_INIT(asdev) mtx_init(&(asdev)->asdev_mtx, \ 280 "audit_sdev_mtx", NULL, MTX_DEF) 281#define AUDIT_SDEV_UNLOCK(asdev) mtx_unlock(&(asdev)->asdev_mtx) 282#define AUDIT_SDEV_MTX(asdev) (&(asdev)->asdev_mtx) 283 284#define AUDIT_SDEV_SX_LOCK_DESTROY(asd) slck_destroy(&(asd)->asdev_sx) 285#define AUDIT_SDEV_SX_LOCK_INIT(asd) slck_init(&(asd)->asdev_sx, \ 286 "audit_sdev_sx") 287#define AUDIT_SDEV_SX_XLOCK_ASSERT(asd) slck_assert(&(asd)->asdev_sx, \ 288 SA_XLOCKED) 289#define AUDIT_SDEV_SX_XLOCK_SIG(asd) slck_lock_sig(&(asd)->asdev_sx) 290#define AUDIT_SDEV_SX_XUNLOCK(asd) slck_unlock(&(asd)->asdev_sx) 291 292/* 293 * Cloning variables and constants. 294 */ 295#define AUDIT_SDEV_NAME "auditsessions" 296#define MAX_AUDIT_SDEVS 32 297 298static int audit_sdev_major; 299static void *devnode; 300 301/* 302 * Global list of audit sdevs. The list is protected by a rw lock. 303 * Individaul record queues are protected by per-sdev locks. These 304 * locks synchronize between threads walking the list to deliver to 305 * individual sdevs and adds/removes of sdevs. 306 */ 307static TAILQ_HEAD(, audit_sdev) audit_sdev_list; 308static struct rwlock audit_sdev_lock; 309 310#define AUDIT_SDEV_LIST_LOCK_INIT() rw_init(&audit_sdev_lock, \ 311 "audit_sdev_list_lock") 312#define AUDIT_SDEV_LIST_RLOCK() rw_rlock(&audit_sdev_lock) 313#define AUDIT_SDEV_LIST_RUNLOCK() rw_runlock(&audit_sdev_lock) 314#define AUDIT_SDEV_LIST_WLOCK() rw_wlock(&audit_sdev_lock) 315#define AUDIT_SDEV_LIST_WLOCK_ASSERT() rw_assert(&audit_sdev_lock, \ 316 RA_WLOCKED) 317#define AUDIT_SDEV_LIST_WUNLOCK() rw_wunlock(&audit_sdev_lock) 318 319/* 320 * dev_t doesn't have a pointer for "softc" data so we have to keep track of 321 * it with the following global array (indexed by the minor number). 322 * 323 * XXX We may want to dynamically grow this as need. 324 */ 325static struct audit_sdev *audit_sdev_dtab[MAX_AUDIT_SDEVS]; 326 327/* 328 * Special device methods and definition. 329 */ 330static open_close_fcn_t audit_sdev_open; 331static open_close_fcn_t audit_sdev_close; 332static read_write_fcn_t audit_sdev_read; 333static ioctl_fcn_t audit_sdev_ioctl; 334static select_fcn_t audit_sdev_poll; 335 336static struct cdevsw audit_sdev_cdevsw = { 337 .d_open = audit_sdev_open, 338 .d_close = audit_sdev_close, 339 .d_read = audit_sdev_read, 340 .d_write = eno_rdwrt, 341 .d_ioctl = audit_sdev_ioctl, 342 .d_stop = eno_stop, 343 .d_reset = eno_reset, 344 .d_ttys = NULL, 345 .d_select = audit_sdev_poll, 346 .d_mmap = eno_mmap, 347 .d_strategy = eno_strat, 348 .d_type = 0 349}; 350 351/* 352 * Global statistics on audit sdevs. 353 */ 354static int audit_sdev_count; /* Current number of sdevs. */ 355static u_int64_t audit_sdev_ever; /* Sdevs ever allocated. */ 356static u_int64_t audit_sdev_records; /* Total records seen. */ 357static u_int64_t audit_sdev_drops; /* Global record drop count. */ 358 359static int audit_sdev_init(void); 360 361#define AUDIT_SENTRY_RWLOCK_INIT() rw_init(&se_entry_lck, \ 362 "se_entry_lck") 363#define AUDIT_SENTRY_RLOCK() rw_rlock(&se_entry_lck) 364#define AUDIT_SENTRY_WLOCK() rw_wlock(&se_entry_lck) 365#define AUDIT_SENTRY_RWLOCK_ASSERT() rw_assert(&se_entry_lck, RA_LOCKED) 366#define AUDIT_SENTRY_RUNLOCK() rw_runlock(&se_entry_lck) 367#define AUDIT_SENTRY_WUNLOCK() rw_wunlock(&se_entry_lck) 368 369/* Access control on the auditinfo_addr.ai_flags member. */ 370static uint64_t audit_session_superuser_set_sflags_mask; 371static uint64_t audit_session_superuser_clear_sflags_mask; 372static uint64_t audit_session_member_set_sflags_mask; 373static uint64_t audit_session_member_clear_sflags_mask; 374SYSCTL_NODE(, OID_AUTO, audit, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Audit controls"); 375SYSCTL_NODE(_audit, OID_AUTO, session, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Audit sessions"); 376SYSCTL_QUAD(_audit_session, OID_AUTO, superuser_set_sflags_mask, CTLFLAG_RW | CTLFLAG_LOCKED, 377 &audit_session_superuser_set_sflags_mask, 378 "Audit session flags settable by superuser"); 379SYSCTL_QUAD(_audit_session, OID_AUTO, superuser_clear_sflags_mask, CTLFLAG_RW | CTLFLAG_LOCKED, 380 &audit_session_superuser_clear_sflags_mask, 381 "Audit session flags clearable by superuser"); 382SYSCTL_QUAD(_audit_session, OID_AUTO, member_set_sflags_mask, CTLFLAG_RW | CTLFLAG_LOCKED, 383 &audit_session_member_set_sflags_mask, 384 "Audit session flags settable by a session member"); 385SYSCTL_QUAD(_audit_session, OID_AUTO, member_clear_sflags_mask, CTLFLAG_RW | CTLFLAG_LOCKED, 386 &audit_session_member_clear_sflags_mask, 387 "Audit session flags clearable by a session member"); 388 389#define AUDIT_SESSION_DEBUG 0 390#if AUDIT_SESSION_DEBUG 391/* 392 * The following is debugging code that can be used to get a snapshot of the 393 * session state. The audit session information is read out using sysctl: 394 * 395 * error = sysctlbyname("kern.audit_session_debug", buffer_ptr, &buffer_len, 396 * NULL, 0); 397 */ 398#include <kern/kalloc.h> 399 400/* 401 * The per session record structure for the snapshot data. 402 */ 403struct au_sentry_debug { 404 auditinfo_addr_t se_auinfo; 405 int64_t se_refcnt; /* refereence count */ 406 int64_t se_procnt; /* process count */ 407 int64_t se_ptcnt; /* process count from 408 proc table */ 409}; 410typedef struct au_sentry_debug au_sentry_debug_t; 411 412static int audit_sysctl_session_debug(struct sysctl_oid *oidp, void *arg1, 413 int arg2, struct sysctl_req *req); 414 415SYSCTL_PROC(_kern, OID_AUTO, audit_session_debug, CTLFLAG_RD | CTLFLAG_LOCKED, 416 NULL, 0, audit_sysctl_session_debug, "S,audit_session_debug", 417 "Current session debug info for auditing."); 418 419/* 420 * Callouts for proc_interate() which is used to reconcile the audit session 421 * proc state information with the proc table. We get everything we need 422 * in the filterfn while the proc_lock() is held so we really don't need the 423 * callout() function. 424 */ 425static int 426audit_session_debug_callout(__unused proc_t p, __unused void *arg) 427{ 428 429 return (PROC_RETURNED_DONE); 430} 431 432static int 433audit_session_debug_filterfn(proc_t p, void *st) 434{ 435 kauth_cred_t cred = p->p_ucred; 436 auditinfo_addr_t *aia_p = cred->cr_audit.as_aia_p; 437 au_sentry_debug_t *sed_tab = (au_sentry_debug_t *) st; 438 au_sentry_debug_t *sdtp; 439 au_sentry_t *se; 440 441 if (IS_VALID_SESSION(aia_p)) { 442 sdtp = &sed_tab[0]; 443 do { 444 if (aia_p->ai_asid == sdtp->se_asid) { 445 sdtp->se_ptcnt++; 446 447 /* Do some santy checks. */ 448 se = AU_SENTRY_PTR(aia_p); 449 if (se->se_refcnt != sdtp->se_refcnt) { 450 sdtp->se_refcnt = 451 (int64_t)se->se_refcnt; 452 } 453 if (se->se_procnt != sdtp->se_procnt) { 454 sdtp->se_procnt = 455 (int64_t)se->se_procnt; 456 } 457 break; 458 } 459 sdtp++; 460 } while (sdtp->se_asid != 0 && sdtp->se_auid != 0); 461 } else { 462 /* add it to the default sesison */ 463 sed_tab->se_ptcnt++; 464 } 465 466 return (0); 467} 468 469/* 470 * Copy out the session debug info via the sysctl interface. 471 * 472 */ 473static int 474audit_sysctl_session_debug(__unused struct sysctl_oid *oidp, 475 __unused void *arg1, __unused int arg2, struct sysctl_req *req) 476{ 477 au_sentry_t *se; 478 au_sentry_debug_t *sed_tab, *next_sed; 479 int i, entry_cnt = 0; 480 size_t sz; 481 int err = 0; 482 483 /* 484 * This provides a read-only node. 485 */ 486 if (req->newptr != USER_ADDR_NULL) 487 return (EPERM); 488 489 /* 490 * Walk the audit session hash table to determine the size. 491 */ 492 AUDIT_SENTRY_RLOCK(); 493 for(i = 0; i < HASH_TABLE_SIZE; i++) 494 LIST_FOREACH(se, &au_sentry_bucket[i], se_link) 495 if (se != NULL) 496 entry_cnt++; 497 498 entry_cnt++; /* add one for the default entry */ 499 /* 500 * If just querying then return the space required. There is an 501 * obvious race condition here so we just fudge this by 3 in case 502 * the audit session table grows. 503 */ 504 if (req->oldptr == USER_ADDR_NULL) { 505 req->oldidx = (entry_cnt + 3) * sizeof(au_sentry_debug_t); 506 AUDIT_SENTRY_RUNLOCK(); 507 return (0); 508 } 509 510 /* 511 * Alloc a temporary buffer. 512 */ 513 if (req->oldlen < (entry_cnt * sizeof(au_sentry_debug_t))) { 514 AUDIT_SENTRY_RUNLOCK(); 515 return (ENOMEM); 516 } 517 /* 518 * We hold the lock over the alloc since we don't want the table to 519 * grow on us. Therefore, use the non-blocking version of kalloc(). 520 */ 521 sed_tab = (au_sentry_debug_t *)kalloc_noblock(entry_cnt * 522 sizeof(au_sentry_debug_t)); 523 if (sed_tab == NULL) { 524 AUDIT_SENTRY_RUNLOCK(); 525 return (ENOMEM); 526 } 527 bzero(sed_tab, entry_cnt * sizeof(au_sentry_debug_t)); 528 529 /* 530 * Walk the audit session hash table and build the record array. 531 */ 532 sz = 0; 533 next_sed = sed_tab; 534 /* add the first entry for processes not tracked in sessions. */ 535 bcopy(audit_default_aia_p, &next_sed->se_auinfo, sizeof (au_sentry_t)); 536 next_sed->se_refcnt = (int64_t)audit_default_se.se_refcnt; 537 next_sed->se_procnt = (int64_t)audit_default_se.se_procnt; 538 next_sed++; 539 sz += sizeof(au_sentry_debug_t); 540 for(i = 0; i < HASH_TABLE_SIZE; i++) { 541 LIST_FOREACH(se, &au_sentry_bucket[i], se_link) { 542 if (se != NULL) { 543 next_sed->se_auinfo = se->se_auinfo; 544 next_sed->se_refcnt = (int64_t)se->se_refcnt; 545 next_sed->se_procnt = (int64_t)se->se_procnt; 546 next_sed++; 547 sz += sizeof(au_sentry_debug_t); 548 } 549 } 550 } 551 AUDIT_SENTRY_RUNLOCK(); 552 553 /* Reconcile with the process table. */ 554 (void) proc_iterate(PROC_ALLPROCLIST | PROC_ZOMBPROCLIST, 555 audit_session_debug_callout, NULL, 556 audit_session_debug_filterfn, (void *)&sed_tab[0]); 557 558 559 req->oldlen = sz; 560 err = SYSCTL_OUT(req, sed_tab, sz); 561 kfree(sed_tab, entry_cnt * sizeof(au_sentry_debug_t)); 562 563 return (err); 564} 565 566#endif /* AUDIT_SESSION_DEBUG */ 567 568/* 569 * Create and commit a session audit event. The proc and se arguments needs to 570 * be that of the subject and not necessarily the current process. 571 */ 572static void 573audit_session_event(int event, auditinfo_addr_t *aia_p) 574{ 575 struct kaudit_record *ar; 576 577 KASSERT(AUE_SESSION_START == event || AUE_SESSION_UPDATE == event || 578 AUE_SESSION_END == event || AUE_SESSION_CLOSE == event, 579 ("audit_session_event: invalid event: %d", event)); 580 581 if (NULL == aia_p) 582 return; 583 584 /* 585 * Create a new audit record. The record will contain the subject 586 * ruid, rgid, egid, pid, auid, asid, amask, and term_addr 587 * (implicitly added by audit_new). 588 */ 589 ar = audit_new(event, PROC_NULL, /* Not used */ NULL); 590 if (NULL == ar) 591 return; 592 593 /* 594 * Audit session events are always generated because they are used 595 * by some userland consumers so just set the preselect flag. 596 */ 597 ar->k_ar_commit |= AR_PRESELECT_FILTER; 598 599 /* 600 * Populate the subject information. Note that the ruid, rgid, 601 * egid, and pid values are incorrect. We only need the auditinfo_addr 602 * information. 603 */ 604 ar->k_ar.ar_subj_ruid = 0; 605 ar->k_ar.ar_subj_rgid = 0; 606 ar->k_ar.ar_subj_egid = 0; 607 ar->k_ar.ar_subj_pid = 0; 608 ar->k_ar.ar_subj_auid = aia_p->ai_auid; 609 ar->k_ar.ar_subj_asid = aia_p->ai_asid; 610 bcopy(&aia_p->ai_termid, &ar->k_ar.ar_subj_term_addr, 611 sizeof(struct au_tid_addr)); 612 613 /* Add the audit masks to the record. */ 614 ar->k_ar.ar_arg_amask.am_success = aia_p->ai_mask.am_success; 615 ar->k_ar.ar_arg_amask.am_failure = aia_p->ai_mask.am_failure; 616 ARG_SET_VALID(ar, ARG_AMASK); 617 618 /* Add the audit session flags to the record. */ 619 ar->k_ar.ar_arg_value64 = aia_p->ai_flags; 620 ARG_SET_VALID(ar, ARG_VALUE64); 621 622 623 /* Commit the record to the queue. */ 624 audit_commit(ar, 0, 0); 625} 626 627/* 628 * Hash the audit session ID using a simple 32-bit mix. 629 */ 630static inline uint32_t 631audit_session_hash(au_asid_t asid) 632{ 633 uint32_t a = (uint32_t) asid; 634 635 a = (a - (a << 6)) ^ (a >> 17); 636 a = (a - (a << 9)) ^ (a << 4); 637 a = (a - (a << 3)) ^ (a << 10); 638 a = a ^ (a >> 15); 639 640 return (a); 641} 642 643/* 644 * Do an hash lookup and find the session entry for a given ASID. Return NULL 645 * if not found. If the session is found then audit_session_find takes a 646 * reference. 647 */ 648static au_sentry_t * 649audit_session_find(au_asid_t asid) 650{ 651 uint32_t hkey; 652 au_sentry_t *found_se; 653 654 AUDIT_SENTRY_RWLOCK_ASSERT(); 655 656 hkey = HASH_ASID(asid); 657 658 LIST_FOREACH(found_se, &au_sentry_bucket[hkey], se_link) 659 if (found_se->se_asid == asid) { 660 au_history_record(found_se, AU_HISTORY_EVENT_FIND); 661 audit_ref_session(found_se); 662 return (found_se); 663 } 664 return (NULL); 665} 666 667/* 668 * Remove the given audit_session entry from the hash table. 669 */ 670static void 671audit_session_remove(au_sentry_t *se) 672{ 673 uint32_t hkey; 674 au_sentry_t *found_se, *tmp_se; 675 676 au_history_record(se, AU_HISTORY_EVENT_DEATH); 677 KASSERT(se->se_refcnt == 0, ("audit_session_remove: ref count != 0")); 678 KASSERT(se != &audit_default_se, 679 ("audit_session_remove: removing default session")); 680 681 hkey = HASH_ASID(se->se_asid); 682 683 AUDIT_SENTRY_WLOCK(); 684 /* 685 * Check and see if someone got a reference before we got the lock. 686 */ 687 if (se->se_refcnt != 0) { 688 AUDIT_SENTRY_WUNLOCK(); 689 return; 690 } 691 692 audit_session_portdestroy(&se->se_port); 693 LIST_FOREACH_SAFE(found_se, &au_sentry_bucket[hkey], se_link, tmp_se) { 694 if (found_se == se) { 695 696 /* 697 * Generate an audit event to notify userland of the 698 * session close. 699 */ 700 audit_session_event(AUE_SESSION_CLOSE, 701 &found_se->se_auinfo); 702 703 LIST_REMOVE(found_se, se_link); 704 AUDIT_SENTRY_WUNLOCK(); 705 free(found_se, M_AU_SESSION); 706 707 return; 708 } 709 } 710 AUDIT_SENTRY_WUNLOCK(); 711} 712 713/* 714 * Reference the session by incrementing the sentry ref count. 715 */ 716static void 717audit_ref_session(au_sentry_t *se) 718{ 719 long old_val; 720 721 if (se == NULL || se == &audit_default_se) 722 return; 723 724 au_history_record(se, AU_HISTORY_EVENT_REF); 725 726 old_val = OSAddAtomicLong(1, &se->se_refcnt); 727 KASSERT(old_val < 100000, 728 ("audit_ref_session: Too many references on session.")); 729} 730 731/* 732 * Decrement the sentry ref count and remove the session entry if last one. 733 */ 734static void 735audit_unref_session(au_sentry_t *se) 736{ 737 long old_val; 738 739 if (se == NULL || se == &audit_default_se) 740 return; 741 742 au_history_record(se, AU_HISTORY_EVENT_UNREF); 743 744 old_val = OSAddAtomicLong(-1, &se->se_refcnt); 745 if (old_val == 1) 746 audit_session_remove(se); 747 KASSERT(old_val > 0, 748 ("audit_unref_session: Too few references on session.")); 749} 750 751/* 752 * Increment the process count in the session. 753 */ 754static void 755audit_inc_procount(au_sentry_t *se) 756{ 757 long old_val; 758 759 if (se == NULL || se == &audit_default_se) 760 return; 761 762 old_val = OSAddAtomicLong(1, &se->se_procnt); 763 KASSERT(old_val <= PID_MAX, 764 ("audit_inc_procount: proc count > PID_MAX")); 765} 766 767/* 768 * Decrement the process count and add a knote if it is the last process 769 * to exit the session. 770 */ 771static void 772audit_dec_procount(au_sentry_t *se) 773{ 774 long old_val; 775 776 if (se == NULL || se == &audit_default_se) 777 return; 778 779 old_val = OSAddAtomicLong(-1, &se->se_procnt); 780 /* 781 * If this was the last process generate an audit event to notify 782 * userland of the session ending. 783 */ 784 if (old_val == 1) 785 audit_session_event(AUE_SESSION_END, &se->se_auinfo); 786 KASSERT(old_val >= 1, 787 ("audit_dec_procount: proc count < 0")); 788} 789 790/* 791 * Update the session entry and check to see if anything was updated. 792 * Returns: 793 * 0 Nothing was updated (We don't care about process preselection masks) 794 * 1 Something was updated. 795 */ 796static int 797audit_update_sentry(au_sentry_t *se, auditinfo_addr_t *new_aia) 798{ 799 auditinfo_addr_t *aia = &se->se_auinfo; 800 int update; 801 802 KASSERT(new_aia != audit_default_aia_p, 803 ("audit_update_sentry: Trying to update the default aia.")); 804 805 update = (aia->ai_auid != new_aia->ai_auid || 806 bcmp(&aia->ai_termid, &new_aia->ai_termid, 807 sizeof(new_aia->ai_termid)) || 808 aia->ai_flags != new_aia->ai_flags); 809 810 if (update) 811 bcopy(new_aia, aia, sizeof(*aia)); 812 813 return (update); 814} 815 816/* 817 * Return the next session ID. The range of kernel generated audit session IDs 818 * is ASSIGNED_ASID_MIN to ASSIGNED_ASID_MAX. 819 */ 820static uint32_t 821audit_session_nextid(void) 822{ 823 static uint32_t next_asid = ASSIGNED_ASID_MIN; 824 825 AUDIT_SENTRY_RWLOCK_ASSERT(); 826 827 if (next_asid > ASSIGNED_ASID_MAX) 828 next_asid = ASSIGNED_ASID_MIN; 829 830 return (next_asid++); 831} 832 833/* 834 * Allocated a new audit_session entry and add it to the hash table. If the 835 * given ASID is set to AU_ASSIGN_ASID then audit_session_new() will pick an 836 * audit session ID. Otherwise, it attempts use the one given. It creates a 837 * reference to the entry that must be unref'ed. 838 */ 839static auditinfo_addr_t * 840audit_session_new(auditinfo_addr_t *new_aia_p, auditinfo_addr_t *old_aia_p) 841{ 842 au_asid_t new_asid; 843 au_sentry_t *se = NULL; 844 au_sentry_t *found_se = NULL; 845 auditinfo_addr_t *aia = NULL; 846 847 KASSERT(new_aia_p != NULL, ("audit_session_new: new_aia_p == NULL")); 848 849 new_asid = new_aia_p->ai_asid; 850 851 /* 852 * Alloc a new session entry now so we don't wait holding the lock. 853 */ 854 se = malloc(sizeof(au_sentry_t), M_AU_SESSION, M_WAITOK | M_ZERO); 855 856 /* 857 * Find an unique session ID, if desired. 858 */ 859 AUDIT_SENTRY_WLOCK(); 860 if (new_asid == AU_ASSIGN_ASID) { 861 do { 862 863 new_asid = (au_asid_t)audit_session_nextid(); 864 found_se = audit_session_find(new_asid); 865 866 /* 867 * If the session ID is currently active then drop the 868 * reference and try again. 869 */ 870 if (found_se != NULL) 871 audit_unref_session(found_se); 872 else 873 break; 874 } while(1); 875 } else { 876 877 /* 878 * Check to see if the requested ASID is already in the 879 * hash table. If so, update it with the new auditinfo. 880 */ 881 if ((found_se = audit_session_find(new_asid)) != NULL) { 882 int updated; 883 884 updated = audit_update_sentry(found_se, new_aia_p); 885 886 AUDIT_SENTRY_WUNLOCK(); 887 free(se, M_AU_SESSION); 888 889 /* If a different session then add this process in. */ 890 if (new_aia_p != old_aia_p) 891 audit_inc_procount(found_se); 892 893 /* 894 * If the session information was updated then 895 * generate an audit event to notify userland. 896 */ 897 if (updated) 898 audit_session_event(AUE_SESSION_UPDATE, 899 &found_se->se_auinfo); 900 901 return (&found_se->se_auinfo); 902 } 903 } 904 905 /* 906 * Start the reference and proc count at 1 to account for the process 907 * that invoked this via setaudit_addr() (or friends). 908 */ 909 se->se_refcnt = se->se_procnt = 1; 910 911 /* 912 * Populate the new session entry. Note that process masks are stored 913 * in kauth ucred so just zero them here. 914 */ 915 se->se_port = IPC_PORT_NULL; 916 aia = &se->se_auinfo; 917 aia->ai_asid = new_asid; 918 aia->ai_auid = new_aia_p->ai_auid; 919 bzero(&new_aia_p->ai_mask, sizeof(new_aia_p->ai_mask)); 920 bcopy(&new_aia_p->ai_termid, &aia->ai_termid, sizeof(aia->ai_termid)); 921 aia->ai_flags = new_aia_p->ai_flags; 922 923 /* 924 * Add it to the hash table. 925 */ 926 LIST_INSERT_HEAD(&au_sentry_bucket[HASH_ASID(new_asid)], se, se_link); 927 AUDIT_SENTRY_WUNLOCK(); 928 929 /* 930 * Generate an audit event to notify userland of the new session. 931 */ 932 audit_session_event(AUE_SESSION_START, aia); 933 au_history_record(se, AU_HISTORY_EVENT_BIRTH); 934 return (aia); 935} 936 937/* 938 * Lookup an existing session. A copy of the audit session info for a given 939 * ASID is returned in ret_aia. Returns 0 on success. 940 */ 941int 942audit_session_lookup(au_asid_t asid, auditinfo_addr_t *ret_aia) 943{ 944 au_sentry_t *se = NULL; 945 946 if ((uint32_t)asid > ASSIGNED_ASID_MAX) 947 return (-1); 948 AUDIT_SENTRY_RLOCK(); 949 if ((se = audit_session_find(asid)) == NULL) { 950 AUDIT_SENTRY_RUNLOCK(); 951 return (1); 952 } 953 /* We have a reference on the session so it is safe to drop the lock. */ 954 AUDIT_SENTRY_RUNLOCK(); 955 if (ret_aia != NULL) 956 bcopy(&se->se_auinfo, ret_aia, sizeof(*ret_aia)); 957 audit_unref_session(se); 958 959 return (0); 960} 961 962void 963audit_session_aiaref(auditinfo_addr_t *aia_p) 964{ 965 966 audit_ref_session(AU_SENTRY_PTR(aia_p)); 967} 968 969/* 970 * Add a reference to the session entry. 971 */ 972void 973audit_session_ref(kauth_cred_t cred) 974{ 975 auditinfo_addr_t *aia_p; 976 977 KASSERT(IS_VALID_CRED(cred), 978 ("audit_session_ref: Invalid kauth_cred.")); 979 980 aia_p = cred->cr_audit.as_aia_p; 981 audit_session_aiaref(aia_p); 982} 983 984void audit_session_aiaunref(auditinfo_addr_t *aia_p) 985{ 986 987 audit_unref_session(AU_SENTRY_PTR(aia_p)); 988} 989 990/* 991 * Remove a reference to the session entry. 992 */ 993void 994audit_session_unref(kauth_cred_t cred) 995{ 996 auditinfo_addr_t *aia_p; 997 998 KASSERT(IS_VALID_CRED(cred), 999 ("audit_session_unref: Invalid kauth_cred.")); 1000 1001 aia_p = cred->cr_audit.as_aia_p; 1002 audit_session_aiaunref(aia_p); 1003} 1004 1005/* 1006 * Increment the per audit session process count. Assumes that the caller has 1007 * a reference on the process' cred. 1008 */ 1009void 1010audit_session_procnew(proc_t p) 1011{ 1012 kauth_cred_t cred = p->p_ucred; 1013 auditinfo_addr_t *aia_p; 1014 1015 KASSERT(IS_VALID_CRED(cred), 1016 ("audit_session_procnew: Invalid kauth_cred.")); 1017 1018 aia_p = cred->cr_audit.as_aia_p; 1019 1020 audit_inc_procount(AU_SENTRY_PTR(aia_p)); 1021} 1022 1023/* 1024 * Decrement the per audit session process count. Assumes that the caller has 1025 * a reference on the cred. 1026 */ 1027void 1028audit_session_procexit(proc_t p) 1029{ 1030 kauth_cred_t cred = p->p_ucred; 1031 auditinfo_addr_t *aia_p; 1032 1033 KASSERT(IS_VALID_CRED(cred), 1034 ("audit_session_procexit: Invalid kauth_cred.")); 1035 1036 aia_p = cred->cr_audit.as_aia_p; 1037 1038 audit_dec_procount(AU_SENTRY_PTR(aia_p)); 1039} 1040 1041/* 1042 * Init the audit session code. 1043 */ 1044void 1045audit_session_init(void) 1046{ 1047 int i; 1048 1049 KASSERT((ASSIGNED_ASID_MAX - ASSIGNED_ASID_MIN) > PID_MAX, 1050 ("audit_session_init: ASSIGNED_ASID_MAX is not large enough.")); 1051 1052 AUDIT_SENTRY_RWLOCK_INIT(); 1053 1054 au_sentry_bucket = malloc( sizeof(struct au_sentry) * 1055 HASH_TABLE_SIZE, M_AU_SESSION, M_WAITOK | M_ZERO); 1056 1057 for (i = 0; i < HASH_TABLE_SIZE; i++) 1058 LIST_INIT(&au_sentry_bucket[i]); 1059 1060 (void)audit_sdev_init(); 1061#if AU_HISTORY_LOGGING 1062 au_history = malloc(sizeof(struct au_history) * au_history_size, 1063 M_AU_SESSION, M_WAITOK|M_ZERO); 1064#endif 1065} 1066 1067static int 1068audit_session_update_check(kauth_cred_t cred, auditinfo_addr_t *old, 1069 auditinfo_addr_t *new) 1070{ 1071 uint64_t n; 1072 1073 /* If the current audit ID is not the default then it is immutable. */ 1074 if (old->ai_auid != AU_DEFAUDITID && old->ai_auid != new->ai_auid) 1075 return (EINVAL); 1076 1077 /* If the current termid is not the default then it is immutable. */ 1078 if ((old->ai_termid.at_type != AU_IPv4 || 1079 old->ai_termid.at_port != 0 || 1080 old->ai_termid.at_addr[0] != 0) && 1081 (old->ai_termid.at_port != new->ai_termid.at_port || 1082 old->ai_termid.at_type != new->ai_termid.at_type || 1083 0 != bcmp(&old->ai_termid.at_addr, &new->ai_termid.at_addr, 1084 sizeof (old->ai_termid.at_addr)))) 1085 return (EINVAL); 1086 1087 /* The flags may be set only according to the 1088 * audit_session_*_set_sflags_masks. 1089 */ 1090 n = ~old->ai_flags & new->ai_flags; 1091 if (0 != n && 1092 !((n == (audit_session_superuser_set_sflags_mask & n) && 1093 kauth_cred_issuser(cred)) || 1094 (n == (audit_session_member_set_sflags_mask & n) && 1095 old->ai_asid == new->ai_asid))) 1096 return (EINVAL); 1097 1098 /* The flags may be cleared only according to the 1099 * audit_session_*_clear_sflags_masks. 1100 */ 1101 n = ~new->ai_flags & old->ai_flags; 1102 if (0 != n && 1103 !((n == (audit_session_superuser_clear_sflags_mask & n) && 1104 kauth_cred_issuser(cred)) || 1105 (n == (audit_session_member_clear_sflags_mask & n) && 1106 old->ai_asid == new->ai_asid))) 1107 return (EINVAL); 1108 1109 /* The audit masks are mutable. */ 1110 return (0); 1111} 1112 1113/* 1114 * Safely update kauth cred of the given process with new the given audit info. 1115 */ 1116int 1117audit_session_setaia(proc_t p, auditinfo_addr_t *new_aia_p) 1118{ 1119 kauth_cred_t my_cred, my_new_cred; 1120 struct au_session as; 1121 struct au_session tmp_as; 1122 auditinfo_addr_t caia, *old_aia_p; 1123 int ret; 1124 1125 /* 1126 * If this is going to modify an existing session then do some 1127 * immutable checks. 1128 */ 1129 if (audit_session_lookup(new_aia_p->ai_asid, &caia) == 0) { 1130 my_cred = kauth_cred_proc_ref(p); 1131 ret = audit_session_update_check(my_cred, &caia, new_aia_p); 1132 kauth_cred_unref(&my_cred); 1133 if (ret) 1134 return (ret); 1135 } 1136 1137 my_cred = kauth_cred_proc_ref(p); 1138 bcopy(&new_aia_p->ai_mask, &as.as_mask, sizeof(as.as_mask)); 1139 old_aia_p = my_cred->cr_audit.as_aia_p; 1140 /* audit_session_new() adds a reference on the session */ 1141 as.as_aia_p = audit_session_new(new_aia_p, old_aia_p); 1142 1143 /* If the process left a session then update the process count. */ 1144 if (old_aia_p != new_aia_p) 1145 audit_dec_procount(AU_SENTRY_PTR(old_aia_p)); 1146 1147 1148 /* 1149 * We are modifying the audit info in a credential so we need a new 1150 * credential (or take another reference on an existing credential that 1151 * matches our new one). We must do this because the audit info in the 1152 * credential is used as part of our hash key. Get current credential 1153 * in the target process and take a reference while we muck with it. 1154 */ 1155 for (;;) { 1156 1157 /* 1158 * Set the credential with new info. If there is no change, 1159 * we get back the same credential we passed in; if there is 1160 * a change, we drop the reference on the credential we 1161 * passed in. The subsequent compare is safe, because it is 1162 * a pointer compare rather than a contents compare. 1163 */ 1164 bcopy(&as, &tmp_as, sizeof(tmp_as)); 1165 my_new_cred = kauth_cred_setauditinfo(my_cred, &tmp_as); 1166 1167 if (my_cred != my_new_cred) { 1168 proc_lock(p); 1169 /* Need to protect for a race where another thread also 1170 * changed the credential after we took our reference. 1171 * If p_ucred has changed then we should restart this 1172 * again with the new cred. 1173 */ 1174 if (p->p_ucred != my_cred) { 1175 proc_unlock(p); 1176 audit_session_unref(my_new_cred); 1177 kauth_cred_unref(&my_new_cred); 1178 /* try again */ 1179 my_cred = kauth_cred_proc_ref(p); 1180 continue; 1181 } 1182 p->p_ucred = my_new_cred; 1183 /* update cred on proc */ 1184 PROC_UPDATE_CREDS_ONPROC(p); 1185 proc_unlock(p); 1186 } 1187 /* 1188 * Drop old proc reference or our extra reference. 1189 */ 1190 kauth_cred_unref(&my_cred); 1191 break; 1192 } 1193 1194 /* Drop the reference taken by audit_session_new() above. */ 1195 audit_unref_session(AU_SENTRY_PTR(as.as_aia_p)); 1196 1197 /* Propagate the change from the process to the Mach task. */ 1198 set_security_token(p); 1199 1200 return (0); 1201} 1202 1203/* 1204 * audit_session_self (system call) 1205 * 1206 * Description: Obtain a Mach send right for the current session. 1207 * 1208 * Parameters: p Process calling audit_session_self(). 1209 * 1210 * Returns: *ret_port Named Mach send right, which may be 1211 * MACH_PORT_NULL in the failure case. 1212 * 1213 * Errno: 0 Success 1214 * EINVAL The calling process' session has not be set. 1215 * ESRCH Bad process, can't get valid cred for process. 1216 * ENOMEM Port allocation failed due to no free memory. 1217 */ 1218int 1219audit_session_self(proc_t p, __unused struct audit_session_self_args *uap, 1220 mach_port_name_t *ret_port) 1221{ 1222 ipc_port_t sendport = IPC_PORT_NULL; 1223 kauth_cred_t cred = NULL; 1224 auditinfo_addr_t *aia_p; 1225 au_sentry_t *se; 1226 int err = 0; 1227 1228 cred = kauth_cred_proc_ref(p); 1229 if (!IS_VALID_CRED(cred)) { 1230 err = ESRCH; 1231 goto done; 1232 } 1233 1234 aia_p = cred->cr_audit.as_aia_p; 1235 if (!IS_VALID_SESSION(aia_p)) { 1236 /* Can't join the default session. */ 1237 err = EINVAL; 1238 goto done; 1239 } 1240 1241 se = AU_SENTRY_PTR(aia_p); 1242 1243 /* 1244 * Processes that join using this mach port will inherit this process' 1245 * pre-selection masks. 1246 */ 1247 if (se->se_port == IPC_PORT_NULL) 1248 bcopy(&cred->cr_audit.as_mask, &se->se_mask, 1249 sizeof(se->se_mask)); 1250 1251 /* 1252 * Get a send right to the session's Mach port and insert it in the 1253 * process' mach port namespace. 1254 */ 1255 sendport = audit_session_mksend(aia_p, &se->se_port); 1256 *ret_port = ipc_port_copyout_send(sendport, get_task_ipcspace(p->task)); 1257 1258done: 1259 if (cred != NULL) 1260 kauth_cred_unref(&cred); 1261 if (err != 0) 1262 *ret_port = MACH_PORT_NULL; 1263 return (err); 1264} 1265 1266/* 1267 * audit_session_port (system call) 1268 * 1269 * Description: Obtain a Mach send right for the given session ID. 1270 * 1271 * Parameters: p Process calling audit_session_port(). 1272 * uap->asid The target audit session ID. The special 1273 * value -1 can be used to target the process's 1274 * own session. 1275 * uap->portnamep User address at which to place port name. 1276 * 1277 * Returns: 0 Success 1278 * EINVAL The calling process' session has not be set. 1279 * EINVAL The given session ID could not be found. 1280 * EINVAL The Mach port right could not be copied out. 1281 * ESRCH Bad process, can't get valid cred for process. 1282 * EPERM Only the superuser can reference sessions other 1283 * than the process's own. 1284 * ENOMEM Port allocation failed due to no free memory. 1285 */ 1286int 1287audit_session_port(proc_t p, struct audit_session_port_args *uap, 1288 __unused int *retval) 1289{ 1290 ipc_port_t sendport = IPC_PORT_NULL; 1291 mach_port_name_t portname = MACH_PORT_NULL; 1292 kauth_cred_t cred = NULL; 1293 auditinfo_addr_t *aia_p = NULL; 1294 au_sentry_t *se = NULL; 1295 int err = 0; 1296 1297 /* Note: Currently this test will never be true, because 1298 * ASSIGNED_ASID_MAX is effectively (uint32_t)-2. 1299 */ 1300 if (uap->asid != -1 && (uint32_t)uap->asid > ASSIGNED_ASID_MAX) { 1301 err = EINVAL; 1302 goto done; 1303 } 1304 cred = kauth_cred_proc_ref(p); 1305 if (!IS_VALID_CRED(cred)) { 1306 err = ESRCH; 1307 goto done; 1308 } 1309 aia_p = cred->cr_audit.as_aia_p; 1310 1311 /* Find the session corresponding to the requested audit 1312 * session ID. If found, take a reference on it so that 1313 * the session is not dropped until the join is later done. 1314 */ 1315 if (uap->asid == (au_asid_t)-1 || 1316 uap->asid == aia_p->ai_asid) { 1317 1318 if (!IS_VALID_SESSION(aia_p)) { 1319 /* Can't join the default session. */ 1320 err = EINVAL; 1321 goto done; 1322 } 1323 1324 /* No privilege is required to obtain a port for our 1325 * own session. 1326 */ 1327 se = AU_SENTRY_PTR(aia_p); 1328 audit_ref_session(se); 1329 } else if (kauth_cred_issuser(cred)) { 1330 /* The superuser may obtain a port for any existing 1331 * session. 1332 */ 1333 AUDIT_SENTRY_RLOCK(); 1334 se = audit_session_find(uap->asid); 1335 AUDIT_SENTRY_RUNLOCK(); 1336 if (NULL == se) { 1337 err = EINVAL; 1338 goto done; 1339 } 1340 aia_p = &se->se_auinfo; 1341 } else { 1342 err = EPERM; 1343 goto done; 1344 } 1345 1346 /* 1347 * Processes that join using this mach port will inherit this process' 1348 * pre-selection masks. 1349 */ 1350 if (se->se_port == IPC_PORT_NULL) 1351 bcopy(&cred->cr_audit.as_mask, &se->se_mask, 1352 sizeof(se->se_mask)); 1353 1354 /* 1355 * Use the session reference to create a mach port reference for the 1356 * session (at which point we are free to drop the session reference) 1357 * and then copy out the mach port to the process' mach port namespace. 1358 */ 1359 sendport = audit_session_mksend(aia_p, &se->se_port); 1360 portname = ipc_port_copyout_send(sendport, get_task_ipcspace(p->task)); 1361 if (!MACH_PORT_VALID(portname)) { 1362 err = EINVAL; 1363 goto done; 1364 } 1365 err = copyout(&portname, uap->portnamep, sizeof(mach_port_name_t)); 1366done: 1367 if (cred != NULL) 1368 kauth_cred_unref(&cred); 1369 if (NULL != se) 1370 audit_unref_session(se); 1371 if (MACH_PORT_VALID(portname) && 0 != err) 1372 (void)mach_port_deallocate(get_task_ipcspace(p->task), 1373 portname); 1374 1375 return (err); 1376} 1377 1378static int 1379audit_session_join_internal(proc_t p, ipc_port_t port, au_asid_t *new_asid) 1380{ 1381 auditinfo_addr_t *new_aia_p, *old_aia_p; 1382 kauth_cred_t my_cred = NULL; 1383 au_asid_t old_asid; 1384 int err = 0; 1385 1386 *new_asid = AU_DEFAUDITSID; 1387 1388 if ((new_aia_p = audit_session_porttoaia(port)) == NULL) { 1389 err = EINVAL; 1390 goto done; 1391 } 1392 1393 proc_lock(p); 1394 kauth_cred_ref(p->p_ucred); 1395 my_cred = p->p_ucred; 1396 if (!IS_VALID_CRED(my_cred)) { 1397 kauth_cred_unref(&my_cred); 1398 proc_unlock(p); 1399 err = ESRCH; 1400 goto done; 1401 } 1402 old_aia_p = my_cred->cr_audit.as_aia_p; 1403 old_asid = old_aia_p->ai_asid; 1404 *new_asid = new_aia_p->ai_asid; 1405 1406 /* 1407 * Add process in if not already in the session. 1408 */ 1409 if (*new_asid != old_asid) { 1410 kauth_cred_t my_new_cred; 1411 struct au_session new_as; 1412 1413 bcopy(&new_aia_p->ai_mask, &new_as.as_mask, 1414 sizeof(new_as.as_mask)); 1415 new_as.as_aia_p = new_aia_p; 1416 1417 my_new_cred = kauth_cred_setauditinfo(my_cred, &new_as); 1418 p->p_ucred = my_new_cred; 1419 PROC_UPDATE_CREDS_ONPROC(p); 1420 1421 /* Increment the proc count of new session */ 1422 audit_inc_procount(AU_SENTRY_PTR(new_aia_p)); 1423 1424 proc_unlock(p); 1425 1426 /* Propagate the change from the process to the Mach task. */ 1427 set_security_token(p); 1428 1429 /* Decrement the process count of the former session. */ 1430 audit_dec_procount(AU_SENTRY_PTR(old_aia_p)); 1431 } else { 1432 proc_unlock(p); 1433 } 1434 kauth_cred_unref(&my_cred); 1435 1436done: 1437 if (port != IPC_PORT_NULL) 1438 ipc_port_release_send(port); 1439 1440 return (err); 1441} 1442 1443/* 1444 * audit_session_spawnjoin 1445 * 1446 * Description: posix_spawn() interface to audit_session_join_internal(). 1447 * 1448 * Returns: 0 Success 1449 * EINVAL Invalid Mach port name. 1450 * ESRCH Invalid calling process/cred. 1451 */ 1452int 1453audit_session_spawnjoin(proc_t p, ipc_port_t port) 1454{ 1455 au_asid_t new_asid; 1456 1457 return (audit_session_join_internal(p, port, &new_asid)); 1458} 1459 1460/* 1461 * audit_session_join (system call) 1462 * 1463 * Description: Join the session for a given Mach port send right. 1464 * 1465 * Parameters: p Process calling session join. 1466 * uap->port A Mach send right. 1467 * 1468 * Returns: *ret_asid Audit session ID of new session. 1469 * In the failure case the return value will be -1 1470 * and 'errno' will be set to a non-zero value 1471 * described below. 1472 * 1473 * Errno: 0 Success 1474 * EINVAL Invalid Mach port name. 1475 * ESRCH Invalid calling process/cred. 1476 */ 1477int 1478audit_session_join(proc_t p, struct audit_session_join_args *uap, 1479 au_asid_t *ret_asid) 1480{ 1481 ipc_port_t port = IPC_PORT_NULL; 1482 mach_port_name_t send = uap->port; 1483 int err = 0; 1484 1485 1486 if (ipc_object_copyin(get_task_ipcspace(p->task), send, 1487 MACH_MSG_TYPE_COPY_SEND, &port) != KERN_SUCCESS) { 1488 *ret_asid = AU_DEFAUDITSID; 1489 err = EINVAL; 1490 } else 1491 err = audit_session_join_internal(p, port, ret_asid); 1492 1493 return (err); 1494} 1495 1496/* 1497 * Audit session device. 1498 */ 1499 1500/* 1501 * Free an audit sdev entry. 1502 */ 1503static void 1504audit_sdev_entry_free(struct audit_sdev_entry *ase) 1505{ 1506 1507 free(ase->ase_record, M_AUDIT_SDEV_ENTRY); 1508 free(ase, M_AUDIT_SDEV_ENTRY); 1509} 1510 1511/* 1512 * Append individual record to a queue. Allocate queue-local buffer and 1513 * add to the queue. If the queue is full or we can't allocate memory, 1514 * drop the newest record. 1515 */ 1516static void 1517audit_sdev_append(struct audit_sdev *asdev, void *record, u_int record_len) 1518{ 1519 struct audit_sdev_entry *ase; 1520 1521 AUDIT_SDEV_LOCK_ASSERT(asdev); 1522 1523 if (asdev->asdev_qlen >= asdev->asdev_qlimit) { 1524 asdev->asdev_drops++; 1525 audit_sdev_drops++; 1526 return; 1527 } 1528 1529 ase = malloc(sizeof (*ase), M_AUDIT_SDEV_ENTRY, M_NOWAIT | M_ZERO); 1530 if (NULL == ase) { 1531 asdev->asdev_drops++; 1532 audit_sdev_drops++; 1533 return; 1534 } 1535 1536 ase->ase_record = malloc(record_len, M_AUDIT_SDEV_ENTRY, M_NOWAIT); 1537 if (NULL == ase->ase_record) { 1538 free(ase, M_AUDIT_SDEV_ENTRY); 1539 asdev->asdev_drops++; 1540 audit_sdev_drops++; 1541 return; 1542 } 1543 1544 bcopy(record, ase->ase_record, record_len); 1545 ase->ase_record_len = record_len; 1546 1547 TAILQ_INSERT_TAIL(&asdev->asdev_queue, ase, ase_queue); 1548 asdev->asdev_inserts++; 1549 asdev->asdev_qlen++; 1550 asdev->asdev_qbyteslen += ase->ase_record_len; 1551 selwakeup(&asdev->asdev_selinfo); 1552 if (asdev->asdev_flags & AUDIT_SDEV_ASYNC) 1553 pgsigio(asdev->asdev_sigio, SIGIO); 1554 1555 cv_broadcast(&asdev->asdev_cv); 1556} 1557 1558/* 1559 * Submit an audit record to be queued in the audit session device. 1560 */ 1561void 1562audit_sdev_submit(__unused au_id_t auid, __unused au_asid_t asid, void *record, 1563 u_int record_len) 1564{ 1565 struct audit_sdev *asdev; 1566 1567 /* 1568 * Lockless read to avoid lock overhead if sessio devices are not in 1569 * use. 1570 */ 1571 if (NULL == TAILQ_FIRST(&audit_sdev_list)) 1572 return; 1573 1574 AUDIT_SDEV_LIST_RLOCK(); 1575 TAILQ_FOREACH(asdev, &audit_sdev_list, asdev_list) { 1576 AUDIT_SDEV_LOCK(asdev); 1577 1578 /* 1579 * Only append to the sdev queue if the AUID and ASID match that 1580 * of the process that opened this session device or if the 1581 * ALLSESSIONS flag is set. 1582 */ 1583 if ((/* XXXss auid == asdev->asdev_auid && */ 1584 asid == asdev->asdev_asid) || 1585 (asdev->asdev_flags & AUDIT_SDEV_ALLSESSIONS) != 0) 1586 audit_sdev_append(asdev, record, record_len); 1587 AUDIT_SDEV_UNLOCK(asdev); 1588 } 1589 AUDIT_SDEV_LIST_RUNLOCK(); 1590 1591 /* Unlocked increment. */ 1592 audit_sdev_records++; 1593} 1594 1595/* 1596 * Allocate a new audit sdev. Connects the sdev, on succes, to the global 1597 * list and updates statistics. 1598 */ 1599static struct audit_sdev * 1600audit_sdev_alloc(void) 1601{ 1602 struct audit_sdev *asdev; 1603 1604 AUDIT_SDEV_LIST_WLOCK_ASSERT(); 1605 1606 asdev = malloc(sizeof (*asdev), M_AUDIT_SDEV, M_WAITOK | M_ZERO); 1607 if (NULL == asdev) 1608 return (NULL); 1609 1610 asdev->asdev_qlimit = AUDIT_SDEV_QLIMIT_DEFAULT; 1611 TAILQ_INIT(&asdev->asdev_queue); 1612 AUDIT_SDEV_LOCK_INIT(asdev); 1613 AUDIT_SDEV_SX_LOCK_INIT(asdev); 1614 cv_init(&asdev->asdev_cv, "audit_sdev_cv"); 1615 1616 /* 1617 * Add to global list and update global statistics. 1618 */ 1619 TAILQ_INSERT_HEAD(&audit_sdev_list, asdev, asdev_list); 1620 audit_sdev_count++; 1621 audit_sdev_ever++; 1622 1623 return (asdev); 1624} 1625 1626/* 1627 * Flush all records currently present in an audit sdev. 1628 */ 1629static void 1630audit_sdev_flush(struct audit_sdev *asdev) 1631{ 1632 struct audit_sdev_entry *ase; 1633 1634 AUDIT_SDEV_LOCK_ASSERT(asdev); 1635 1636 while ((ase = TAILQ_FIRST(&asdev->asdev_queue)) != NULL) { 1637 TAILQ_REMOVE(&asdev->asdev_queue, ase, ase_queue); 1638 asdev->asdev_qbyteslen -= ase->ase_record_len; 1639 audit_sdev_entry_free(ase); 1640 asdev->asdev_qlen--; 1641 } 1642 asdev->asdev_qoffset = 0; 1643 1644 KASSERT(0 == asdev->asdev_qlen, ("audit_sdev_flush: asdev_qlen")); 1645 KASSERT(0 == asdev->asdev_qbyteslen, 1646 ("audit_sdev_flush: asdev_qbyteslen")); 1647} 1648 1649/* 1650 * Free an audit sdev. 1651 */ 1652static void 1653audit_sdev_free(struct audit_sdev *asdev) 1654{ 1655 1656 AUDIT_SDEV_LIST_WLOCK_ASSERT(); 1657 AUDIT_SDEV_LOCK_ASSERT(asdev); 1658 1659 /* XXXss - preselect hook here */ 1660 audit_sdev_flush(asdev); 1661 cv_destroy(&asdev->asdev_cv); 1662 AUDIT_SDEV_SX_LOCK_DESTROY(asdev); 1663 AUDIT_SDEV_UNLOCK(asdev); 1664 AUDIT_SDEV_LOCK_DESTROY(asdev); 1665 1666 TAILQ_REMOVE(&audit_sdev_list, asdev, asdev_list); 1667 free(asdev, M_AUDIT_SDEV); 1668 audit_sdev_count--; 1669} 1670 1671/* 1672 * Get the auditinfo_addr of the proc and check to see if suser. Will return 1673 * non-zero if not suser. 1674 */ 1675static int 1676audit_sdev_get_aia(proc_t p, struct auditinfo_addr *aia_p) 1677{ 1678 int error; 1679 kauth_cred_t scred; 1680 1681 scred = kauth_cred_proc_ref(p); 1682 error = suser(scred, &p->p_acflag); 1683 1684 if (NULL != aia_p) 1685 bcopy(scred->cr_audit.as_aia_p, aia_p, sizeof (*aia_p)); 1686 kauth_cred_unref(&scred); 1687 1688 return (error); 1689} 1690 1691/* 1692 * Audit session dev open method. 1693 */ 1694static int 1695audit_sdev_open(dev_t dev, __unused int flags, __unused int devtype, proc_t p) 1696{ 1697 struct audit_sdev *asdev; 1698 struct auditinfo_addr aia; 1699 int u; 1700 1701 u = minor(dev); 1702 if (u < 0 || u > MAX_AUDIT_SDEVS) 1703 return (ENXIO); 1704 1705 (void) audit_sdev_get_aia(p, &aia); 1706 1707 AUDIT_SDEV_LIST_WLOCK(); 1708 asdev = audit_sdev_dtab[u]; 1709 if (NULL == asdev) { 1710 asdev = audit_sdev_alloc(); 1711 if (NULL == asdev) { 1712 AUDIT_SDEV_LIST_WUNLOCK(); 1713 return (ENOMEM); 1714 } 1715 audit_sdev_dtab[u] = asdev; 1716 } else { 1717 KASSERT(asdev->asdev_open, ("audit_sdev_open: Already open")); 1718 AUDIT_SDEV_LIST_WUNLOCK(); 1719 return (EBUSY); 1720 } 1721 asdev->asdev_open = 1; 1722 asdev->asdev_auid = aia.ai_auid; 1723 asdev->asdev_asid = aia.ai_asid; 1724 asdev->asdev_flags = 0; 1725 1726 AUDIT_SDEV_LIST_WUNLOCK(); 1727 1728 return (0); 1729} 1730 1731/* 1732 * Audit session dev close method. 1733 */ 1734static int 1735audit_sdev_close(dev_t dev, __unused int flags, __unused int devtype, 1736 __unused proc_t p) 1737{ 1738 struct audit_sdev *asdev; 1739 int u; 1740 1741 u = minor(dev); 1742 asdev = audit_sdev_dtab[u]; 1743 1744 KASSERT(asdev != NULL, ("audit_sdev_close: asdev == NULL")); 1745 KASSERT(asdev->asdev_open, ("audit_sdev_close: !asdev_open")); 1746 1747 AUDIT_SDEV_LIST_WLOCK(); 1748 AUDIT_SDEV_LOCK(asdev); 1749 asdev->asdev_open = 0; 1750 audit_sdev_free(asdev); /* sdev lock unlocked in audit_sdev_free() */ 1751 audit_sdev_dtab[u] = NULL; 1752 AUDIT_SDEV_LIST_WUNLOCK(); 1753 1754 return (0); 1755} 1756 1757/* 1758 * Audit session dev ioctl method. 1759 */ 1760static int 1761audit_sdev_ioctl(dev_t dev, u_long cmd, caddr_t data, 1762 __unused int flag, proc_t p) 1763{ 1764 struct audit_sdev *asdev; 1765 int error; 1766 1767 asdev = audit_sdev_dtab[minor(dev)]; 1768 KASSERT(asdev != NULL, ("audit_sdev_ioctl: asdev == NULL")); 1769 1770 error = 0; 1771 1772 switch (cmd) { 1773 case FIONBIO: 1774 AUDIT_SDEV_LOCK(asdev); 1775 if (*(int *)data) 1776 asdev->asdev_flags |= AUDIT_SDEV_NBIO; 1777 else 1778 asdev->asdev_flags &= ~AUDIT_SDEV_NBIO; 1779 AUDIT_SDEV_UNLOCK(asdev); 1780 break; 1781 1782 case FIONREAD: 1783 AUDIT_SDEV_LOCK(asdev); 1784 *(int *)data = asdev->asdev_qbyteslen - asdev->asdev_qoffset; 1785 AUDIT_SDEV_UNLOCK(asdev); 1786 break; 1787 1788 case AUDITSDEV_GET_QLEN: 1789 *(u_int *)data = asdev->asdev_qlen; 1790 break; 1791 1792 case AUDITSDEV_GET_QLIMIT: 1793 *(u_int *)data = asdev->asdev_qlimit; 1794 break; 1795 1796 case AUDITSDEV_SET_QLIMIT: 1797 if (*(u_int *)data >= AUDIT_SDEV_QLIMIT_MIN || 1798 *(u_int *)data <= AUDIT_SDEV_QLIMIT_MAX) { 1799 asdev->asdev_qlimit = *(u_int *)data; 1800 } else 1801 error = EINVAL; 1802 break; 1803 1804 case AUDITSDEV_GET_QLIMIT_MIN: 1805 *(u_int *)data = AUDIT_SDEV_QLIMIT_MIN; 1806 break; 1807 1808 case AUDITSDEV_GET_QLIMIT_MAX: 1809 *(u_int *)data = AUDIT_SDEV_QLIMIT_MAX; 1810 break; 1811 1812 case AUDITSDEV_FLUSH: 1813 if (AUDIT_SDEV_SX_XLOCK_SIG(asdev) != 0) 1814 return (EINTR); 1815 AUDIT_SDEV_LOCK(asdev); 1816 audit_sdev_flush(asdev); 1817 AUDIT_SDEV_UNLOCK(asdev); 1818 AUDIT_SDEV_SX_XUNLOCK(asdev); 1819 break; 1820 1821 case AUDITSDEV_GET_MAXDATA: 1822 *(u_int *)data = MAXAUDITDATA; 1823 break; 1824 1825 /* XXXss these should be 64 bit, maybe. */ 1826 case AUDITSDEV_GET_INSERTS: 1827 *(u_int *)data = asdev->asdev_inserts; 1828 break; 1829 1830 case AUDITSDEV_GET_READS: 1831 *(u_int *)data = asdev->asdev_reads; 1832 break; 1833 1834 case AUDITSDEV_GET_DROPS: 1835 *(u_int *)data = asdev->asdev_drops; 1836 break; 1837 1838 case AUDITSDEV_GET_ALLSESSIONS: 1839 error = audit_sdev_get_aia(p, NULL); 1840 if (error) 1841 break; 1842 *(u_int *)data = (asdev->asdev_flags & AUDIT_SDEV_ALLSESSIONS) ? 1843 1 : 0; 1844 break; 1845 1846 case AUDITSDEV_SET_ALLSESSIONS: 1847 error = audit_sdev_get_aia(p, NULL); 1848 if (error) 1849 break; 1850 1851 AUDIT_SDEV_LOCK(asdev); 1852 if (*(int *)data) 1853 asdev->asdev_flags |= AUDIT_SDEV_ALLSESSIONS; 1854 else 1855 asdev->asdev_flags &= ~AUDIT_SDEV_ALLSESSIONS; 1856 AUDIT_SDEV_UNLOCK(asdev); 1857 break; 1858 1859 default: 1860 error = ENOTTY; 1861 } 1862 1863 return (error); 1864} 1865 1866/* 1867 * Audit session dev read method. 1868 */ 1869static int 1870audit_sdev_read(dev_t dev, struct uio *uio, __unused int flag) 1871{ 1872 struct audit_sdev_entry *ase; 1873 struct audit_sdev *asdev; 1874 u_int toread; 1875 int error; 1876 1877 asdev = audit_sdev_dtab[minor(dev)]; 1878 KASSERT(NULL != asdev, ("audit_sdev_read: asdev == NULL")); 1879 1880 /* 1881 * We hold a sleep lock over read and flush because we rely on the 1882 * stability of a record in the queue during uiomove. 1883 */ 1884 if (0 != AUDIT_SDEV_SX_XLOCK_SIG(asdev)) 1885 return (EINTR); 1886 AUDIT_SDEV_LOCK(asdev); 1887 while (TAILQ_EMPTY(&asdev->asdev_queue)) { 1888 if (asdev->asdev_flags & AUDIT_SDEV_NBIO) { 1889 AUDIT_SDEV_UNLOCK(asdev); 1890 AUDIT_SDEV_SX_XUNLOCK(asdev); 1891 return (EAGAIN); 1892 } 1893 error = cv_wait_sig(&asdev->asdev_cv, AUDIT_SDEV_MTX(asdev)); 1894 if (error) { 1895 AUDIT_SDEV_UNLOCK(asdev); 1896 AUDIT_SDEV_SX_XUNLOCK(asdev); 1897 return (error); 1898 } 1899 } 1900 1901 /* 1902 * Copy as many remaining bytes from the current record to userspace 1903 * as we can. Keep processing records until we run out of records in 1904 * the queue or until the user buffer runs out of space. 1905 * 1906 * We rely on the sleep lock to maintain ase's stability here. 1907 */ 1908 asdev->asdev_reads++; 1909 while ((ase = TAILQ_FIRST(&asdev->asdev_queue)) != NULL && 1910 uio_resid(uio) > 0) { 1911 AUDIT_SDEV_LOCK_ASSERT(asdev); 1912 1913 KASSERT(ase->ase_record_len > asdev->asdev_qoffset, 1914 ("audit_sdev_read: record_len > qoffset (1)")); 1915 toread = MIN((int)(ase->ase_record_len - asdev->asdev_qoffset), 1916 uio_resid(uio)); 1917 AUDIT_SDEV_UNLOCK(asdev); 1918 error = uiomove((char *) ase->ase_record + asdev->asdev_qoffset, 1919 toread, uio); 1920 if (error) { 1921 AUDIT_SDEV_SX_XUNLOCK(asdev); 1922 return (error); 1923 } 1924 1925 /* 1926 * If the copy succeeded then update book-keeping, and if no 1927 * bytes remain in the current record then free it. 1928 */ 1929 AUDIT_SDEV_LOCK(asdev); 1930 KASSERT(TAILQ_FIRST(&asdev->asdev_queue) == ase, 1931 ("audit_sdev_read: queue out of sync after uiomove")); 1932 asdev->asdev_qoffset += toread; 1933 KASSERT(ase->ase_record_len >= asdev->asdev_qoffset, 1934 ("audit_sdev_read: record_len >= qoffset (2)")); 1935 if (asdev->asdev_qoffset == ase->ase_record_len) { 1936 TAILQ_REMOVE(&asdev->asdev_queue, ase, ase_queue); 1937 asdev->asdev_qbyteslen -= ase->ase_record_len; 1938 audit_sdev_entry_free(ase); 1939 asdev->asdev_qlen--; 1940 asdev->asdev_qoffset = 0; 1941 } 1942 } 1943 AUDIT_SDEV_UNLOCK(asdev); 1944 AUDIT_SDEV_SX_XUNLOCK(asdev); 1945 return (0); 1946} 1947 1948/* 1949 * Audit session device poll method. 1950 */ 1951static int 1952audit_sdev_poll(dev_t dev, int events, void *wql, struct proc *p) 1953{ 1954 struct audit_sdev *asdev; 1955 int revents; 1956 1957 revents = 0; 1958 asdev = audit_sdev_dtab[minor(dev)]; 1959 KASSERT(NULL != asdev, ("audit_sdev_poll: asdev == NULL")); 1960 1961 if (events & (POLLIN | POLLRDNORM)) { 1962 AUDIT_SDEV_LOCK(asdev); 1963 if (NULL != TAILQ_FIRST(&asdev->asdev_queue)) 1964 revents |= events & (POLLIN | POLLRDNORM); 1965 else 1966 selrecord(p, &asdev->asdev_selinfo, wql); 1967 AUDIT_SDEV_UNLOCK(asdev); 1968 } 1969 return (revents); 1970} 1971 1972/* 1973 * Audit sdev clone routine. Provides a new minor number or returns -1. 1974 * This called with DEVFS_LOCK held. 1975 */ 1976static int 1977audit_sdev_clone(__unused dev_t dev, int action) 1978{ 1979 int i; 1980 1981 if (DEVFS_CLONE_ALLOC == action) { 1982 for(i = 0; i < MAX_AUDIT_SDEVS; i++) 1983 if (NULL == audit_sdev_dtab[i]) 1984 return (i); 1985 1986 /* 1987 * This really should return -1 here but that seems to 1988 * hang things in devfs. We instead return 0 and let 1989 * audit_sdev_open tell userland the bad news. 1990 */ 1991 return (0); 1992 } 1993 1994 return (-1); 1995} 1996 1997static int 1998audit_sdev_init(void) 1999{ 2000 dev_t dev; 2001 2002 TAILQ_INIT(&audit_sdev_list); 2003 AUDIT_SDEV_LIST_LOCK_INIT(); 2004 2005 audit_sdev_major = cdevsw_add(-1, &audit_sdev_cdevsw); 2006 if (audit_sdev_major < 0) 2007 return (KERN_FAILURE); 2008 2009 dev = makedev(audit_sdev_major, 0); 2010 devnode = devfs_make_node_clone(dev, DEVFS_CHAR, UID_ROOT, GID_WHEEL, 2011 0644, audit_sdev_clone, AUDIT_SDEV_NAME, 0); 2012 2013 if (NULL == devnode) 2014 return (KERN_FAILURE); 2015 2016 return (KERN_SUCCESS); 2017} 2018 2019/* XXXss 2020static int 2021audit_sdev_shutdown(void) 2022{ 2023 2024 devfs_remove(devnode); 2025 (void) cdevsw_remove(audit_sdev_major, &audit_sdev_cdevsw); 2026 2027 return (KERN_SUCCESS); 2028} 2029*/ 2030 2031#else 2032 2033int 2034audit_session_self(proc_t p, struct audit_session_self_args *uap, 2035 mach_port_name_t *ret_port) 2036{ 2037#pragma unused(p, uap, ret_port) 2038 2039 return (ENOSYS); 2040} 2041 2042int 2043audit_session_join(proc_t p, struct audit_session_join_args *uap, 2044 au_asid_t *ret_asid) 2045{ 2046#pragma unused(p, uap, ret_asid) 2047 2048 return (ENOSYS); 2049} 2050 2051int 2052audit_session_port(proc_t p, struct audit_session_port_args *uap, int *retval) 2053{ 2054#pragma unused(p, uap, retval) 2055 2056 return (ENOSYS); 2057} 2058 2059#endif /* CONFIG_AUDIT */ 2060