17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51d7bfecdStz204579 * Common Development and Distribution License (the "License").
61d7bfecdStz204579 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
224a0fa546SMarek Pospisil * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
254a0fa546SMarek Pospisil /*
264a0fa546SMarek Pospisil * Routines for writing audit records.
274a0fa546SMarek Pospisil */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <sys/door.h>
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <sys/time.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> /* for statfs */
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/file.h>
367c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
377c478bd9Sstevel@tonic-gate #include <sys/user.h>
387c478bd9Sstevel@tonic-gate #include <sys/uio.h>
397c478bd9Sstevel@tonic-gate #include <sys/reboot.h>
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> /* for KM_SLEEP */
417c478bd9Sstevel@tonic-gate #include <sys/resource.h> /* for RLIM_INFINITY */
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> /* panic */
437c478bd9Sstevel@tonic-gate #include <sys/systm.h>
447c478bd9Sstevel@tonic-gate #include <sys/debug.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
467c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
477c478bd9Sstevel@tonic-gate #include <sys/zone.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include <c2/audit.h>
507c478bd9Sstevel@tonic-gate #include <c2/audit_kernel.h>
517c478bd9Sstevel@tonic-gate #include <c2/audit_record.h>
527c478bd9Sstevel@tonic-gate #include <c2/audit_kevents.h>
537c478bd9Sstevel@tonic-gate #include <c2/audit_door_infc.h>
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate static void au_dequeue(au_kcontext_t *, au_buff_t *);
567c478bd9Sstevel@tonic-gate static void audit_async_finish_backend(void *);
577c478bd9Sstevel@tonic-gate static int audit_sync_block(au_kcontext_t *);
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate * each of these two tables are indexed by the values AU_DBUF_COMPLETE
607c478bd9Sstevel@tonic-gate * through AU_DBUF_LAST; the content is the next state value. The
617c478bd9Sstevel@tonic-gate * first table determines the next state for a buffer which is not the
627c478bd9Sstevel@tonic-gate * end of a record and the second table determines the state for a
637c478bd9Sstevel@tonic-gate * buffer which is the end of a record. The initial state is
647c478bd9Sstevel@tonic-gate * AU_DBUF_COMPLETE.
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate static int state_if_part[] = {
677c478bd9Sstevel@tonic-gate AU_DBUF_FIRST, AU_DBUF_MIDDLE, AU_DBUF_MIDDLE, AU_DBUF_FIRST};
687c478bd9Sstevel@tonic-gate static int state_if_not_part[] = {
697c478bd9Sstevel@tonic-gate AU_DBUF_COMPLETE, AU_DBUF_LAST, AU_DBUF_LAST, AU_DBUF_COMPLETE};
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate * Write to an audit descriptor.
727c478bd9Sstevel@tonic-gate * Add the au_membuf to the descriptor chain and free the chain passed in.
737c478bd9Sstevel@tonic-gate */
747c478bd9Sstevel@tonic-gate void
au_uwrite(m)757c478bd9Sstevel@tonic-gate au_uwrite(m)
767c478bd9Sstevel@tonic-gate token_t *m;
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate au_write(&(u_ad), m);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate void
au_write(caddr_t * d,token_t * m)827c478bd9Sstevel@tonic-gate au_write(caddr_t *d, token_t *m)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate if (d == NULL) {
857c478bd9Sstevel@tonic-gate au_toss_token(m);
867c478bd9Sstevel@tonic-gate return;
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate if (m == (token_t *)0) {
897c478bd9Sstevel@tonic-gate printf("au_write: null token\n");
907c478bd9Sstevel@tonic-gate return;
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate if (*d == NULL)
947c478bd9Sstevel@tonic-gate *d = (caddr_t)m;
957c478bd9Sstevel@tonic-gate else
967c478bd9Sstevel@tonic-gate (void) au_append_rec((au_buff_t *)*d, m, AU_PACK);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate * Close an audit descriptor.
1017c478bd9Sstevel@tonic-gate * Use the second parameter to indicate if it should be written or not.
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate void
au_close(au_kcontext_t * kctx,caddr_t * d,int flag,au_event_t e_type,au_emod_t e_mod,timestruc_t * e_time)104d0fa49b7STony Nguyen au_close(au_kcontext_t *kctx, caddr_t *d, int flag, au_event_t e_type,
105005d3febSMarek Pospisil au_emod_t e_mod, timestruc_t *e_time)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate token_t *dchain; /* au_membuf chain which is the tokens */
1087c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u);
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate ASSERT(tad != NULL);
1117c478bd9Sstevel@tonic-gate ASSERT(d != NULL);
1127c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL);
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate if ((dchain = (token_t *)*d) == (token_t *)NULL)
1157c478bd9Sstevel@tonic-gate return;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate *d = NULL;
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate * If async then defer; or if requested, defer the closing/queueing to
1217c478bd9Sstevel@tonic-gate * syscall end, unless no syscall is active or the syscall is _exit.
1227c478bd9Sstevel@tonic-gate */
1237c478bd9Sstevel@tonic-gate if ((flag & AU_DONTBLOCK) || ((flag & AU_DEFER) &&
1247c478bd9Sstevel@tonic-gate (tad->tad_scid != 0) && (tad->tad_scid != SYS_exit))) {
125005d3febSMarek Pospisil au_close_defer(dchain, flag, e_type, e_mod, e_time);
1267c478bd9Sstevel@tonic-gate return;
1277c478bd9Sstevel@tonic-gate }
128005d3febSMarek Pospisil au_close_time(kctx, dchain, flag, e_type, e_mod, e_time);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate * Defer closing/queueing of an audit descriptor. For async events, queue
1337c478bd9Sstevel@tonic-gate * via softcall. Otherwise, defer by queueing the record onto the tad; at
1347c478bd9Sstevel@tonic-gate * syscall end time it will be pulled off.
1357c478bd9Sstevel@tonic-gate */
1367c478bd9Sstevel@tonic-gate void
au_close_defer(token_t * dchain,int flag,au_event_t e_type,au_emod_t e_mod,timestruc_t * e_time)137005d3febSMarek Pospisil au_close_defer(token_t *dchain, int flag, au_event_t e_type, au_emod_t e_mod,
138005d3febSMarek Pospisil timestruc_t *e_time)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate au_defer_info_t *attr;
1417c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u);
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate ASSERT(tad != NULL);
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /* If not to be written, toss the record. */
1467c478bd9Sstevel@tonic-gate if ((flag & AU_OK) == 0) {
1477c478bd9Sstevel@tonic-gate au_toss_token(dchain);
1487c478bd9Sstevel@tonic-gate return;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate attr = kmem_alloc(sizeof (au_defer_info_t), KM_NOSLEEP);
1527c478bd9Sstevel@tonic-gate /* If no mem available, failing silently is the best recourse */
1537c478bd9Sstevel@tonic-gate if (attr == NULL) {
1547c478bd9Sstevel@tonic-gate au_toss_token(dchain);
1557c478bd9Sstevel@tonic-gate return;
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate attr->audi_next = NULL;
1597c478bd9Sstevel@tonic-gate attr->audi_ad = dchain;
1607c478bd9Sstevel@tonic-gate attr->audi_e_type = e_type;
1617c478bd9Sstevel@tonic-gate attr->audi_e_mod = e_mod;
1627c478bd9Sstevel@tonic-gate attr->audi_flag = flag;
163005d3febSMarek Pospisil if (e_time != NULL)
164005d3febSMarek Pospisil attr->audi_atime = *e_time;
165005d3febSMarek Pospisil else
1667c478bd9Sstevel@tonic-gate gethrestime(&attr->audi_atime);
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * All async events must be queued via softcall to avoid possible
1707c478bd9Sstevel@tonic-gate * sleeping in high interrupt context. softcall will ensure it's
1717c478bd9Sstevel@tonic-gate * done on a dedicated software-level interrupt thread.
1727c478bd9Sstevel@tonic-gate */
1737c478bd9Sstevel@tonic-gate if (flag & AU_DONTBLOCK) {
1747c478bd9Sstevel@tonic-gate softcall(audit_async_finish_backend, attr);
1757c478bd9Sstevel@tonic-gate audit_async_done(NULL, 0);
1767c478bd9Sstevel@tonic-gate return;
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate * If not an async event, defer by queuing onto the tad until
1817c478bd9Sstevel@tonic-gate * syscall end. No locking is needed because the tad is per-thread.
1827c478bd9Sstevel@tonic-gate */
1837c478bd9Sstevel@tonic-gate if (tad->tad_defer_head)
1847c478bd9Sstevel@tonic-gate tad->tad_defer_tail->audi_next = attr;
1857c478bd9Sstevel@tonic-gate else
1867c478bd9Sstevel@tonic-gate tad->tad_defer_head = attr;
1877c478bd9Sstevel@tonic-gate tad->tad_defer_tail = attr;
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate * Save the time in the event header. If time is not specified (i.e., pointer
1937c478bd9Sstevel@tonic-gate * is NULL), use the current time. This code is fairly ugly since it needs
1947c478bd9Sstevel@tonic-gate * to support both 32- and 64-bit environments and can be called indirectly
1957c478bd9Sstevel@tonic-gate * from both au_close() (for kernel audit) and from audit() (userland audit).
1967c478bd9Sstevel@tonic-gate */
1977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1987c478bd9Sstevel@tonic-gate static void
au_save_time(adr_t * hadrp,timestruc_t * time,int size)1997c478bd9Sstevel@tonic-gate au_save_time(adr_t *hadrp, timestruc_t *time, int size)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate struct {
2027c478bd9Sstevel@tonic-gate uint32_t sec;
2037c478bd9Sstevel@tonic-gate uint32_t usec;
2047c478bd9Sstevel@tonic-gate } tv;
2057c478bd9Sstevel@tonic-gate timestruc_t now;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate if (time == NULL) {
2087c478bd9Sstevel@tonic-gate gethrestime(&now);
2097c478bd9Sstevel@tonic-gate time = &now;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate #ifdef _LP64
2137c478bd9Sstevel@tonic-gate if (size)
2147c478bd9Sstevel@tonic-gate adr_int64(hadrp, (int64_t *)time, 2);
2157c478bd9Sstevel@tonic-gate else
2167c478bd9Sstevel@tonic-gate #endif
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate tv.sec = (uint32_t)time->tv_sec;
2197c478bd9Sstevel@tonic-gate tv.usec = (uint32_t)time->tv_nsec;
2207c478bd9Sstevel@tonic-gate adr_int32(hadrp, (int32_t *)&tv, 2);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate * Close an audit descriptor.
2277c478bd9Sstevel@tonic-gate * If time of event is specified, use it in the record, otherwise use the
2287c478bd9Sstevel@tonic-gate * current time.
2297c478bd9Sstevel@tonic-gate */
2307c478bd9Sstevel@tonic-gate void
au_close_time(au_kcontext_t * kctx,token_t * dchain,int flag,au_event_t e_type,au_emod_t e_mod,timestruc_t * etime)231d0fa49b7STony Nguyen au_close_time(au_kcontext_t *kctx, token_t *dchain, int flag, au_event_t e_type,
232d0fa49b7STony Nguyen au_emod_t e_mod, timestruc_t *etime)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate token_t *record; /* au_membuf chain == the record */
2357c478bd9Sstevel@tonic-gate int byte_count;
2367c478bd9Sstevel@tonic-gate token_t *m; /* for potential sequence token */
2377c478bd9Sstevel@tonic-gate adr_t hadr; /* handle for header token */
2387c478bd9Sstevel@tonic-gate adr_t sadr; /* handle for sequence token */
2397c478bd9Sstevel@tonic-gate size_t zone_length; /* length of zonename token */
240005d3febSMarek Pospisil uint32_t auditing;
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate ASSERT(dchain != NULL);
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate /* If not to be written, toss the record */
2457c478bd9Sstevel@tonic-gate if ((flag & AU_OK) == 0) {
2467c478bd9Sstevel@tonic-gate au_toss_token(dchain);
2477c478bd9Sstevel@tonic-gate return;
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate /* if auditing not enabled, then don't generate an audit record */
250005d3febSMarek Pospisil ASSERT(U2A(u) != NULL);
2517c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL);
2527c478bd9Sstevel@tonic-gate
253005d3febSMarek Pospisil auditing = (U2A(u)->tad_audit == AUC_UNSET)
254005d3febSMarek Pospisil ? kctx->auk_auditstate
255005d3febSMarek Pospisil : U2A(u)->tad_audit;
256005d3febSMarek Pospisil
257005d3febSMarek Pospisil if (auditing & ~(AUC_AUDITING | AUC_INIT_AUDIT)) {
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate * at system boot, neither is set yet we want to generate
2607c478bd9Sstevel@tonic-gate * an audit record.
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate if (e_type != AUE_SYSTEMBOOT) {
2637c478bd9Sstevel@tonic-gate au_toss_token(dchain);
2647c478bd9Sstevel@tonic-gate return;
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /* Count up the bytes used in the record. */
2697c478bd9Sstevel@tonic-gate byte_count = au_token_size(dchain);
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate * add in size of header token (always present).
2737c478bd9Sstevel@tonic-gate */
2747c478bd9Sstevel@tonic-gate byte_count += sizeof (char) + sizeof (int32_t) +
2757c478bd9Sstevel@tonic-gate sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t);
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid)
278787b48eaSgww byte_count += sizeof (int32_t) +
279787b48eaSgww kctx->auk_info.ai_termid.at_type;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate * add in size of zonename token (zero if !AUDIT_ZONENAME)
2837c478bd9Sstevel@tonic-gate */
2847c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_ZONENAME) {
2851d7bfecdStz204579 zone_length = au_zonename_length(NULL);
2867c478bd9Sstevel@tonic-gate byte_count += zone_length;
2877c478bd9Sstevel@tonic-gate } else {
2887c478bd9Sstevel@tonic-gate zone_length = 0;
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate /* add in size of (optional) trailer token */
2917c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_TRAIL)
2927c478bd9Sstevel@tonic-gate byte_count += 7;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate /* add in size of (optional) sequence token */
2957c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_SEQ)
2967c478bd9Sstevel@tonic-gate byte_count += 5;
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate /* build the header */
2997c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid)
3007c478bd9Sstevel@tonic-gate record = au_to_header_ex(byte_count, e_type, e_mod);
3017c478bd9Sstevel@tonic-gate else
3027c478bd9Sstevel@tonic-gate record = au_to_header(byte_count, e_type, e_mod);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * If timestamp was specified, save it in header now. Otherwise,
3067c478bd9Sstevel@tonic-gate * save reference to header so we can update time/data later
3077c478bd9Sstevel@tonic-gate * and artificially adjust pointer to the time/date field of header.
3087c478bd9Sstevel@tonic-gate */
3097c478bd9Sstevel@tonic-gate adr_start(&hadr, memtod(record, char *));
3107c478bd9Sstevel@tonic-gate hadr.adr_now += sizeof (char) + sizeof (int32_t) +
3117c478bd9Sstevel@tonic-gate sizeof (char) + 2 * sizeof (short);
3127c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid)
3137c478bd9Sstevel@tonic-gate hadr.adr_now += sizeof (int32_t) +
3147c478bd9Sstevel@tonic-gate kctx->auk_info.ai_termid.at_type;
3157c478bd9Sstevel@tonic-gate if (etime != NULL) {
3167c478bd9Sstevel@tonic-gate au_save_time(&hadr, etime, 1);
3177c478bd9Sstevel@tonic-gate hadr.adr_now = (char *)NULL;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate /* append body of audit record */
3217c478bd9Sstevel@tonic-gate (void) au_append_rec(record, dchain, AU_PACK);
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate /* add (optional) zonename token */
3247c478bd9Sstevel@tonic-gate if (zone_length > 0) {
3251d7bfecdStz204579 m = au_to_zonename(zone_length, NULL);
3267c478bd9Sstevel@tonic-gate (void) au_append_rec(record, m, AU_PACK);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate /* Add an (optional) sequence token. NULL offset if none */
3307c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_SEQ) {
3317c478bd9Sstevel@tonic-gate /* get the sequence token */
3327c478bd9Sstevel@tonic-gate m = au_to_seq();
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate /* link to audit record (i.e. don't pack the data) */
3357c478bd9Sstevel@tonic-gate (void) au_append_rec(record, m, AU_LINK);
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate * advance to count field of sequence token by skipping
3397c478bd9Sstevel@tonic-gate * the token type byte.
3407c478bd9Sstevel@tonic-gate */
3417c478bd9Sstevel@tonic-gate adr_start(&sadr, memtod(m, char *));
3427c478bd9Sstevel@tonic-gate sadr.adr_now += 1;
3437c478bd9Sstevel@tonic-gate } else {
3447c478bd9Sstevel@tonic-gate sadr.adr_now = NULL;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate /* add (optional) trailer token */
3477c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_TRAIL) {
3487c478bd9Sstevel@tonic-gate (void) au_append_rec(record, au_to_trailer(byte_count),
3497c478bd9Sstevel@tonic-gate AU_PACK);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate * 1 - use 64 bit version of audit tokens for 64 bit kernels.
3547c478bd9Sstevel@tonic-gate * 0 - use 32 bit version of audit tokens for 32 bit kernels.
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate #ifdef _LP64
3577c478bd9Sstevel@tonic-gate au_enqueue(kctx, record, &hadr, &sadr, 1, flag & AU_DONTBLOCK);
3587c478bd9Sstevel@tonic-gate #else
3597c478bd9Sstevel@tonic-gate au_enqueue(kctx, record, &hadr, &sadr, 0, flag & AU_DONTBLOCK);
3607c478bd9Sstevel@tonic-gate #endif
3617c478bd9Sstevel@tonic-gate AS_INC(as_totalsize, byte_count, kctx);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3657c478bd9Sstevel@tonic-gate void
au_enqueue(au_kcontext_t * kctx,au_buff_t * m,adr_t * hadrp,adr_t * sadrp,int size,int dontblock)3667c478bd9Sstevel@tonic-gate au_enqueue(au_kcontext_t *kctx, au_buff_t *m, adr_t *hadrp, adr_t *sadrp,
3677c478bd9Sstevel@tonic-gate int size, int dontblock)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate if (kctx == NULL)
3707c478bd9Sstevel@tonic-gate return;
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock));
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate if (!dontblock && (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) &&
3757c478bd9Sstevel@tonic-gate audit_sync_block(kctx)) {
3767c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock));
3777c478bd9Sstevel@tonic-gate au_free_rec(m);
3787c478bd9Sstevel@tonic-gate return;
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate /* Fill in date and time if needed */
3827c478bd9Sstevel@tonic-gate if (hadrp->adr_now) {
3837c478bd9Sstevel@tonic-gate au_save_time(hadrp, NULL, size);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate /* address will be non-zero only if AUDIT_SEQ set */
3877c478bd9Sstevel@tonic-gate if (sadrp->adr_now) {
3887c478bd9Sstevel@tonic-gate kctx->auk_sequence++;
3897c478bd9Sstevel@tonic-gate adr_int32(sadrp, (int32_t *)&(kctx->auk_sequence), 1);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate if (kctx->auk_queue.head)
3937c478bd9Sstevel@tonic-gate kctx->auk_queue.tail->next_rec = m;
3947c478bd9Sstevel@tonic-gate else
3957c478bd9Sstevel@tonic-gate kctx->auk_queue.head = m;
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate kctx->auk_queue.tail = m;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (++(kctx->auk_queue.cnt) >
4007c478bd9Sstevel@tonic-gate kctx->auk_queue.lowater && kctx->auk_queue.rd_block)
4017c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.read_cv));
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock));
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate /* count # audit records put onto kernel audit queue */
4067c478bd9Sstevel@tonic-gate AS_INC(as_enqueue, 1, kctx);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate * Dequeue and free buffers upto and including "freeto"
4117c478bd9Sstevel@tonic-gate * Keeps the queue lock long but acquires it only once when doing
4127c478bd9Sstevel@tonic-gate * bulk dequeueing.
4137c478bd9Sstevel@tonic-gate */
4147c478bd9Sstevel@tonic-gate static void
au_dequeue(au_kcontext_t * kctx,au_buff_t * freeto)4157c478bd9Sstevel@tonic-gate au_dequeue(au_kcontext_t *kctx, au_buff_t *freeto)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate au_buff_t *m, *l, *lastl;
4187c478bd9Sstevel@tonic-gate int n = 0;
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock));
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate ASSERT(kctx->auk_queue.head != NULL);
4257c478bd9Sstevel@tonic-gate ASSERT(freeto != NULL);
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate l = m = kctx->auk_queue.head;
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate do {
4307c478bd9Sstevel@tonic-gate n++;
4317c478bd9Sstevel@tonic-gate lastl = l;
4327c478bd9Sstevel@tonic-gate l = l->next_rec;
4337c478bd9Sstevel@tonic-gate } while (l != NULL && freeto != lastl);
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate kctx->auk_queue.cnt -= n;
4367c478bd9Sstevel@tonic-gate lastl->next_rec = NULL;
4377c478bd9Sstevel@tonic-gate kctx->auk_queue.head = l;
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate /* Freeto must exist in the list */
4407c478bd9Sstevel@tonic-gate ASSERT(freeto == lastl);
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate if (kctx->auk_queue.cnt <= kctx->auk_queue.lowater &&
4437c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block)
4447c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.write_cv));
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock));
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate while (m) {
4497c478bd9Sstevel@tonic-gate l = m->next_rec;
4507c478bd9Sstevel@tonic-gate au_free_rec(m);
4517c478bd9Sstevel@tonic-gate m = l;
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate AS_INC(as_written, n, kctx);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate * audit_sync_block()
4587c478bd9Sstevel@tonic-gate * If we've reached the high water mark, we look at the policy to see
4597c478bd9Sstevel@tonic-gate * if we sleep or we should drop the audit record.
4607c478bd9Sstevel@tonic-gate * This function is called with the auk_queue.lock held and the check
4617c478bd9Sstevel@tonic-gate * performed one time already as an optimization. Caller should unlock.
4627c478bd9Sstevel@tonic-gate * Returns 1 if the caller needs to free the record.
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate static int
audit_sync_block(au_kcontext_t * kctx)4657c478bd9Sstevel@tonic-gate audit_sync_block(au_kcontext_t *kctx)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(kctx->auk_queue.lock)));
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate * Loop while we are at the high watermark.
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate do {
472005d3febSMarek Pospisil if (((U2A(u)->tad_audit != AUC_UNSET)
473005d3febSMarek Pospisil ? (U2A(u)->tad_audit != AUC_AUDITING)
474005d3febSMarek Pospisil : (kctx->auk_auditstate != AUC_AUDITING)) ||
4757c478bd9Sstevel@tonic-gate (kctx->auk_policy & AUDIT_CNT)) {
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate /* just count # of dropped audit records */
4787c478bd9Sstevel@tonic-gate AS_INC(as_dropped, 1, kctx);
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate return (1);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate /* kick reader awake if its asleep */
4847c478bd9Sstevel@tonic-gate if (kctx->auk_queue.rd_block &&
4857c478bd9Sstevel@tonic-gate kctx->auk_queue.cnt > kctx->auk_queue.lowater)
4867c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.read_cv));
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate /* keep count of # times blocked */
4897c478bd9Sstevel@tonic-gate AS_INC(as_wblocked, 1, kctx);
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /* sleep now, until woken by reader */
4927c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block++;
4937c478bd9Sstevel@tonic-gate cv_wait(&(kctx->auk_queue.write_cv), &(kctx->auk_queue.lock));
4947c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block--;
4957c478bd9Sstevel@tonic-gate } while (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater);
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate return (0);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate * audit_async_block()
5027c478bd9Sstevel@tonic-gate * if we've reached the high water mark, we look at the ahlt policy to see
5037c478bd9Sstevel@tonic-gate * if we reboot we should drop the audit record.
5047c478bd9Sstevel@tonic-gate * Returns 1 if blocked.
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate static int
audit_async_block(au_kcontext_t * kctx,caddr_t * rpp)5077c478bd9Sstevel@tonic-gate audit_async_block(au_kcontext_t *kctx, caddr_t *rpp)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock));
5127c478bd9Sstevel@tonic-gate /* see if we've reached high water mark */
5137c478bd9Sstevel@tonic-gate if (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) {
5147c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock));
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate audit_async_drop(rpp, AU_BACKEND);
5177c478bd9Sstevel@tonic-gate return (1);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock));
5207c478bd9Sstevel@tonic-gate return (0);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * au_door_upcall. auditdoor() may change vp without notice, so
5257c478bd9Sstevel@tonic-gate * some locking seems in order.
5267c478bd9Sstevel@tonic-gate *
5277c478bd9Sstevel@tonic-gate */
5287c478bd9Sstevel@tonic-gate #define AGAIN_TICKS 10
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate static int
au_door_upcall(au_kcontext_t * kctx,au_dbuf_t * aubuf)5317c478bd9Sstevel@tonic-gate au_door_upcall(au_kcontext_t *kctx, au_dbuf_t *aubuf)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate int rc;
5347c478bd9Sstevel@tonic-gate door_arg_t darg;
5357c478bd9Sstevel@tonic-gate int retry = 1;
5367c478bd9Sstevel@tonic-gate int ticks_to_wait;
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate darg.data_ptr = (char *)aubuf;
5397c478bd9Sstevel@tonic-gate darg.data_size = AU_DBUF_HEADER + aubuf->aub_size;
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate darg.desc_ptr = NULL;
5427c478bd9Sstevel@tonic-gate darg.desc_num = 0;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate while (retry == 1) {
5457c478bd9Sstevel@tonic-gate /* non-zero means return results expected */
5467c478bd9Sstevel@tonic-gate darg.rbuf = (char *)aubuf;
5477c478bd9Sstevel@tonic-gate darg.rsize = darg.data_size;
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate retry = 0;
5507c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_svc_lock));
551323a81d9Sjwadams rc = door_upcall(kctx->auk_current_vp, &darg, NULL,
552323a81d9Sjwadams SIZE_MAX, 0);
553024b0a25Sseb if (rc != 0) {
5547c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock));
5557c478bd9Sstevel@tonic-gate if (rc == EAGAIN)
5567c478bd9Sstevel@tonic-gate ticks_to_wait = AGAIN_TICKS;
5577c478bd9Sstevel@tonic-gate else
5587c478bd9Sstevel@tonic-gate return (rc);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_eagain_mutex));
561d3d50737SRafael Vanoni (void) cv_reltimedwait(&(kctx->auk_eagain_cv),
562d3d50737SRafael Vanoni &(kctx->auk_eagain_mutex), ticks_to_wait,
563d3d50737SRafael Vanoni TR_CLOCK_TICK);
5647c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_eagain_mutex));
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate retry = 1;
5677c478bd9Sstevel@tonic-gate } else
5687c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock)); /* no retry */
5697c478bd9Sstevel@tonic-gate } /* end while (retry == 1) */
5707c478bd9Sstevel@tonic-gate if (darg.rbuf == NULL)
5717c478bd9Sstevel@tonic-gate return (-1);
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate /* return code from door server */
5747c478bd9Sstevel@tonic-gate return (*(int *)darg.rbuf);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate * Write an audit control message to the door handle. The message
5797c478bd9Sstevel@tonic-gate * structure depends on message_code and at present the only control
5807c478bd9Sstevel@tonic-gate * message defined is for a policy change. These are infrequent,
5817c478bd9Sstevel@tonic-gate * so no memory is held for control messages.
5827c478bd9Sstevel@tonic-gate */
5837c478bd9Sstevel@tonic-gate int
au_doormsg(au_kcontext_t * kctx,uint32_t message_code,void * message)5847c478bd9Sstevel@tonic-gate au_doormsg(au_kcontext_t *kctx, uint32_t message_code, void *message)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate int rc;
5877c478bd9Sstevel@tonic-gate au_dbuf_t *buf;
5887c478bd9Sstevel@tonic-gate size_t alloc_size;
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate switch (message_code) {
5917c478bd9Sstevel@tonic-gate case AU_DBUF_POLICY:
5927c478bd9Sstevel@tonic-gate alloc_size = AU_DBUF_HEADER + sizeof (uint32_t);
5937c478bd9Sstevel@tonic-gate buf = kmem_alloc(alloc_size, KM_SLEEP);
5947c478bd9Sstevel@tonic-gate buf->aub_size = sizeof (uint32_t);
5957c478bd9Sstevel@tonic-gate *(uint32_t *)buf->aub_buf = *(uint32_t *)message;
5967c478bd9Sstevel@tonic-gate break;
5977c478bd9Sstevel@tonic-gate case AU_DBUF_SHUTDOWN:
5987c478bd9Sstevel@tonic-gate alloc_size = AU_DBUF_HEADER;
5997c478bd9Sstevel@tonic-gate buf = kmem_alloc(alloc_size, KM_SLEEP);
6007c478bd9Sstevel@tonic-gate buf->aub_size = 0;
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate default:
6037c478bd9Sstevel@tonic-gate return (1);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate buf->aub_type = AU_DBUF_NOTIFY | message_code;
6077c478bd9Sstevel@tonic-gate rc = au_door_upcall(kctx, buf);
6087c478bd9Sstevel@tonic-gate kmem_free(buf, alloc_size);
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate return (rc);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate /*
6147c478bd9Sstevel@tonic-gate * Write audit information to the door handle. au_doorio is called with
6157c478bd9Sstevel@tonic-gate * one or more complete audit records on the queue and outputs those
6167c478bd9Sstevel@tonic-gate * records in buffers of up to auk_queue.buflen in size.
6177c478bd9Sstevel@tonic-gate */
6187c478bd9Sstevel@tonic-gate int
au_doorio(au_kcontext_t * kctx)6197c478bd9Sstevel@tonic-gate au_doorio(au_kcontext_t *kctx) {
6207c478bd9Sstevel@tonic-gate off_t off; /* space used in buffer */
6217c478bd9Sstevel@tonic-gate ssize_t used; /* space used in au_membuf */
6227c478bd9Sstevel@tonic-gate token_t *cAR; /* current AR being processed */
6237c478bd9Sstevel@tonic-gate token_t *cMB; /* current au_membuf being processed */
6247c478bd9Sstevel@tonic-gate token_t *sp; /* last AR processed */
6257c478bd9Sstevel@tonic-gate char *bp; /* start of free space in staging buffer */
6267c478bd9Sstevel@tonic-gate unsigned char *cp; /* ptr to data to be moved */
627*1700d80aSMarek Pospisil int error = 0; /* return from door upcall */
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate * size (data left in au_membuf - space in buffer)
6317c478bd9Sstevel@tonic-gate */
6327c478bd9Sstevel@tonic-gate ssize_t sz;
6337c478bd9Sstevel@tonic-gate ssize_t len; /* len of data to move, size of AR */
6347c478bd9Sstevel@tonic-gate ssize_t curr_sz = 0; /* amount of data written during now */
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate int part = 0; /* partial audit record written */
6397c478bd9Sstevel@tonic-gate int partial_state = AU_DBUF_COMPLETE;
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate * Has the write buffer changed length due to a auditctl(2)?
6427c478bd9Sstevel@tonic-gate * Initial allocation is from audit_start.c/audit_init()
6437c478bd9Sstevel@tonic-gate */
6447c478bd9Sstevel@tonic-gate if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) {
6455562c04eSMarek Pospisil size_t new_sz = kctx->auk_queue.bufsz;
6465562c04eSMarek Pospisil
6477c478bd9Sstevel@tonic-gate kmem_free(kctx->auk_dbuffer, AU_DBUF_HEADER +
6487c478bd9Sstevel@tonic-gate kctx->auk_queue.buflen);
6497c478bd9Sstevel@tonic-gate
6505562c04eSMarek Pospisil kctx->auk_dbuffer = kmem_alloc(AU_DBUF_HEADER + new_sz,
6515562c04eSMarek Pospisil KM_SLEEP);
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate /* omit the 64 bit header */
6545562c04eSMarek Pospisil kctx->auk_queue.buflen = new_sz;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate if (!kctx->auk_queue.head)
6577c478bd9Sstevel@tonic-gate goto nodata;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate sp = NULL; /* no record copied */
6607c478bd9Sstevel@tonic-gate off = 0; /* no space used in buffer */
6617c478bd9Sstevel@tonic-gate used = 0; /* no data processed in au_membuf */
6627c478bd9Sstevel@tonic-gate cAR = kctx->auk_queue.head; /* start at head of queue */
6637c478bd9Sstevel@tonic-gate cMB = cAR; /* start with first au_membuf of record */
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate /* start at beginning of buffer */
6667c478bd9Sstevel@tonic-gate bp = &(kctx->auk_dbuffer->aub_buf[0]);
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate while (cMB) {
6697c478bd9Sstevel@tonic-gate part = 1; /* indicate audit record being processed */
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate cp = memtod(cMB, unsigned char *); /* buffer ptr */
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate sz = (ssize_t)cMB->len - used; /* data left in au_membuf */
6747c478bd9Sstevel@tonic-gate /* len to move */
6757c478bd9Sstevel@tonic-gate len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off);
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /* move the data */
6787c478bd9Sstevel@tonic-gate bcopy(cp + used, bp + off, len);
6797c478bd9Sstevel@tonic-gate used += len; /* update used au_membuf */
6807c478bd9Sstevel@tonic-gate off += len; /* update offset into buffer */
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate if (used >= (ssize_t)cMB->len) {
6837c478bd9Sstevel@tonic-gate /* advance to next au_membuf */
6847c478bd9Sstevel@tonic-gate used = 0;
6857c478bd9Sstevel@tonic-gate cMB = cMB->next_buf;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate if (cMB == NULL) {
6887c478bd9Sstevel@tonic-gate /* advance to next audit record */
6897c478bd9Sstevel@tonic-gate sp = cAR;
6907c478bd9Sstevel@tonic-gate cAR = cAR->next_rec;
6917c478bd9Sstevel@tonic-gate cMB = cAR;
6927c478bd9Sstevel@tonic-gate part = 0; /* have a complete record */
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate error = 0;
6957c478bd9Sstevel@tonic-gate if ((kctx->auk_queue.buflen == off) || (part == 0)) {
6967c478bd9Sstevel@tonic-gate if (part)
6977c478bd9Sstevel@tonic-gate partial_state = state_if_part[partial_state];
6987c478bd9Sstevel@tonic-gate else
6997c478bd9Sstevel@tonic-gate partial_state =
7007c478bd9Sstevel@tonic-gate state_if_not_part[partial_state];
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate kctx->auk_dbuffer->aub_type = partial_state;
7037c478bd9Sstevel@tonic-gate kctx->auk_dbuffer->aub_size = off;
7047c478bd9Sstevel@tonic-gate error = au_door_upcall(kctx, kctx->auk_dbuffer);
7057c478bd9Sstevel@tonic-gate if (error != 0)
7067c478bd9Sstevel@tonic-gate goto nodata;
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate * if we've successfully written an audit record,
7097c478bd9Sstevel@tonic-gate * free records up to last full record copied
7107c478bd9Sstevel@tonic-gate */
7117c478bd9Sstevel@tonic-gate if (sp)
7127c478bd9Sstevel@tonic-gate au_dequeue(kctx, sp);
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate /* Update size */
7157c478bd9Sstevel@tonic-gate curr_sz += off;
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate /* reset auk_dbuffer pointers */
7187c478bd9Sstevel@tonic-gate sp = NULL;
7197c478bd9Sstevel@tonic-gate off = 0;
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate } /* while(cMB) */
7227c478bd9Sstevel@tonic-gate nodata:
7237c478bd9Sstevel@tonic-gate return (error);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate /*
7277c478bd9Sstevel@tonic-gate * Clean up thread audit state to clear out asynchronous audit record
7287c478bd9Sstevel@tonic-gate * generation error recovery processing. Note that this is done on a
7297c478bd9Sstevel@tonic-gate * per-thread basis and thus does not need any locking.
7307c478bd9Sstevel@tonic-gate */
7317c478bd9Sstevel@tonic-gate void
audit_async_done(caddr_t * rpp,int flags)7327c478bd9Sstevel@tonic-gate audit_async_done(caddr_t *rpp, int flags)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u);
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate /* clean up the tad unless called from softcall backend */
7377c478bd9Sstevel@tonic-gate if (!(flags & AU_BACKEND)) {
7387c478bd9Sstevel@tonic-gate ASSERT(tad != NULL);
7394a0fa546SMarek Pospisil ASSERT(tad->tad_ctrl & TAD_ERRJMP);
7407c478bd9Sstevel@tonic-gate
7414a0fa546SMarek Pospisil tad->tad_ctrl &= ~TAD_ERRJMP;
7427c478bd9Sstevel@tonic-gate tad->tad_errjmp = NULL;
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /* clean out partial audit record */
7467c478bd9Sstevel@tonic-gate if ((rpp != NULL) && (*rpp != NULL)) {
7477c478bd9Sstevel@tonic-gate au_toss_token((au_buff_t *)*rpp);
7487c478bd9Sstevel@tonic-gate *rpp = NULL;
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate /*
7537c478bd9Sstevel@tonic-gate * implement the audit policy for asynchronous events generated within
7547c478bd9Sstevel@tonic-gate * the kernel.
7557c478bd9Sstevel@tonic-gate * XXX might need locks around audit_policy check.
7567c478bd9Sstevel@tonic-gate */
7577c478bd9Sstevel@tonic-gate void
audit_async_drop(caddr_t * rpp,int flags)7587c478bd9Sstevel@tonic-gate audit_async_drop(caddr_t *rpp, int flags)
7597c478bd9Sstevel@tonic-gate {
7607c478bd9Sstevel@tonic-gate au_kcontext_t *kctx;
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate /* could not generate audit record, clean up */
7637c478bd9Sstevel@tonic-gate audit_async_done((caddr_t *)rpp, flags);
7647c478bd9Sstevel@tonic-gate
7659e9e6ab8Spaulson kctx = GET_KCTX_GZ;
7669e9e6ab8Spaulson
7677c478bd9Sstevel@tonic-gate /* just drop the record and return */
7687c478bd9Sstevel@tonic-gate if (((audit_policy & AUDIT_AHLT) == 0) ||
7697c478bd9Sstevel@tonic-gate (kctx->auk_auditstate == AUC_INIT_AUDIT)) {
7707c478bd9Sstevel@tonic-gate /* just count # of dropped audit records */
7717c478bd9Sstevel@tonic-gate AS_INC(as_dropped, 1, kctx);
7727c478bd9Sstevel@tonic-gate return;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * There can be a lot of data in the audit queue. We
7777c478bd9Sstevel@tonic-gate * will first sync the file systems then attempt to
7787c478bd9Sstevel@tonic-gate * shutdown the kernel so that a memory dump is
7797c478bd9Sstevel@tonic-gate * performed.
7807c478bd9Sstevel@tonic-gate */
7817c478bd9Sstevel@tonic-gate sync();
7827c478bd9Sstevel@tonic-gate sync();
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate * now shut down. What a cruel world it has been
7867c478bd9Sstevel@tonic-gate */
7877c478bd9Sstevel@tonic-gate panic("non-attributable halt. should dump core");
7887c478bd9Sstevel@tonic-gate /* No return */
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate int
audit_async_start(label_t * jb,au_event_t event,int sorf)792d0fa49b7STony Nguyen audit_async_start(label_t *jb, au_event_t event, int sorf)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u);
7957c478bd9Sstevel@tonic-gate au_state_t estate;
7967c478bd9Sstevel@tonic-gate int success = 0, failure = 0;
7979e9e6ab8Spaulson au_kcontext_t *kctx = GET_KCTX_GZ;
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /* if audit state off, then no audit record generation */
8007c478bd9Sstevel@tonic-gate if ((kctx->auk_auditstate != AUC_AUDITING) &&
8017c478bd9Sstevel@tonic-gate (kctx->auk_auditstate != AUC_INIT_AUDIT))
8027c478bd9Sstevel@tonic-gate return (1);
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate * preselect asynchronous event
8067c478bd9Sstevel@tonic-gate * XXX should we check for out-of-range???
8077c478bd9Sstevel@tonic-gate */
8087c478bd9Sstevel@tonic-gate estate = kctx->auk_ets[event];
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate if (sorf & AUM_SUCC)
811f8994074SJan Friedel success = kctx->auk_info.ai_namask.as_success & estate;
8127c478bd9Sstevel@tonic-gate if (sorf & AUM_FAIL)
813f8994074SJan Friedel failure = kctx->auk_info.ai_namask.as_failure & estate;
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate if ((success | failure) == NULL)
8167c478bd9Sstevel@tonic-gate return (1);
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate ASSERT(tad->tad_errjmp == NULL);
8197c478bd9Sstevel@tonic-gate tad->tad_errjmp = (void *)jb;
8204a0fa546SMarek Pospisil tad->tad_ctrl |= TAD_ERRJMP;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate return (0);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate * Complete auditing of an async event. The AU_DONTBLOCK flag to au_close will
8277c478bd9Sstevel@tonic-gate * result in the backend routine being invoked from softcall, so all the real
8287c478bd9Sstevel@tonic-gate * work can be done in a safe context.
8297c478bd9Sstevel@tonic-gate */
8307c478bd9Sstevel@tonic-gate void
audit_async_finish(caddr_t * ad,au_event_t aid,au_emod_t amod,timestruc_t * e_time)831005d3febSMarek Pospisil audit_async_finish(caddr_t *ad, au_event_t aid, au_emod_t amod,
832005d3febSMarek Pospisil timestruc_t *e_time)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate au_kcontext_t *kctx;
8357c478bd9Sstevel@tonic-gate
8369e9e6ab8Spaulson kctx = GET_KCTX_GZ;
8377c478bd9Sstevel@tonic-gate
838005d3febSMarek Pospisil au_close(kctx, ad, AU_DONTBLOCK | AU_OK, aid, PAD_NONATTR|amod, e_time);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate * Backend routine to complete an async audit. Invoked from softcall.
8437c478bd9Sstevel@tonic-gate * (Note: the blocking and the queuing below both involve locking which can't
8447c478bd9Sstevel@tonic-gate * be done safely in high interrupt context due to the chance of sleeping on
8457c478bd9Sstevel@tonic-gate * the corresponding adaptive mutex. Hence the softcall.)
8467c478bd9Sstevel@tonic-gate */
8477c478bd9Sstevel@tonic-gate static void
audit_async_finish_backend(void * addr)8487c478bd9Sstevel@tonic-gate audit_async_finish_backend(void *addr)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate au_kcontext_t *kctx;
8517c478bd9Sstevel@tonic-gate au_defer_info_t *attr = (au_defer_info_t *)addr;
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate if (attr == NULL)
8547c478bd9Sstevel@tonic-gate return; /* won't happen unless softcall is broken */
8557c478bd9Sstevel@tonic-gate
8569e9e6ab8Spaulson kctx = GET_KCTX_GZ;
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate if (audit_async_block(kctx, (caddr_t *)&attr->audi_ad)) {
8597c478bd9Sstevel@tonic-gate kmem_free(attr, sizeof (au_defer_info_t));
8607c478bd9Sstevel@tonic-gate return;
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate /*
8647c478bd9Sstevel@tonic-gate * Call au_close_time to complete the audit with the saved values.
8657c478bd9Sstevel@tonic-gate *
8667c478bd9Sstevel@tonic-gate * For the exit-prom event, use the current time instead of the
8677c478bd9Sstevel@tonic-gate * saved time as a better approximation. (Because the time saved via
8687c478bd9Sstevel@tonic-gate * gethrestime during prom-exit handling would not yet be caught up
8697c478bd9Sstevel@tonic-gate * after the system was idled in the debugger for a period of time.)
8707c478bd9Sstevel@tonic-gate */
8717c478bd9Sstevel@tonic-gate if (attr->audi_e_type == AUE_EXITPROM) {
8727c478bd9Sstevel@tonic-gate au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag,
8737c478bd9Sstevel@tonic-gate attr->audi_e_type, attr->audi_e_mod, NULL);
8747c478bd9Sstevel@tonic-gate } else {
8757c478bd9Sstevel@tonic-gate au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag,
8767c478bd9Sstevel@tonic-gate attr->audi_e_type, attr->audi_e_mod, &attr->audi_atime);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate AS_INC(as_generated, 1, kctx);
8807c478bd9Sstevel@tonic-gate AS_INC(as_nonattrib, 1, kctx);
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate kmem_free(attr, sizeof (au_defer_info_t));
8837c478bd9Sstevel@tonic-gate }
884