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