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
389extern int set_security_token_task_internal(proc_t p, void *task);
390
391#define AUDIT_SESSION_DEBUG 0
392#if AUDIT_SESSION_DEBUG
393/*
394 * The following is debugging code that can be used to get a snapshot of the
395 * session state. The audit session information is read out using sysctl:
396 *
397 * error = sysctlbyname("kern.audit_session_debug", buffer_ptr, &buffer_len,
398 * NULL, 0);
399 */
400#include <kern/kalloc.h>
401
402/*
403 * The per session record structure for the snapshot data.
404 */
405struct au_sentry_debug {
406 auditinfo_addr_t se_auinfo;
407 int64_t se_refcnt; /* refereence count */
408 int64_t se_procnt; /* process count */
409 int64_t se_ptcnt; /* process count from
410 proc table */
411};
412typedef struct au_sentry_debug au_sentry_debug_t;
413
414static int audit_sysctl_session_debug(struct sysctl_oid *oidp, void *arg1,
415 int arg2, struct sysctl_req *req);
416
417SYSCTL_PROC(_kern, OID_AUTO, audit_session_debug, CTLFLAG_RD | CTLFLAG_LOCKED,
418 NULL, 0, audit_sysctl_session_debug, "S,audit_session_debug",
419 "Current session debug info for auditing.");
420
421/*
422 * Callouts for proc_interate() which is used to reconcile the audit session
423 * proc state information with the proc table. We get everything we need
424 * in the filterfn while the proc_lock() is held so we really don't need the
425 * callout() function.
426 */
427static int
428audit_session_debug_callout(__unused proc_t p, __unused void *arg)
429{
430
431 return (PROC_RETURNED_DONE);
432}
433
434static int
435audit_session_debug_filterfn(proc_t p, void *st)
436{
437 kauth_cred_t cred = p->p_ucred;
438 auditinfo_addr_t *aia_p = cred->cr_audit.as_aia_p;
439 au_sentry_debug_t *sed_tab = (au_sentry_debug_t *) st;
440 au_sentry_debug_t *sdtp;
441 au_sentry_t *se;
442
443 if (IS_VALID_SESSION(aia_p)) {
444 sdtp = &sed_tab[0];
445 do {
446 if (aia_p->ai_asid == sdtp->se_asid) {
447 sdtp->se_ptcnt++;
448
449 /* Do some santy checks. */
450 se = AU_SENTRY_PTR(aia_p);
451 if (se->se_refcnt != sdtp->se_refcnt) {
452 sdtp->se_refcnt =
453 (int64_t)se->se_refcnt;
454 }
455 if (se->se_procnt != sdtp->se_procnt) {
456 sdtp->se_procnt =
457 (int64_t)se->se_procnt;
458 }
459 break;
460 }
461 sdtp++;
462 } while (sdtp->se_asid != 0 && sdtp->se_auid != 0);
463 } else {
464 /* add it to the default sesison */
465 sed_tab->se_ptcnt++;
466 }
467
468 return (0);
469}
470
471/*
472 * Copy out the session debug info via the sysctl interface.
473 *
474 */
475static int
476audit_sysctl_session_debug(__unused struct sysctl_oid *oidp,
477 __unused void *arg1, __unused int arg2, struct sysctl_req *req)
478{
479 au_sentry_t *se;
480 au_sentry_debug_t *sed_tab, *next_sed;
481 int i, entry_cnt = 0;
482 size_t sz;
483 int err = 0;
484
485 /*
486 * This provides a read-only node.
487 */
488 if (req->newptr != USER_ADDR_NULL)
489 return (EPERM);
490
491 /*
492 * Walk the audit session hash table to determine the size.
493 */
494 AUDIT_SENTRY_RLOCK();
495 for(i = 0; i < HASH_TABLE_SIZE; i++)
496 LIST_FOREACH(se, &au_sentry_bucket[i], se_link)
497 if (se != NULL)
498 entry_cnt++;
499
500 entry_cnt++; /* add one for the default entry */
501 /*
502 * If just querying then return the space required. There is an
503 * obvious race condition here so we just fudge this by 3 in case
504 * the audit session table grows.
505 */
506 if (req->oldptr == USER_ADDR_NULL) {
507 req->oldidx = (entry_cnt + 3) * sizeof(au_sentry_debug_t);
508 AUDIT_SENTRY_RUNLOCK();
509 return (0);
510 }
511
512 /*
513 * Alloc a temporary buffer.
514 */
515 if (req->oldlen < (entry_cnt * sizeof(au_sentry_debug_t))) {
516 AUDIT_SENTRY_RUNLOCK();
517 return (ENOMEM);
518 }
519 /*
520 * We hold the lock over the alloc since we don't want the table to
521 * grow on us. Therefore, use the non-blocking version of kalloc().
522 */
523 sed_tab = (au_sentry_debug_t *)kalloc_noblock(entry_cnt *
524 sizeof(au_sentry_debug_t));
525 if (sed_tab == NULL) {
526 AUDIT_SENTRY_RUNLOCK();
527 return (ENOMEM);
528 }
529 bzero(sed_tab, entry_cnt * sizeof(au_sentry_debug_t));
530
531 /*
532 * Walk the audit session hash table and build the record array.
533 */
534 sz = 0;
535 next_sed = sed_tab;
536 /* add the first entry for processes not tracked in sessions. */
537 bcopy(audit_default_aia_p, &next_sed->se_auinfo, sizeof (au_sentry_t));
538 next_sed->se_refcnt = (int64_t)audit_default_se.se_refcnt;
539 next_sed->se_procnt = (int64_t)audit_default_se.se_procnt;
540 next_sed++;
541 sz += sizeof(au_sentry_debug_t);
542 for(i = 0; i < HASH_TABLE_SIZE; i++) {
543 LIST_FOREACH(se, &au_sentry_bucket[i], se_link) {
544 if (se != NULL) {
545 next_sed->se_auinfo = se->se_auinfo;
546 next_sed->se_refcnt = (int64_t)se->se_refcnt;
547 next_sed->se_procnt = (int64_t)se->se_procnt;
548 next_sed++;
549 sz += sizeof(au_sentry_debug_t);
550 }
551 }
552 }
553 AUDIT_SENTRY_RUNLOCK();
554
555 /* Reconcile with the process table. */
556 (void) proc_iterate(PROC_ALLPROCLIST | PROC_ZOMBPROCLIST,
557 audit_session_debug_callout, NULL,
558 audit_session_debug_filterfn, (void *)&sed_tab[0]);
559
560
561 req->oldlen = sz;
562 err = SYSCTL_OUT(req, sed_tab, sz);
563 kfree(sed_tab, entry_cnt * sizeof(au_sentry_debug_t));
564
565 return (err);
566}
567
568#endif /* AUDIT_SESSION_DEBUG */
569
570/*
571 * Create and commit a session audit event. The proc and se arguments needs to
572 * be that of the subject and not necessarily the current process.
573 */
574static void
575audit_session_event(int event, auditinfo_addr_t *aia_p)
576{
577 struct kaudit_record *ar;
578
579 KASSERT(AUE_SESSION_START == event || AUE_SESSION_UPDATE == event ||
580 AUE_SESSION_END == event || AUE_SESSION_CLOSE == event,
581 ("audit_session_event: invalid event: %d", event));
582
583 if (NULL == aia_p)
584 return;
585
586 /*
587 * Create a new audit record. The record will contain the subject
588 * ruid, rgid, egid, pid, auid, asid, amask, and term_addr
589 * (implicitly added by audit_new).
590 */
591 ar = audit_new(event, PROC_NULL, /* Not used */ NULL);
592 if (NULL == ar)
593 return;
594
595 /*
596 * Audit session events are always generated because they are used
597 * by some userland consumers so just set the preselect flag.
598 */
599 ar->k_ar_commit |= AR_PRESELECT_FILTER;
600
601 /*
602 * Populate the subject information. Note that the ruid, rgid,
603 * egid, and pid values are incorrect. We only need the auditinfo_addr
604 * information.
605 */
606 ar->k_ar.ar_subj_ruid = 0;
607 ar->k_ar.ar_subj_rgid = 0;
608 ar->k_ar.ar_subj_egid = 0;
609 ar->k_ar.ar_subj_pid = 0;
610 ar->k_ar.ar_subj_auid = aia_p->ai_auid;
611 ar->k_ar.ar_subj_asid = aia_p->ai_asid;
612 bcopy(&aia_p->ai_termid, &ar->k_ar.ar_subj_term_addr,
613 sizeof(struct au_tid_addr));
614
615 /* Add the audit masks to the record. */
616 ar->k_ar.ar_arg_amask.am_success = aia_p->ai_mask.am_success;
617 ar->k_ar.ar_arg_amask.am_failure = aia_p->ai_mask.am_failure;
618 ARG_SET_VALID(ar, ARG_AMASK);
619
620 /* Add the audit session flags to the record. */
621 ar->k_ar.ar_arg_value64 = aia_p->ai_flags;
622 ARG_SET_VALID(ar, ARG_VALUE64);
623
624
625 /* Commit the record to the queue. */
626 audit_commit(ar, 0, 0);
627}
628
629/*
630 * Hash the audit session ID using a simple 32-bit mix.
631 */
632static inline uint32_t
633audit_session_hash(au_asid_t asid)
634{
635 uint32_t a = (uint32_t) asid;
636
637 a = (a - (a << 6)) ^ (a >> 17);
638 a = (a - (a << 9)) ^ (a << 4);
639 a = (a - (a << 3)) ^ (a << 10);
640 a = a ^ (a >> 15);
641
642 return (a);
643}
644
645/*
646 * Do an hash lookup and find the session entry for a given ASID. Return NULL
647 * if not found. If the session is found then audit_session_find takes a
648 * reference.
649 */
650static au_sentry_t *
651audit_session_find(au_asid_t asid)
652{
653 uint32_t hkey;
654 au_sentry_t *found_se;
655
656 AUDIT_SENTRY_RWLOCK_ASSERT();
657
658 hkey = HASH_ASID(asid);
659
660 LIST_FOREACH(found_se, &au_sentry_bucket[hkey], se_link)
661 if (found_se->se_asid == asid) {
662 au_history_record(found_se, AU_HISTORY_EVENT_FIND);
663 audit_ref_session(found_se);
664 return (found_se);
665 }
666 return (NULL);
667}
668
669/*
670 * Remove the given audit_session entry from the hash table.
671 */
672static void
673audit_session_remove(au_sentry_t *se)
674{
675 uint32_t hkey;
676 au_sentry_t *found_se, *tmp_se;
677
678 au_history_record(se, AU_HISTORY_EVENT_DEATH);
679 KASSERT(se->se_refcnt == 0, ("audit_session_remove: ref count != 0"));
680 KASSERT(se != &audit_default_se,
681 ("audit_session_remove: removing default session"));
682
683 hkey = HASH_ASID(se->se_asid);
684
685 AUDIT_SENTRY_WLOCK();
686 /*
687 * Check and see if someone got a reference before we got the lock.
688 */
689 if (se->se_refcnt != 0) {
690 AUDIT_SENTRY_WUNLOCK();
691 return;
692 }
693
694 audit_session_portdestroy(&se->se_port);
695 LIST_FOREACH_SAFE(found_se, &au_sentry_bucket[hkey], se_link, tmp_se) {
696 if (found_se == se) {
697
698 /*
699 * Generate an audit event to notify userland of the
700 * session close.
701 */
702 audit_session_event(AUE_SESSION_CLOSE,
703 &found_se->se_auinfo);
704
705 LIST_REMOVE(found_se, se_link);
706 AUDIT_SENTRY_WUNLOCK();
707 free(found_se, M_AU_SESSION);
708
709 return;
710 }
711 }
712 AUDIT_SENTRY_WUNLOCK();
713}
714
715/*
716 * Reference the session by incrementing the sentry ref count.
717 */
718static void
719audit_ref_session(au_sentry_t *se)
720{
721 long old_val;
722
723 if (se == NULL || se == &audit_default_se)
724 return;
725
726 au_history_record(se, AU_HISTORY_EVENT_REF);
727
728 old_val = OSAddAtomicLong(1, &se->se_refcnt);
729 KASSERT(old_val < 100000,
730 ("audit_ref_session: Too many references on session."));
731}
732
733/*
734 * Decrement the sentry ref count and remove the session entry if last one.
735 */
736static void
737audit_unref_session(au_sentry_t *se)
738{
739 long old_val;
740
741 if (se == NULL || se == &audit_default_se)
742 return;
743
744 au_history_record(se, AU_HISTORY_EVENT_UNREF);
745
746 old_val = OSAddAtomicLong(-1, &se->se_refcnt);
747 if (old_val == 1)
748 audit_session_remove(se);
749 KASSERT(old_val > 0,
750 ("audit_unref_session: Too few references on session."));
751}
752
753/*
754 * Increment the process count in the session.
755 */
756static void
757audit_inc_procount(au_sentry_t *se)
758{
759 long old_val;
760
761 if (se == NULL || se == &audit_default_se)
762 return;
763
764 old_val = OSAddAtomicLong(1, &se->se_procnt);
765 KASSERT(old_val <= PID_MAX,
766 ("audit_inc_procount: proc count > PID_MAX"));
767}
768
769/*
770 * Decrement the process count and add a knote if it is the last process
771 * to exit the session.
772 */
773static void
774audit_dec_procount(au_sentry_t *se)
775{
776 long old_val;
777
778 if (se == NULL || se == &audit_default_se)
779 return;
780
781 old_val = OSAddAtomicLong(-1, &se->se_procnt);
782 /*
783 * If this was the last process generate an audit event to notify
784 * userland of the session ending.
785 */
786 if (old_val == 1)
787 audit_session_event(AUE_SESSION_END, &se->se_auinfo);
788 KASSERT(old_val >= 1,
789 ("audit_dec_procount: proc count < 0"));
790}
791
792/*
793 * Update the session entry and check to see if anything was updated.
794 * Returns:
795 * 0 Nothing was updated (We don't care about process preselection masks)
796 * 1 Something was updated.
797 */
798static int
799audit_update_sentry(au_sentry_t *se, auditinfo_addr_t *new_aia)
800{
801 auditinfo_addr_t *aia = &se->se_auinfo;
802 int update;
803
804 KASSERT(new_aia != audit_default_aia_p,
805 ("audit_update_sentry: Trying to update the default aia."));
806
807 update = (aia->ai_auid != new_aia->ai_auid ||
808 bcmp(&aia->ai_termid, &new_aia->ai_termid,
809 sizeof(new_aia->ai_termid)) ||
810 aia->ai_flags != new_aia->ai_flags);
811
812 if (update)
813 bcopy(new_aia, aia, sizeof(*aia));
814
815 return (update);
816}
817
818/*
819 * Return the next session ID. The range of kernel generated audit session IDs
820 * is ASSIGNED_ASID_MIN to ASSIGNED_ASID_MAX.
821 */
822static uint32_t
823audit_session_nextid(void)
824{
825 static uint32_t next_asid = ASSIGNED_ASID_MIN;
826
827 AUDIT_SENTRY_RWLOCK_ASSERT();
828
829 if (next_asid > ASSIGNED_ASID_MAX)
830 next_asid = ASSIGNED_ASID_MIN;
831
832 return (next_asid++);
833}
834
835/*
836 * Allocated a new audit_session entry and add it to the hash table. If the
837 * given ASID is set to AU_ASSIGN_ASID then audit_session_new() will pick an
838 * audit session ID. Otherwise, it attempts use the one given. It creates a
839 * reference to the entry that must be unref'ed.
840 */
841static auditinfo_addr_t *
842audit_session_new(auditinfo_addr_t *new_aia_p, auditinfo_addr_t *old_aia_p)
843{
844 au_asid_t new_asid;
845 au_sentry_t *se = NULL;
846 au_sentry_t *found_se = NULL;
847 auditinfo_addr_t *aia = NULL;
848
849 KASSERT(new_aia_p != NULL, ("audit_session_new: new_aia_p == NULL"));
850
851 new_asid = new_aia_p->ai_asid;
852
853 /*
854 * Alloc a new session entry now so we don't wait holding the lock.
855 */
856 se = malloc(sizeof(au_sentry_t), M_AU_SESSION, M_WAITOK | M_ZERO);
857
858 /*
859 * Find an unique session ID, if desired.
860 */
861 AUDIT_SENTRY_WLOCK();
862 if (new_asid == AU_ASSIGN_ASID) {
863 do {
864
865 new_asid = (au_asid_t)audit_session_nextid();
866 found_se = audit_session_find(new_asid);
867
868 /*
869 * If the session ID is currently active then drop the
870 * reference and try again.
871 */
872 if (found_se != NULL)
873 audit_unref_session(found_se);
874 else
875 break;
876 } while(1);
877 } else {
878
879 /*
880 * Check to see if the requested ASID is already in the
881 * hash table. If so, update it with the new auditinfo.
882 */
883 if ((found_se = audit_session_find(new_asid)) != NULL) {
884 int updated;
885
886 updated = audit_update_sentry(found_se, new_aia_p);
887
888 AUDIT_SENTRY_WUNLOCK();
889 free(se, M_AU_SESSION);
890
891 /* If a different session then add this process in. */
892 if (new_aia_p != old_aia_p)
893 audit_inc_procount(found_se);
894
895 /*
896 * If the session information was updated then
897 * generate an audit event to notify userland.
898 */
899 if (updated)
900 audit_session_event(AUE_SESSION_UPDATE,
901 &found_se->se_auinfo);
902
903 return (&found_se->se_auinfo);
904 }
905 }
906
907 /*
908 * Start the reference and proc count at 1 to account for the process
909 * that invoked this via setaudit_addr() (or friends).
910 */
911 se->se_refcnt = se->se_procnt = 1;
912
913 /*
914 * Populate the new session entry. Note that process masks are stored
915 * in kauth ucred so just zero them here.
916 */
917 se->se_port = IPC_PORT_NULL;
918 aia = &se->se_auinfo;
919 aia->ai_asid = new_asid;
920 aia->ai_auid = new_aia_p->ai_auid;
921 bzero(&new_aia_p->ai_mask, sizeof(new_aia_p->ai_mask));
922 bcopy(&new_aia_p->ai_termid, &aia->ai_termid, sizeof(aia->ai_termid));
923 aia->ai_flags = new_aia_p->ai_flags;
924
925 /*
926 * Add it to the hash table.
927 */
928 LIST_INSERT_HEAD(&au_sentry_bucket[HASH_ASID(new_asid)], se, se_link);
929 AUDIT_SENTRY_WUNLOCK();
930
931 /*
932 * Generate an audit event to notify userland of the new session.
933 */
934 audit_session_event(AUE_SESSION_START, aia);
935 au_history_record(se, AU_HISTORY_EVENT_BIRTH);
936 return (aia);
937}
938
939/*
940 * Lookup an existing session. A copy of the audit session info for a given
941 * ASID is returned in ret_aia. Returns 0 on success.
942 */
943int
944audit_session_lookup(au_asid_t asid, auditinfo_addr_t *ret_aia)
945{
946 au_sentry_t *se = NULL;
947
948 if ((uint32_t)asid > ASSIGNED_ASID_MAX)
949 return (-1);
950 AUDIT_SENTRY_RLOCK();
951 if ((se = audit_session_find(asid)) == NULL) {
952 AUDIT_SENTRY_RUNLOCK();
953 return (1);
954 }
955 /* We have a reference on the session so it is safe to drop the lock. */
956 AUDIT_SENTRY_RUNLOCK();
957 if (ret_aia != NULL)
958 bcopy(&se->se_auinfo, ret_aia, sizeof(*ret_aia));
959 audit_unref_session(se);
960
961 return (0);
962}
963
964void
965audit_session_aiaref(auditinfo_addr_t *aia_p)
966{
967
968 audit_ref_session(AU_SENTRY_PTR(aia_p));
969}
970
971/*
972 * Add a reference to the session entry.
973 */
974void
975audit_session_ref(kauth_cred_t cred)
976{
977 auditinfo_addr_t *aia_p;
978
979 KASSERT(IS_VALID_CRED(cred),
980 ("audit_session_ref: Invalid kauth_cred."));
981
982 aia_p = cred->cr_audit.as_aia_p;
983 audit_session_aiaref(aia_p);
984}
985
986void audit_session_aiaunref(auditinfo_addr_t *aia_p)
987{
988
989 audit_unref_session(AU_SENTRY_PTR(aia_p));
990}
991
992/*
993 * Remove a reference to the session entry.
994 */
995void
996audit_session_unref(kauth_cred_t cred)
997{
998 auditinfo_addr_t *aia_p;
999
1000 KASSERT(IS_VALID_CRED(cred),
1001 ("audit_session_unref: Invalid kauth_cred."));
1002
1003 aia_p = cred->cr_audit.as_aia_p;
1004 audit_session_aiaunref(aia_p);
1005}
1006
1007/*
1008 * Increment the per audit session process count. Assumes that the caller has
1009 * a reference on the process' cred.
1010 */
1011void
1012audit_session_procnew(proc_t p)
1013{
1014 kauth_cred_t cred = p->p_ucred;
1015 auditinfo_addr_t *aia_p;
1016
1017 KASSERT(IS_VALID_CRED(cred),
1018 ("audit_session_procnew: Invalid kauth_cred."));
1019
1020 aia_p = cred->cr_audit.as_aia_p;
1021
1022 audit_inc_procount(AU_SENTRY_PTR(aia_p));
1023}
1024
1025/*
1026 * Decrement the per audit session process count. Assumes that the caller has
1027 * a reference on the cred.
1028 */
1029void
1030audit_session_procexit(proc_t p)
1031{
1032 kauth_cred_t cred = p->p_ucred;
1033 auditinfo_addr_t *aia_p;
1034
1035 KASSERT(IS_VALID_CRED(cred),
1036 ("audit_session_procexit: Invalid kauth_cred."));
1037
1038 aia_p = cred->cr_audit.as_aia_p;
1039
1040 audit_dec_procount(AU_SENTRY_PTR(aia_p));
1041}
1042
1043/*
1044 * Init the audit session code.
1045 */
1046void
1047audit_session_init(void)
1048{
1049 int i;
1050
1051 KASSERT((ASSIGNED_ASID_MAX - ASSIGNED_ASID_MIN) > PID_MAX,
1052 ("audit_session_init: ASSIGNED_ASID_MAX is not large enough."));
1053
1054 AUDIT_SENTRY_RWLOCK_INIT();
1055
1056 au_sentry_bucket = malloc( sizeof(struct au_sentry) *
1057 HASH_TABLE_SIZE, M_AU_SESSION, M_WAITOK | M_ZERO);
1058
1059 for (i = 0; i < HASH_TABLE_SIZE; i++)
1060 LIST_INIT(&au_sentry_bucket[i]);
1061
1062 (void)audit_sdev_init();
1063#if AU_HISTORY_LOGGING
1064 au_history = malloc(sizeof(struct au_history) * au_history_size,
1065 M_AU_SESSION, M_WAITOK|M_ZERO);
1066#endif
1067}
1068
1069static int
1070audit_session_update_check(kauth_cred_t cred, auditinfo_addr_t *old,
1071 auditinfo_addr_t *new)
1072{
1073 uint64_t n;
1074
1075 /* If the current audit ID is not the default then it is immutable. */
1076 if (old->ai_auid != AU_DEFAUDITID && old->ai_auid != new->ai_auid)
1077 return (EINVAL);
1078
1079 /* If the current termid is not the default then it is immutable. */
1080 if ((old->ai_termid.at_type != AU_IPv4 ||
1081 old->ai_termid.at_port != 0 ||
1082 old->ai_termid.at_addr[0] != 0) &&
1083 (old->ai_termid.at_port != new->ai_termid.at_port ||
1084 old->ai_termid.at_type != new->ai_termid.at_type ||
1085 0 != bcmp(&old->ai_termid.at_addr, &new->ai_termid.at_addr,
1086 sizeof (old->ai_termid.at_addr))))
1087 return (EINVAL);
1088
1089 /* The flags may be set only according to the
1090 * audit_session_*_set_sflags_masks.
1091 */
1092 n = ~old->ai_flags & new->ai_flags;
1093 if (0 != n &&
1094 !((n == (audit_session_superuser_set_sflags_mask & n) &&
1095 kauth_cred_issuser(cred)) ||
1096 (n == (audit_session_member_set_sflags_mask & n) &&
1097 old->ai_asid == new->ai_asid)))
1098 return (EINVAL);
1099
1100 /* The flags may be cleared only according to the
1101 * audit_session_*_clear_sflags_masks.
1102 */
1103 n = ~new->ai_flags & old->ai_flags;
1104 if (0 != n &&
1105 !((n == (audit_session_superuser_clear_sflags_mask & n) &&
1106 kauth_cred_issuser(cred)) ||
1107 (n == (audit_session_member_clear_sflags_mask & n) &&
1108 old->ai_asid == new->ai_asid)))
1109 return (EINVAL);
1110
1111 /* The audit masks are mutable. */
1112 return (0);
1113}
1114
1115/*
1116 * Safely update kauth cred of the given process with new the given audit info.
1117 */
1118int
1119audit_session_setaia(proc_t p, auditinfo_addr_t *new_aia_p)
1120{
1121 kauth_cred_t my_cred, my_new_cred;
1122 struct au_session as;
1123 struct au_session tmp_as;
1124 auditinfo_addr_t caia, *old_aia_p;
1125 int ret;
1126
1127 /*
1128 * If this is going to modify an existing session then do some
1129 * immutable checks.
1130 */
1131 if (audit_session_lookup(new_aia_p->ai_asid, &caia) == 0) {
1132 my_cred = kauth_cred_proc_ref(p);
1133 ret = audit_session_update_check(my_cred, &caia, new_aia_p);
1134 kauth_cred_unref(&my_cred);
1135 if (ret)
1136 return (ret);
1137 }
1138
1139 my_cred = kauth_cred_proc_ref(p);
1140 bcopy(&new_aia_p->ai_mask, &as.as_mask, sizeof(as.as_mask));
1141 old_aia_p = my_cred->cr_audit.as_aia_p;
1142 /* audit_session_new() adds a reference on the session */
1143 as.as_aia_p = audit_session_new(new_aia_p, old_aia_p);
1144
1145 /* If the process left a session then update the process count. */
1146 if (old_aia_p != new_aia_p)
1147 audit_dec_procount(AU_SENTRY_PTR(old_aia_p));
1148
1149
1150 /*
1151 * We are modifying the audit info in a credential so we need a new
1152 * credential (or take another reference on an existing credential that
1153 * matches our new one). We must do this because the audit info in the
1154 * credential is used as part of our hash key. Get current credential
1155 * in the target process and take a reference while we muck with it.
1156 */
1157 for (;;) {
1158
1159 /*
1160 * Set the credential with new info. If there is no change,
1161 * we get back the same credential we passed in; if there is
1162 * a change, we drop the reference on the credential we
1163 * passed in. The subsequent compare is safe, because it is
1164 * a pointer compare rather than a contents compare.
1165 */
1166 bcopy(&as, &tmp_as, sizeof(tmp_as));
1167 my_new_cred = kauth_cred_setauditinfo(my_cred, &tmp_as);
1168
1169 if (my_cred != my_new_cred) {
1170 proc_ucred_lock(p);
1171 /* Need to protect for a race where another thread also
1172 * changed the credential after we took our reference.
1173 * If p_ucred has changed then we should restart this
1174 * again with the new cred.
1175 */
1176 if (p->p_ucred != my_cred) {
1177 proc_ucred_unlock(p);
1178 audit_session_unref(my_new_cred);
1179 kauth_cred_unref(&my_new_cred);
1180 /* try again */
1181 my_cred = kauth_cred_proc_ref(p);
1182 continue;
1183 }
1184 p->p_ucred = my_new_cred;
1185 /* update cred on proc */
1186 PROC_UPDATE_CREDS_ONPROC(p);
1187 proc_ucred_unlock(p);
1188 }
1189 /*
1190 * Drop old proc reference or our extra reference.
1191 */
1192 kauth_cred_unref(&my_cred);
1193 break;
1194 }
1195
1196 /* Drop the reference taken by audit_session_new() above. */
1197 audit_unref_session(AU_SENTRY_PTR(as.as_aia_p));
1198
1199 /* Propagate the change from the process to the Mach task. */
1200 set_security_token(p);
1201
1202 return (0);
1203}
1204
1205/*
1206 * audit_session_self (system call)
1207 *
1208 * Description: Obtain a Mach send right for the current session.
1209 *
1210 * Parameters: p Process calling audit_session_self().
1211 *
1212 * Returns: *ret_port Named Mach send right, which may be
1213 * MACH_PORT_NULL in the failure case.
1214 *
1215 * Errno: 0 Success
1216 * EINVAL The calling process' session has not be set.
1217 * ESRCH Bad process, can't get valid cred for process.
1218 * ENOMEM Port allocation failed due to no free memory.
1219 */
1220int
1221audit_session_self(proc_t p, __unused struct audit_session_self_args *uap,
1222 mach_port_name_t *ret_port)
1223{
1224 ipc_port_t sendport = IPC_PORT_NULL;
1225 kauth_cred_t cred = NULL;
1226 auditinfo_addr_t *aia_p;
1227 au_sentry_t *se;
1228 int err = 0;
1229
1230 cred = kauth_cred_proc_ref(p);
1231 if (!IS_VALID_CRED(cred)) {
1232 err = ESRCH;
1233 goto done;
1234 }
1235
1236 aia_p = cred->cr_audit.as_aia_p;
1237 if (!IS_VALID_SESSION(aia_p)) {
1238 /* Can't join the default session. */
1239 err = EINVAL;
1240 goto done;
1241 }
1242
1243 se = AU_SENTRY_PTR(aia_p);
1244
1245 /*
1246 * Processes that join using this mach port will inherit this process'
1247 * pre-selection masks.
1248 */
1249 if (se->se_port == IPC_PORT_NULL)
1250 bcopy(&cred->cr_audit.as_mask, &se->se_mask,
1251 sizeof(se->se_mask));
1252
1253 /*
1254 * Get a send right to the session's Mach port and insert it in the
1255 * process' mach port namespace.
1256 */
1257 sendport = audit_session_mksend(aia_p, &se->se_port);
1258 *ret_port = ipc_port_copyout_send(sendport, get_task_ipcspace(p->task));
1259
1260done:
1261 if (cred != NULL)
1262 kauth_cred_unref(&cred);
1263 if (err != 0)
1264 *ret_port = MACH_PORT_NULL;
1265 return (err);
1266}
1267
1268/*
1269 * audit_session_port (system call)
1270 *
1271 * Description: Obtain a Mach send right for the given session ID.
1272 *
1273 * Parameters: p Process calling audit_session_port().
1274 * uap->asid The target audit session ID. The special
1275 * value -1 can be used to target the process's
1276 * own session.
1277 * uap->portnamep User address at which to place port name.
1278 *
1279 * Returns: 0 Success
1280 * EINVAL The calling process' session has not be set.
1281 * EINVAL The given session ID could not be found.
1282 * EINVAL The Mach port right could not be copied out.
1283 * ESRCH Bad process, can't get valid cred for process.
1284 * EPERM Only the superuser can reference sessions other
1285 * than the process's own.
1286 * ENOMEM Port allocation failed due to no free memory.
1287 */
1288int
1289audit_session_port(proc_t p, struct audit_session_port_args *uap,
1290 __unused int *retval)
1291{
1292 ipc_port_t sendport = IPC_PORT_NULL;
1293 mach_port_name_t portname = MACH_PORT_NULL;
1294 kauth_cred_t cred = NULL;
1295 auditinfo_addr_t *aia_p = NULL;
1296 au_sentry_t *se = NULL;
1297 int err = 0;
1298
1299 /* Note: Currently this test will never be true, because
1300 * ASSIGNED_ASID_MAX is effectively (uint32_t)-2.
1301 */
1302 if (uap->asid != -1 && (uint32_t)uap->asid > ASSIGNED_ASID_MAX) {
1303 err = EINVAL;
1304 goto done;
1305 }
1306 cred = kauth_cred_proc_ref(p);
1307 if (!IS_VALID_CRED(cred)) {
1308 err = ESRCH;
1309 goto done;
1310 }
1311 aia_p = cred->cr_audit.as_aia_p;
1312
1313 /* Find the session corresponding to the requested audit
1314 * session ID. If found, take a reference on it so that
1315 * the session is not dropped until the join is later done.
1316 */
1317 if (uap->asid == (au_asid_t)-1 ||
1318 uap->asid == aia_p->ai_asid) {
1319
1320 if (!IS_VALID_SESSION(aia_p)) {
1321 /* Can't join the default session. */
1322 err = EINVAL;
1323 goto done;
1324 }
1325
1326 /* No privilege is required to obtain a port for our
1327 * own session.
1328 */
1329 se = AU_SENTRY_PTR(aia_p);
1330 audit_ref_session(se);
1331 } else if (kauth_cred_issuser(cred)) {
1332 /* The superuser may obtain a port for any existing
1333 * session.
1334 */
1335 AUDIT_SENTRY_RLOCK();
1336 se = audit_session_find(uap->asid);
1337 AUDIT_SENTRY_RUNLOCK();
1338 if (NULL == se) {
1339 err = EINVAL;
1340 goto done;
1341 }
1342 aia_p = &se->se_auinfo;
1343 } else {
1344 err = EPERM;
1345 goto done;
1346 }
1347
1348 /*
1349 * Processes that join using this mach port will inherit this process'
1350 * pre-selection masks.
1351 */
1352 if (se->se_port == IPC_PORT_NULL)
1353 bcopy(&cred->cr_audit.as_mask, &se->se_mask,
1354 sizeof(se->se_mask));
1355
1356 /*
1357 * Use the session reference to create a mach port reference for the
1358 * session (at which point we are free to drop the session reference)
1359 * and then copy out the mach port to the process' mach port namespace.
1360 */
1361 sendport = audit_session_mksend(aia_p, &se->se_port);
1362 portname = ipc_port_copyout_send(sendport, get_task_ipcspace(p->task));
1363 if (!MACH_PORT_VALID(portname)) {
1364 err = EINVAL;
1365 goto done;
1366 }
1367 err = copyout(&portname, uap->portnamep, sizeof(mach_port_name_t));
1368done:
1369 if (cred != NULL)
1370 kauth_cred_unref(&cred);
1371 if (NULL != se)
1372 audit_unref_session(se);
1373 if (MACH_PORT_VALID(portname) && 0 != err)
1374 (void)mach_port_deallocate(get_task_ipcspace(p->task),
1375 portname);
1376
1377 return (err);
1378}
1379
1380static int
1381audit_session_join_internal(proc_t p, task_t task, ipc_port_t port, au_asid_t *new_asid)
1382{
1383 auditinfo_addr_t *new_aia_p, *old_aia_p;
1384 kauth_cred_t my_cred = NULL;
1385 au_asid_t old_asid;
1386 int err = 0;
1387
1388 *new_asid = AU_DEFAUDITSID;
1389
1390 if ((new_aia_p = audit_session_porttoaia(port)) == NULL) {
1391 err = EINVAL;
1392 goto done;
1393 }
1394
1395 proc_ucred_lock(p);
1396 kauth_cred_ref(p->p_ucred);
1397 my_cred = p->p_ucred;
1398 if (!IS_VALID_CRED(my_cred)) {
1399 kauth_cred_unref(&my_cred);
1400 proc_ucred_unlock(p);
1401 err = ESRCH;
1402 goto done;
1403 }
1404 old_aia_p = my_cred->cr_audit.as_aia_p;
1405 old_asid = old_aia_p->ai_asid;
1406 *new_asid = new_aia_p->ai_asid;
1407
1408 /*
1409 * Add process in if not already in the session.
1410 */
1411 if (*new_asid != old_asid) {
1412 kauth_cred_t my_new_cred;
1413 struct au_session new_as;
1414
1415 bcopy(&new_aia_p->ai_mask, &new_as.as_mask,
1416 sizeof(new_as.as_mask));
1417 new_as.as_aia_p = new_aia_p;
1418
1419 my_new_cred = kauth_cred_setauditinfo(my_cred, &new_as);
1420 p->p_ucred = my_new_cred;
1421 PROC_UPDATE_CREDS_ONPROC(p);
1422
1423 /* Increment the proc count of new session */
1424 audit_inc_procount(AU_SENTRY_PTR(new_aia_p));
1425
1426 proc_ucred_unlock(p);
1427
1428 /* Propagate the change from the process to the Mach task. */
1429 set_security_token_task_internal(p, task);
1430
1431 /* Decrement the process count of the former session. */
1432 audit_dec_procount(AU_SENTRY_PTR(old_aia_p));
1433 } else {
1434 proc_ucred_unlock(p);
1435 }
1436 kauth_cred_unref(&my_cred);
1437
1438done:
1439 if (port != IPC_PORT_NULL)
1440 ipc_port_release_send(port);
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, task_t task, ipc_port_t port)
1456{
1457 au_asid_t new_asid;
1458
1459 return (audit_session_join_internal(p, task, port, &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(p->task), send,
1489 MACH_MSG_TYPE_COPY_SEND, &port) != KERN_SUCCESS) {
1490 *ret_asid = AU_DEFAUDITSID;
1491 err = EINVAL;
1492 } else
1493 err = audit_session_join_internal(p, p->task, port, ret_asid);
1494
1495 return (err);
1496}
1497
1498/*
1499 * Audit session device.
1500 */
1501
1502/*
1503 * Free an audit sdev entry.
1504 */
1505static void
1506audit_sdev_entry_free(struct audit_sdev_entry *ase)
1507{
1508
1509 free(ase->ase_record, M_AUDIT_SDEV_ENTRY);
1510 free(ase, M_AUDIT_SDEV_ENTRY);
1511}
1512
1513/*
1514 * Append individual record to a queue. Allocate queue-local buffer and
1515 * add to the queue. If the queue is full or we can't allocate memory,
1516 * drop the newest record.
1517 */
1518static void
1519audit_sdev_append(struct audit_sdev *asdev, void *record, u_int record_len)
1520{
1521 struct audit_sdev_entry *ase;
1522
1523 AUDIT_SDEV_LOCK_ASSERT(asdev);
1524
1525 if (asdev->asdev_qlen >= asdev->asdev_qlimit) {
1526 asdev->asdev_drops++;
1527 audit_sdev_drops++;
1528 return;
1529 }
1530
1531 ase = malloc(sizeof (*ase), M_AUDIT_SDEV_ENTRY, M_NOWAIT | M_ZERO);
1532 if (NULL == ase) {
1533 asdev->asdev_drops++;
1534 audit_sdev_drops++;
1535 return;
1536 }
1537
1538 ase->ase_record = malloc(record_len, M_AUDIT_SDEV_ENTRY, M_NOWAIT);
1539 if (NULL == ase->ase_record) {
1540 free(ase, M_AUDIT_SDEV_ENTRY);
1541 asdev->asdev_drops++;
1542 audit_sdev_drops++;
1543 return;
1544 }
1545
1546 bcopy(record, ase->ase_record, record_len);
1547 ase->ase_record_len = record_len;
1548
1549 TAILQ_INSERT_TAIL(&asdev->asdev_queue, ase, ase_queue);
1550 asdev->asdev_inserts++;
1551 asdev->asdev_qlen++;
1552 asdev->asdev_qbyteslen += ase->ase_record_len;
1553 selwakeup(&asdev->asdev_selinfo);
1554 if (asdev->asdev_flags & AUDIT_SDEV_ASYNC)
1555 pgsigio(asdev->asdev_sigio, SIGIO);
1556
1557 cv_broadcast(&asdev->asdev_cv);
1558}
1559
1560/*
1561 * Submit an audit record to be queued in the audit session device.
1562 */
1563void
1564audit_sdev_submit(__unused au_id_t auid, __unused au_asid_t asid, void *record,
1565 u_int record_len)
1566{
1567 struct audit_sdev *asdev;
1568
1569 /*
1570 * Lockless read to avoid lock overhead if sessio devices are not in
1571 * use.
1572 */
1573 if (NULL == TAILQ_FIRST(&audit_sdev_list))
1574 return;
1575
1576 AUDIT_SDEV_LIST_RLOCK();
1577 TAILQ_FOREACH(asdev, &audit_sdev_list, asdev_list) {
1578 AUDIT_SDEV_LOCK(asdev);
1579
1580 /*
1581 * Only append to the sdev queue if the AUID and ASID match that
1582 * of the process that opened this session device or if the
1583 * ALLSESSIONS flag is set.
1584 */
1585 if ((/* XXXss auid == asdev->asdev_auid && */
1586 asid == asdev->asdev_asid) ||
1587 (asdev->asdev_flags & AUDIT_SDEV_ALLSESSIONS) != 0)
1588 audit_sdev_append(asdev, record, record_len);
1589 AUDIT_SDEV_UNLOCK(asdev);
1590 }
1591 AUDIT_SDEV_LIST_RUNLOCK();
1592
1593 /* Unlocked increment. */
1594 audit_sdev_records++;
1595}
1596
1597/*
1598 * Allocate a new audit sdev. Connects the sdev, on succes, to the global
1599 * list and updates statistics.
1600 */
1601static struct audit_sdev *
1602audit_sdev_alloc(void)
1603{
1604 struct audit_sdev *asdev;
1605
1606 AUDIT_SDEV_LIST_WLOCK_ASSERT();
1607
1608 asdev = malloc(sizeof (*asdev), M_AUDIT_SDEV, M_WAITOK | M_ZERO);
1609 if (NULL == asdev)
1610 return (NULL);
1611
1612 asdev->asdev_qlimit = AUDIT_SDEV_QLIMIT_DEFAULT;
1613 TAILQ_INIT(&asdev->asdev_queue);
1614 AUDIT_SDEV_LOCK_INIT(asdev);
1615 AUDIT_SDEV_SX_LOCK_INIT(asdev);
1616 cv_init(&asdev->asdev_cv, "audit_sdev_cv");
1617
1618 /*
1619 * Add to global list and update global statistics.
1620 */
1621 TAILQ_INSERT_HEAD(&audit_sdev_list, asdev, asdev_list);
1622 audit_sdev_count++;
1623 audit_sdev_ever++;
1624
1625 return (asdev);
1626}
1627
1628/*
1629 * Flush all records currently present in an audit sdev.
1630 */
1631static void
1632audit_sdev_flush(struct audit_sdev *asdev)
1633{
1634 struct audit_sdev_entry *ase;
1635
1636 AUDIT_SDEV_LOCK_ASSERT(asdev);
1637
1638 while ((ase = TAILQ_FIRST(&asdev->asdev_queue)) != NULL) {
1639 TAILQ_REMOVE(&asdev->asdev_queue, ase, ase_queue);
1640 asdev->asdev_qbyteslen -= ase->ase_record_len;
1641 audit_sdev_entry_free(ase);
1642 asdev->asdev_qlen--;
1643 }
1644 asdev->asdev_qoffset = 0;
1645
1646 KASSERT(0 == asdev->asdev_qlen, ("audit_sdev_flush: asdev_qlen"));
1647 KASSERT(0 == asdev->asdev_qbyteslen,
1648 ("audit_sdev_flush: asdev_qbyteslen"));
1649}
1650
1651/*
1652 * Free an audit sdev.
1653 */
1654static void
1655audit_sdev_free(struct audit_sdev *asdev)
1656{
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 free(asdev, M_AUDIT_SDEV);
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(p);
1684 error = suser(scred, &p->p_acflag);
1685
1686 if (NULL != aia_p)
1687 bcopy(scred->cr_audit.as_aia_p, aia_p, sizeof (*aia_p));
1688 kauth_cred_unref(&scred);
1689
1690 return (error);
1691}
1692
1693/*
1694 * Audit session dev open method.
1695 */
1696static int
1697audit_sdev_open(dev_t dev, __unused int flags, __unused int devtype, proc_t p)
1698{
1699 struct audit_sdev *asdev;
1700 struct auditinfo_addr aia;
1701 int u;
1702
1703 u = minor(dev);
1704 if (u < 0 || u >= MAX_AUDIT_SDEVS)
1705 return (ENXIO);
1706
1707 (void) audit_sdev_get_aia(p, &aia);
1708
1709 AUDIT_SDEV_LIST_WLOCK();
1710 asdev = audit_sdev_dtab[u];
1711 if (NULL == asdev) {
1712 asdev = audit_sdev_alloc();
1713 if (NULL == asdev) {
1714 AUDIT_SDEV_LIST_WUNLOCK();
1715 return (ENOMEM);
1716 }
1717 audit_sdev_dtab[u] = asdev;
1718 } else {
1719 KASSERT(asdev->asdev_open, ("audit_sdev_open: Already open"));
1720 AUDIT_SDEV_LIST_WUNLOCK();
1721 return (EBUSY);
1722 }
1723 asdev->asdev_open = 1;
1724 asdev->asdev_auid = aia.ai_auid;
1725 asdev->asdev_asid = aia.ai_asid;
1726 asdev->asdev_flags = 0;
1727
1728 AUDIT_SDEV_LIST_WUNLOCK();
1729
1730 return (0);
1731}
1732
1733/*
1734 * Audit session dev close method.
1735 */
1736static int
1737audit_sdev_close(dev_t dev, __unused int flags, __unused int devtype,
1738 __unused proc_t p)
1739{
1740 struct audit_sdev *asdev;
1741 int u;
1742
1743 u = minor(dev);
1744 asdev = audit_sdev_dtab[u];
1745
1746 KASSERT(asdev != NULL, ("audit_sdev_close: asdev == NULL"));
1747 KASSERT(asdev->asdev_open, ("audit_sdev_close: !asdev_open"));
1748
1749 AUDIT_SDEV_LIST_WLOCK();
1750 AUDIT_SDEV_LOCK(asdev);
1751 asdev->asdev_open = 0;
1752 audit_sdev_free(asdev); /* sdev lock unlocked in audit_sdev_free() */
1753 audit_sdev_dtab[u] = NULL;
1754 AUDIT_SDEV_LIST_WUNLOCK();
1755
1756 return (0);
1757}
1758
1759/*
1760 * Audit session dev ioctl method.
1761 */
1762static int
1763audit_sdev_ioctl(dev_t dev, u_long cmd, caddr_t data,
1764 __unused int flag, proc_t p)
1765{
1766 struct audit_sdev *asdev;
1767 int error;
1768
1769 asdev = audit_sdev_dtab[minor(dev)];
1770 KASSERT(asdev != NULL, ("audit_sdev_ioctl: asdev == NULL"));
1771
1772 error = 0;
1773
1774 switch (cmd) {
1775 case FIONBIO:
1776 AUDIT_SDEV_LOCK(asdev);
1777 if (*(int *)data)
1778 asdev->asdev_flags |= AUDIT_SDEV_NBIO;
1779 else
1780 asdev->asdev_flags &= ~AUDIT_SDEV_NBIO;
1781 AUDIT_SDEV_UNLOCK(asdev);
1782 break;
1783
1784 case FIONREAD:
1785 AUDIT_SDEV_LOCK(asdev);
1786 *(int *)data = asdev->asdev_qbyteslen - asdev->asdev_qoffset;
1787 AUDIT_SDEV_UNLOCK(asdev);
1788 break;
1789
1790 case AUDITSDEV_GET_QLEN:
1791 *(u_int *)data = asdev->asdev_qlen;
1792 break;
1793
1794 case AUDITSDEV_GET_QLIMIT:
1795 *(u_int *)data = asdev->asdev_qlimit;
1796 break;
1797
1798 case AUDITSDEV_SET_QLIMIT:
1799 if (*(u_int *)data >= AUDIT_SDEV_QLIMIT_MIN ||
1800 *(u_int *)data <= AUDIT_SDEV_QLIMIT_MAX) {
1801 asdev->asdev_qlimit = *(u_int *)data;
1802 } else
1803 error = EINVAL;
1804 break;
1805
1806 case AUDITSDEV_GET_QLIMIT_MIN:
1807 *(u_int *)data = AUDIT_SDEV_QLIMIT_MIN;
1808 break;
1809
1810 case AUDITSDEV_GET_QLIMIT_MAX:
1811 *(u_int *)data = AUDIT_SDEV_QLIMIT_MAX;
1812 break;
1813
1814 case AUDITSDEV_FLUSH:
1815 if (AUDIT_SDEV_SX_XLOCK_SIG(asdev) != 0)
1816 return (EINTR);
1817 AUDIT_SDEV_LOCK(asdev);
1818 audit_sdev_flush(asdev);
1819 AUDIT_SDEV_UNLOCK(asdev);
1820 AUDIT_SDEV_SX_XUNLOCK(asdev);
1821 break;
1822
1823 case AUDITSDEV_GET_MAXDATA:
1824 *(u_int *)data = MAXAUDITDATA;
1825 break;
1826
1827 /* XXXss these should be 64 bit, maybe. */
1828 case AUDITSDEV_GET_INSERTS:
1829 *(u_int *)data = asdev->asdev_inserts;
1830 break;
1831
1832 case AUDITSDEV_GET_READS:
1833 *(u_int *)data = asdev->asdev_reads;
1834 break;
1835
1836 case AUDITSDEV_GET_DROPS:
1837 *(u_int *)data = asdev->asdev_drops;
1838 break;
1839
1840 case AUDITSDEV_GET_ALLSESSIONS:
1841 error = audit_sdev_get_aia(p, NULL);
1842 if (error)
1843 break;
1844 *(u_int *)data = (asdev->asdev_flags & AUDIT_SDEV_ALLSESSIONS) ?
1845 1 : 0;
1846 break;
1847
1848 case AUDITSDEV_SET_ALLSESSIONS:
1849 error = audit_sdev_get_aia(p, NULL);
1850 if (error)
1851 break;
1852
1853 AUDIT_SDEV_LOCK(asdev);
1854 if (*(int *)data)
1855 asdev->asdev_flags |= AUDIT_SDEV_ALLSESSIONS;
1856 else
1857 asdev->asdev_flags &= ~AUDIT_SDEV_ALLSESSIONS;
1858 AUDIT_SDEV_UNLOCK(asdev);
1859 break;
1860
1861 default:
1862 error = ENOTTY;
1863 }
1864
1865 return (error);
1866}
1867
1868/*
1869 * Audit session dev read method.
1870 */
1871static int
1872audit_sdev_read(dev_t dev, struct uio *uio, __unused int flag)
1873{
1874 struct audit_sdev_entry *ase;
1875 struct audit_sdev *asdev;
1876 u_int toread;
1877 int error;
1878
1879 asdev = audit_sdev_dtab[minor(dev)];
1880 KASSERT(NULL != asdev, ("audit_sdev_read: asdev == NULL"));
1881
1882 /*
1883 * We hold a sleep lock over read and flush because we rely on the
1884 * stability of a record in the queue during uiomove.
1885 */
1886 if (0 != AUDIT_SDEV_SX_XLOCK_SIG(asdev))
1887 return (EINTR);
1888 AUDIT_SDEV_LOCK(asdev);
1889 while (TAILQ_EMPTY(&asdev->asdev_queue)) {
1890 if (asdev->asdev_flags & AUDIT_SDEV_NBIO) {
1891 AUDIT_SDEV_UNLOCK(asdev);
1892 AUDIT_SDEV_SX_XUNLOCK(asdev);
1893 return (EAGAIN);
1894 }
1895 error = cv_wait_sig(&asdev->asdev_cv, AUDIT_SDEV_MTX(asdev));
1896 if (error) {
1897 AUDIT_SDEV_UNLOCK(asdev);
1898 AUDIT_SDEV_SX_XUNLOCK(asdev);
1899 return (error);
1900 }
1901 }
1902
1903 /*
1904 * Copy as many remaining bytes from the current record to userspace
1905 * as we can. Keep processing records until we run out of records in
1906 * the queue or until the user buffer runs out of space.
1907 *
1908 * We rely on the sleep lock to maintain ase's stability here.
1909 */
1910 asdev->asdev_reads++;
1911 while ((ase = TAILQ_FIRST(&asdev->asdev_queue)) != NULL &&
1912 uio_resid(uio) > 0) {
1913 AUDIT_SDEV_LOCK_ASSERT(asdev);
1914
1915 KASSERT(ase->ase_record_len > asdev->asdev_qoffset,
1916 ("audit_sdev_read: record_len > qoffset (1)"));
1917 toread = MIN((int)(ase->ase_record_len - asdev->asdev_qoffset),
1918 uio_resid(uio));
1919 AUDIT_SDEV_UNLOCK(asdev);
1920 error = uiomove((char *) ase->ase_record + asdev->asdev_qoffset,
1921 toread, uio);
1922 if (error) {
1923 AUDIT_SDEV_SX_XUNLOCK(asdev);
1924 return (error);
1925 }
1926
1927 /*
1928 * If the copy succeeded then update book-keeping, and if no
1929 * bytes remain in the current record then free it.
1930 */
1931 AUDIT_SDEV_LOCK(asdev);
1932 KASSERT(TAILQ_FIRST(&asdev->asdev_queue) == ase,
1933 ("audit_sdev_read: queue out of sync after uiomove"));
1934 asdev->asdev_qoffset += toread;
1935 KASSERT(ase->ase_record_len >= asdev->asdev_qoffset,
1936 ("audit_sdev_read: record_len >= qoffset (2)"));
1937 if (asdev->asdev_qoffset == ase->ase_record_len) {
1938 TAILQ_REMOVE(&asdev->asdev_queue, ase, ase_queue);
1939 asdev->asdev_qbyteslen -= ase->ase_record_len;
1940 audit_sdev_entry_free(ase);
1941 asdev->asdev_qlen--;
1942 asdev->asdev_qoffset = 0;
1943 }
1944 }
1945 AUDIT_SDEV_UNLOCK(asdev);
1946 AUDIT_SDEV_SX_XUNLOCK(asdev);
1947 return (0);
1948}
1949
1950/*
1951 * Audit session device poll method.
1952 */
1953static int
1954audit_sdev_poll(dev_t dev, int events, void *wql, struct proc *p)
1955{
1956 struct audit_sdev *asdev;
1957 int revents;
1958
1959 revents = 0;
1960 asdev = audit_sdev_dtab[minor(dev)];
1961 KASSERT(NULL != asdev, ("audit_sdev_poll: asdev == NULL"));
1962
1963 if (events & (POLLIN | POLLRDNORM)) {
1964 AUDIT_SDEV_LOCK(asdev);
1965 if (NULL != TAILQ_FIRST(&asdev->asdev_queue))
1966 revents |= events & (POLLIN | POLLRDNORM);
1967 else
1968 selrecord(p, &asdev->asdev_selinfo, wql);
1969 AUDIT_SDEV_UNLOCK(asdev);
1970 }
1971 return (revents);
1972}
1973
1974/*
1975 * Audit sdev clone routine. Provides a new minor number or returns -1.
1976 * This called with DEVFS_LOCK held.
1977 */
1978static int
1979audit_sdev_clone(__unused dev_t dev, int action)
1980{
1981 int i;
1982
1983 if (DEVFS_CLONE_ALLOC == action) {
1984 for(i = 0; i < MAX_AUDIT_SDEVS; i++)
1985 if (NULL == audit_sdev_dtab[i])
1986 return (i);
1987
1988 /*
1989 * This really should return -1 here but that seems to
1990 * hang things in devfs. We instead return 0 and let
1991 * audit_sdev_open tell userland the bad news.
1992 */
1993 return (0);
1994 }
1995
1996 return (-1);
1997}
1998
1999static int
2000audit_sdev_init(void)
2001{
2002 dev_t dev;
2003
2004 TAILQ_INIT(&audit_sdev_list);
2005 AUDIT_SDEV_LIST_LOCK_INIT();
2006
2007 audit_sdev_major = cdevsw_add(-1, &audit_sdev_cdevsw);
2008 if (audit_sdev_major < 0)
2009 return (KERN_FAILURE);
2010
2011 dev = makedev(audit_sdev_major, 0);
2012 devnode = devfs_make_node_clone(dev, DEVFS_CHAR, UID_ROOT, GID_WHEEL,
2013 0644, audit_sdev_clone, AUDIT_SDEV_NAME, 0);
2014
2015 if (NULL == devnode)
2016 return (KERN_FAILURE);
2017
2018 return (KERN_SUCCESS);
2019}
2020
2021/* XXXss
2022static int
2023audit_sdev_shutdown(void)
2024{
2025
2026 devfs_remove(devnode);
2027 (void) cdevsw_remove(audit_sdev_major, &audit_sdev_cdevsw);
2028
2029 return (KERN_SUCCESS);
2030}
2031*/
2032
2033#else
2034
2035int
2036audit_session_self(proc_t p, struct audit_session_self_args *uap,
2037 mach_port_name_t *ret_port)
2038{
2039#pragma unused(p, uap, ret_port)
2040
2041 return (ENOSYS);
2042}
2043
2044int
2045audit_session_join(proc_t p, struct audit_session_join_args *uap,
2046 au_asid_t *ret_asid)
2047{
2048#pragma unused(p, uap, ret_asid)
2049
2050 return (ENOSYS);
2051}
2052
2053int
2054audit_session_port(proc_t p, struct audit_session_port_args *uap, int *retval)
2055{
2056#pragma unused(p, uap, retval)
2057
2058 return (ENOSYS);
2059}
2060
2061#endif /* CONFIG_AUDIT */
2062