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