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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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