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 51d7bfecdStz * Common Development and Distribution License (the "License"). 61d7bfecdStz * 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 /* 227c478bd9Sstevel@tonic-gate * Routines for writing audit records. 237c478bd9Sstevel@tonic-gate * 241d7bfecdStz * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/door.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/time.h> 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> /* for statfs */ 357c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 367c478bd9Sstevel@tonic-gate #include <sys/file.h> 377c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/user.h> 397c478bd9Sstevel@tonic-gate #include <sys/uio.h> 407c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 417c478bd9Sstevel@tonic-gate #include <sys/kmem.h> /* for KM_SLEEP */ 427c478bd9Sstevel@tonic-gate #include <sys/resource.h> /* for RLIM_INFINITY */ 437c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> /* panic */ 447c478bd9Sstevel@tonic-gate #include <sys/systm.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 477c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 487c478bd9Sstevel@tonic-gate #include <sys/zone.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <c2/audit.h> 517c478bd9Sstevel@tonic-gate #include <c2/audit_kernel.h> 527c478bd9Sstevel@tonic-gate #include <c2/audit_record.h> 537c478bd9Sstevel@tonic-gate #include <c2/audit_kevents.h> 547c478bd9Sstevel@tonic-gate #include <c2/audit_door_infc.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static void au_dequeue(au_kcontext_t *, au_buff_t *); 577c478bd9Sstevel@tonic-gate static void audit_async_finish_backend(void *); 587c478bd9Sstevel@tonic-gate static int audit_sync_block(au_kcontext_t *); 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * each of these two tables are indexed by the values AU_DBUF_COMPLETE 617c478bd9Sstevel@tonic-gate * through AU_DBUF_LAST; the content is the next state value. The 627c478bd9Sstevel@tonic-gate * first table determines the next state for a buffer which is not the 637c478bd9Sstevel@tonic-gate * end of a record and the second table determines the state for a 647c478bd9Sstevel@tonic-gate * buffer which is the end of a record. The initial state is 657c478bd9Sstevel@tonic-gate * AU_DBUF_COMPLETE. 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static int state_if_part[] = { 687c478bd9Sstevel@tonic-gate AU_DBUF_FIRST, AU_DBUF_MIDDLE, AU_DBUF_MIDDLE, AU_DBUF_FIRST}; 697c478bd9Sstevel@tonic-gate static int state_if_not_part[] = { 707c478bd9Sstevel@tonic-gate AU_DBUF_COMPLETE, AU_DBUF_LAST, AU_DBUF_LAST, AU_DBUF_COMPLETE}; 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * Write to an audit descriptor. 737c478bd9Sstevel@tonic-gate * Add the au_membuf to the descriptor chain and free the chain passed in. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate void 767c478bd9Sstevel@tonic-gate au_uwrite(m) 777c478bd9Sstevel@tonic-gate token_t *m; 787c478bd9Sstevel@tonic-gate { 797c478bd9Sstevel@tonic-gate au_write(&(u_ad), m); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate void 837c478bd9Sstevel@tonic-gate au_write(caddr_t *d, token_t *m) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate if (d == NULL) { 867c478bd9Sstevel@tonic-gate au_toss_token(m); 877c478bd9Sstevel@tonic-gate return; 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate if (m == (token_t *)0) { 907c478bd9Sstevel@tonic-gate printf("au_write: null token\n"); 917c478bd9Sstevel@tonic-gate return; 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (*d == NULL) 957c478bd9Sstevel@tonic-gate *d = (caddr_t)m; 967c478bd9Sstevel@tonic-gate else 977c478bd9Sstevel@tonic-gate (void) au_append_rec((au_buff_t *)*d, m, AU_PACK); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate #define AU_INTERVAL 120 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Write audit information to the disk. 1037c478bd9Sstevel@tonic-gate * Called from auditsvc(); EOL'd as of Sol 10. 1047c478bd9Sstevel@tonic-gate * Local zones are not allowed; the caller (auditsvc()) enforces the 1057c478bd9Sstevel@tonic-gate * restriction. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate int 1087c478bd9Sstevel@tonic-gate au_doio(vp, limit) 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate struct vnode *vp; 1117c478bd9Sstevel@tonic-gate int limit; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate { /* AU_DOIO */ 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate off_t off; /* space used in buffer */ 1167c478bd9Sstevel@tonic-gate size_t used; /* space used in au_membuf */ 1177c478bd9Sstevel@tonic-gate token_t *cAR; /* current AR being processed */ 1187c478bd9Sstevel@tonic-gate token_t *cMB; /* current au_membuf being processed */ 1197c478bd9Sstevel@tonic-gate token_t *sp; /* last AR processed */ 1207c478bd9Sstevel@tonic-gate char *bp; /* start of free space in staging buffer */ 1217c478bd9Sstevel@tonic-gate unsigned char *cp; /* ptr to data to be moved */ 1227c478bd9Sstevel@tonic-gate au_kcontext_t *kctx; 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * size (data left in au_membuf - space in buffer) 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate ssize_t sz; 1277c478bd9Sstevel@tonic-gate ssize_t len; /* len of data to move, size of AR */ 1287c478bd9Sstevel@tonic-gate int error; /* error return */ 1297c478bd9Sstevel@tonic-gate ssize_t left; /* data not xfered by write to disk */ 1307c478bd9Sstevel@tonic-gate statvfs64_t sb; /* buffer for statfs */ 1317c478bd9Sstevel@tonic-gate size_t curr_sz = 0; /* amount of data written during now */ 1327c478bd9Sstevel@tonic-gate int part = 0; /* partial audit record written */ 1337c478bd9Sstevel@tonic-gate int partial = 0; /* flag to force partial AR to file */ 1347c478bd9Sstevel@tonic-gate /* 0 - idle, ignore */ 1357c478bd9Sstevel@tonic-gate /* 1 - force write of audit record */ 1367c478bd9Sstevel@tonic-gate /* 2 - finished writing AR, commit */ 1377c478bd9Sstevel@tonic-gate 138*9e9e6ab8Spaulson kctx = GET_KCTX_GZ; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * Check to ensure enough free space on audit device. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate bzero(&sb, sizeof (statvfs64_t)); 1447c478bd9Sstevel@tonic-gate (void) VFS_STATVFS(vp->v_vfsp, &sb); 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * Large Files: We do not convert any of this part of kernel 1477c478bd9Sstevel@tonic-gate * to be large file aware. Original behaviour should be 1487c478bd9Sstevel@tonic-gate * maintained. This function is called from audit_svc and 1497c478bd9Sstevel@tonic-gate * it already checks for negative values of limit. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (sb.f_blocks && (fsblkcnt64_t)limit > sb.f_bavail) 1537c478bd9Sstevel@tonic-gate return (ENOSPC); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (kctx->auk_file_stat.af_filesz && 1567c478bd9Sstevel@tonic-gate (kctx->auk_file_stat.af_currsz >= 1577c478bd9Sstevel@tonic-gate kctx->auk_file_stat.af_filesz)) 1587c478bd9Sstevel@tonic-gate return (EFBIG); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * has the write buffer changed length due to a auditctl(2)? 1627c478bd9Sstevel@tonic-gate * (remember that auk_buffer is an element of auk_dbuffer) 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) { 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate kmem_free(kctx->auk_buffer, kctx->auk_queue.buflen); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* bad, should not sleep here. Testing only */ 1697c478bd9Sstevel@tonic-gate kctx->auk_buffer = kmem_alloc(kctx->auk_queue.bufsz, KM_SLEEP); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate kctx->auk_queue.buflen = kctx->auk_queue.bufsz; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (!kctx->auk_queue.head) { 1757c478bd9Sstevel@tonic-gate goto nodata; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate sp = (token_t *)0; /* no AR copied */ 1787c478bd9Sstevel@tonic-gate off = 0; /* no space used in buffer */ 1797c478bd9Sstevel@tonic-gate used = 0; /* no data processed in au_membuf */ 1807c478bd9Sstevel@tonic-gate cAR = kctx->auk_queue.head; /* start at head of queue */ 1817c478bd9Sstevel@tonic-gate cMB = cAR; /* start with first au_membuf of record */ 1827c478bd9Sstevel@tonic-gate bp = &(kctx->auk_buffer[0]); /* start at beginning of buffer */ 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate while (cMB) { 1857c478bd9Sstevel@tonic-gate ASSERT(kctx->auk_queue.head != NULL); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* indicate audit record being processed */ 1887c478bd9Sstevel@tonic-gate part = 1; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate /* pointer to buffer data */ 1917c478bd9Sstevel@tonic-gate cp = memtod(cMB, unsigned char *); 1927c478bd9Sstevel@tonic-gate /* data left in au_membuf */ 1937c478bd9Sstevel@tonic-gate sz = (ssize_t)cMB->len - used; 1947c478bd9Sstevel@tonic-gate /* len to move */ 1957c478bd9Sstevel@tonic-gate len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* move the data */ 1987c478bd9Sstevel@tonic-gate bcopy(cp + used, bp + off, len); 1997c478bd9Sstevel@tonic-gate used += len; /* update used au_membuf */ 2007c478bd9Sstevel@tonic-gate off += len; /* update offset into buffer */ 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (used >= (ssize_t)cMB->len) { 2037c478bd9Sstevel@tonic-gate /* advance to next au_membuf */ 2047c478bd9Sstevel@tonic-gate used = 0; 2057c478bd9Sstevel@tonic-gate cMB = cMB->next_buf; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate if (cMB == (au_buff_t *)0) { 2087c478bd9Sstevel@tonic-gate /* advance to next AR */ 2097c478bd9Sstevel@tonic-gate sp = cAR; 2107c478bd9Sstevel@tonic-gate cAR = cAR->next_rec; 2117c478bd9Sstevel@tonic-gate cMB = cAR; 2127c478bd9Sstevel@tonic-gate /* reached end of an audit record */ 2137c478bd9Sstevel@tonic-gate part = 0; 2147c478bd9Sstevel@tonic-gate /* force abort at end of audit record? */ 2157c478bd9Sstevel@tonic-gate if (partial == 1) 2167c478bd9Sstevel@tonic-gate partial = 2; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * If we've reached end of buffer, or have run out of 2207c478bd9Sstevel@tonic-gate * audit records on the queue or we've processed a 2217c478bd9Sstevel@tonic-gate * partial audit record to complete the audit file, 2227c478bd9Sstevel@tonic-gate * then its time to flush the holding buffer to the 2237c478bd9Sstevel@tonic-gate * audit trail. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate if ((kctx->auk_queue.buflen == off) || 2267c478bd9Sstevel@tonic-gate (cAR == (au_buff_t *)0) || 2277c478bd9Sstevel@tonic-gate (partial == 2)) { 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate left = 0; 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Largefiles: We purposely pass a value of 2327c478bd9Sstevel@tonic-gate * MAXOFF_T as we do not want any of the 2337c478bd9Sstevel@tonic-gate * auditing files to exceed 2GB. May be we will 2347c478bd9Sstevel@tonic-gate * support this in future. 2357c478bd9Sstevel@tonic-gate */ 2367c478bd9Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, vp, kctx->auk_buffer, 2377c478bd9Sstevel@tonic-gate off, 0LL, UIO_SYSSPACE, FAPPEND, 2387c478bd9Sstevel@tonic-gate (rlim64_t)MAXOFF_T, CRED(), &left); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* error on write */ 2417c478bd9Sstevel@tonic-gate if (error != 0) { 2427c478bd9Sstevel@tonic-gate if (error == EDQUOT) 2437c478bd9Sstevel@tonic-gate error = ENOSPC; 2447c478bd9Sstevel@tonic-gate return (error); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* end of file system? */ 2487c478bd9Sstevel@tonic-gate if (left) { 2497c478bd9Sstevel@tonic-gate au_buff_t *b = NULL; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate sz = off - left; /* how much written */ 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* update space counters */ 2547c478bd9Sstevel@tonic-gate kctx->auk_file_stat.af_currsz += sz; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* which AR are done */ 2577c478bd9Sstevel@tonic-gate cAR = kctx->auk_queue.head; 2587c478bd9Sstevel@tonic-gate while (sz) { 2597c478bd9Sstevel@tonic-gate cp = memtod(cAR, unsigned char *); 2607c478bd9Sstevel@tonic-gate len = (ssize_t)((cp[1]<<24 | cp[2]<<16 | 2617c478bd9Sstevel@tonic-gate cp[3]<<8 | cp[4]) & 2627c478bd9Sstevel@tonic-gate 0xffffffffU); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate if (len > sz) 2657c478bd9Sstevel@tonic-gate break; 2667c478bd9Sstevel@tonic-gate b = cAR; 2677c478bd9Sstevel@tonic-gate cAR = cAR->next_rec; 2687c478bd9Sstevel@tonic-gate sz -= len; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate if (b != NULL) 2717c478bd9Sstevel@tonic-gate au_dequeue(kctx, b); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate return (ENOSPC); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate } else { /* still space in file system */ 2767c478bd9Sstevel@tonic-gate /* if we've written an AR */ 2777c478bd9Sstevel@tonic-gate if (sp) { 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * free records up to last one copied. 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate au_dequeue(kctx, sp); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate /* Update sizes */ 2847c478bd9Sstevel@tonic-gate curr_sz += off; 2857c478bd9Sstevel@tonic-gate kctx->auk_file_stat.af_currsz += (uint_t)off; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* reset auk_buffer pointers */ 2887c478bd9Sstevel@tonic-gate sp = (token_t *)0; 2897c478bd9Sstevel@tonic-gate off = 0; 2907c478bd9Sstevel@tonic-gate bp = &(kctx->auk_buffer[0]); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* check exit conditions */ 2937c478bd9Sstevel@tonic-gate if (sb.f_blocks) { 2947c478bd9Sstevel@tonic-gate ulong_t blks_used; 2957c478bd9Sstevel@tonic-gate blks_used = (curr_sz / sb.f_bsize); 2967c478bd9Sstevel@tonic-gate if ((fsblkcnt64_t)limit > 2977c478bd9Sstevel@tonic-gate (sb.f_bavail - (fsblkcnt64_t)blks_used)) { 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * if we haven't put out a 3007c478bd9Sstevel@tonic-gate * complete audit record, 3017c478bd9Sstevel@tonic-gate * continue to process the 3027c478bd9Sstevel@tonic-gate * audit queue until we reach 3037c478bd9Sstevel@tonic-gate * the end of the record. 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate if (part && (partial == 0)) { 3067c478bd9Sstevel@tonic-gate partial = 1; 3077c478bd9Sstevel@tonic-gate continue; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * exit if complete record 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate if (partial != 1) 3137c478bd9Sstevel@tonic-gate return (ENOSPC); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate if (kctx->auk_file_stat.af_filesz && 3177c478bd9Sstevel@tonic-gate (kctx->auk_file_stat.af_currsz 3187c478bd9Sstevel@tonic-gate >= kctx->auk_file_stat.af_filesz)) { 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * force a complete audit 3217c478bd9Sstevel@tonic-gate * record to the trail. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate if (partial == 0) 3247c478bd9Sstevel@tonic-gate partial = 1; 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Written data to AR boundry. 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate if (partial != 1) 3297c478bd9Sstevel@tonic-gate return (EFBIG); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate } /* while(cMB) */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate nodata: 3367c478bd9Sstevel@tonic-gate return (0); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * Close an audit descriptor. 3417c478bd9Sstevel@tonic-gate * Use the second parameter to indicate if it should be written or not. 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate void 3447c478bd9Sstevel@tonic-gate au_close(au_kcontext_t *kctx, caddr_t *d, int flag, short e_type, short e_mod) 3457c478bd9Sstevel@tonic-gate { 3467c478bd9Sstevel@tonic-gate token_t *dchain; /* au_membuf chain which is the tokens */ 3477c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate ASSERT(tad != NULL); 3507c478bd9Sstevel@tonic-gate ASSERT(d != NULL); 3517c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if ((dchain = (token_t *)*d) == (token_t *)NULL) 3547c478bd9Sstevel@tonic-gate return; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate *d = NULL; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * If async then defer; or if requested, defer the closing/queueing to 3607c478bd9Sstevel@tonic-gate * syscall end, unless no syscall is active or the syscall is _exit. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate if ((flag & AU_DONTBLOCK) || ((flag & AU_DEFER) && 3637c478bd9Sstevel@tonic-gate (tad->tad_scid != 0) && (tad->tad_scid != SYS_exit))) { 3647c478bd9Sstevel@tonic-gate au_close_defer(dchain, flag, e_type, e_mod); 3657c478bd9Sstevel@tonic-gate return; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate au_close_time(kctx, dchain, flag, e_type, e_mod, NULL); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * Defer closing/queueing of an audit descriptor. For async events, queue 3727c478bd9Sstevel@tonic-gate * via softcall. Otherwise, defer by queueing the record onto the tad; at 3737c478bd9Sstevel@tonic-gate * syscall end time it will be pulled off. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate void 3767c478bd9Sstevel@tonic-gate au_close_defer(token_t *dchain, int flag, short e_type, short e_mod) 3777c478bd9Sstevel@tonic-gate { 3787c478bd9Sstevel@tonic-gate au_defer_info_t *attr; 3797c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate ASSERT(tad != NULL); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* If not to be written, toss the record. */ 3847c478bd9Sstevel@tonic-gate if ((flag & AU_OK) == 0) { 3857c478bd9Sstevel@tonic-gate au_toss_token(dchain); 3867c478bd9Sstevel@tonic-gate return; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate attr = kmem_alloc(sizeof (au_defer_info_t), KM_NOSLEEP); 3907c478bd9Sstevel@tonic-gate /* If no mem available, failing silently is the best recourse */ 3917c478bd9Sstevel@tonic-gate if (attr == NULL) { 3927c478bd9Sstevel@tonic-gate au_toss_token(dchain); 3937c478bd9Sstevel@tonic-gate return; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate attr->audi_next = NULL; 3977c478bd9Sstevel@tonic-gate attr->audi_ad = dchain; 3987c478bd9Sstevel@tonic-gate attr->audi_e_type = e_type; 3997c478bd9Sstevel@tonic-gate attr->audi_e_mod = e_mod; 4007c478bd9Sstevel@tonic-gate attr->audi_flag = flag; 4017c478bd9Sstevel@tonic-gate gethrestime(&attr->audi_atime); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * All async events must be queued via softcall to avoid possible 4057c478bd9Sstevel@tonic-gate * sleeping in high interrupt context. softcall will ensure it's 4067c478bd9Sstevel@tonic-gate * done on a dedicated software-level interrupt thread. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate if (flag & AU_DONTBLOCK) { 4097c478bd9Sstevel@tonic-gate softcall(audit_async_finish_backend, attr); 4107c478bd9Sstevel@tonic-gate audit_async_done(NULL, 0); 4117c478bd9Sstevel@tonic-gate return; 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* 4157c478bd9Sstevel@tonic-gate * If not an async event, defer by queuing onto the tad until 4167c478bd9Sstevel@tonic-gate * syscall end. No locking is needed because the tad is per-thread. 4177c478bd9Sstevel@tonic-gate */ 4187c478bd9Sstevel@tonic-gate if (tad->tad_defer_head) 4197c478bd9Sstevel@tonic-gate tad->tad_defer_tail->audi_next = attr; 4207c478bd9Sstevel@tonic-gate else 4217c478bd9Sstevel@tonic-gate tad->tad_defer_head = attr; 4227c478bd9Sstevel@tonic-gate tad->tad_defer_tail = attr; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Save the time in the event header. If time is not specified (i.e., pointer 4287c478bd9Sstevel@tonic-gate * is NULL), use the current time. This code is fairly ugly since it needs 4297c478bd9Sstevel@tonic-gate * to support both 32- and 64-bit environments and can be called indirectly 4307c478bd9Sstevel@tonic-gate * from both au_close() (for kernel audit) and from audit() (userland audit). 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4337c478bd9Sstevel@tonic-gate static void 4347c478bd9Sstevel@tonic-gate au_save_time(adr_t *hadrp, timestruc_t *time, int size) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate struct { 4377c478bd9Sstevel@tonic-gate uint32_t sec; 4387c478bd9Sstevel@tonic-gate uint32_t usec; 4397c478bd9Sstevel@tonic-gate } tv; 4407c478bd9Sstevel@tonic-gate timestruc_t now; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if (time == NULL) { 4437c478bd9Sstevel@tonic-gate gethrestime(&now); 4447c478bd9Sstevel@tonic-gate time = &now; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate #ifdef _LP64 4487c478bd9Sstevel@tonic-gate if (size) 4497c478bd9Sstevel@tonic-gate adr_int64(hadrp, (int64_t *)time, 2); 4507c478bd9Sstevel@tonic-gate else 4517c478bd9Sstevel@tonic-gate #endif 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate tv.sec = (uint32_t)time->tv_sec; 4547c478bd9Sstevel@tonic-gate tv.usec = (uint32_t)time->tv_nsec; 4557c478bd9Sstevel@tonic-gate adr_int32(hadrp, (int32_t *)&tv, 2); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Close an audit descriptor. 4627c478bd9Sstevel@tonic-gate * If time of event is specified, use it in the record, otherwise use the 4637c478bd9Sstevel@tonic-gate * current time. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate void 4667c478bd9Sstevel@tonic-gate au_close_time(au_kcontext_t *kctx, token_t *dchain, int flag, short e_type, 4677c478bd9Sstevel@tonic-gate short e_mod, timestruc_t *etime) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate token_t *record; /* au_membuf chain == the record */ 4707c478bd9Sstevel@tonic-gate int byte_count; 4717c478bd9Sstevel@tonic-gate token_t *m; /* for potential sequence token */ 4727c478bd9Sstevel@tonic-gate adr_t hadr; /* handle for header token */ 4737c478bd9Sstevel@tonic-gate adr_t sadr; /* handle for sequence token */ 4747c478bd9Sstevel@tonic-gate size_t zone_length; /* length of zonename token */ 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate ASSERT(dchain != NULL); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* If not to be written, toss the record */ 4797c478bd9Sstevel@tonic-gate if ((flag & AU_OK) == 0) { 4807c478bd9Sstevel@tonic-gate au_toss_token(dchain); 4817c478bd9Sstevel@tonic-gate return; 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate /* if auditing not enabled, then don't generate an audit record */ 4847c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if ((kctx->auk_auditstate != AUC_AUDITING) && 4877c478bd9Sstevel@tonic-gate (kctx->auk_auditstate != AUC_INIT_AUDIT)) { 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * at system boot, neither is set yet we want to generate 4907c478bd9Sstevel@tonic-gate * an audit record. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if (e_type != AUE_SYSTEMBOOT) { 4937c478bd9Sstevel@tonic-gate au_toss_token(dchain); 4947c478bd9Sstevel@tonic-gate return; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* Count up the bytes used in the record. */ 4997c478bd9Sstevel@tonic-gate byte_count = au_token_size(dchain); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * add in size of header token (always present). 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate byte_count += sizeof (char) + sizeof (int32_t) + 5057c478bd9Sstevel@tonic-gate sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid) 5087c478bd9Sstevel@tonic-gate byte_count += sizeof (int32_t) + kctx->auk_info.ai_termid.at_type; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * add in size of zonename token (zero if !AUDIT_ZONENAME) 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_ZONENAME) { 5141d7bfecdStz zone_length = au_zonename_length(NULL); 5157c478bd9Sstevel@tonic-gate byte_count += zone_length; 5167c478bd9Sstevel@tonic-gate } else { 5177c478bd9Sstevel@tonic-gate zone_length = 0; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate /* add in size of (optional) trailer token */ 5207c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_TRAIL) 5217c478bd9Sstevel@tonic-gate byte_count += 7; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* add in size of (optional) sequence token */ 5247c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_SEQ) 5257c478bd9Sstevel@tonic-gate byte_count += 5; 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* build the header */ 5287c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid) 5297c478bd9Sstevel@tonic-gate record = au_to_header_ex(byte_count, e_type, e_mod); 5307c478bd9Sstevel@tonic-gate else 5317c478bd9Sstevel@tonic-gate record = au_to_header(byte_count, e_type, e_mod); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * If timestamp was specified, save it in header now. Otherwise, 5357c478bd9Sstevel@tonic-gate * save reference to header so we can update time/data later 5367c478bd9Sstevel@tonic-gate * and artificially adjust pointer to the time/date field of header. 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate adr_start(&hadr, memtod(record, char *)); 5397c478bd9Sstevel@tonic-gate hadr.adr_now += sizeof (char) + sizeof (int32_t) + 5407c478bd9Sstevel@tonic-gate sizeof (char) + 2 * sizeof (short); 5417c478bd9Sstevel@tonic-gate if (kctx->auk_hostaddr_valid) 5427c478bd9Sstevel@tonic-gate hadr.adr_now += sizeof (int32_t) + 5437c478bd9Sstevel@tonic-gate kctx->auk_info.ai_termid.at_type; 5447c478bd9Sstevel@tonic-gate if (etime != NULL) { 5457c478bd9Sstevel@tonic-gate au_save_time(&hadr, etime, 1); 5467c478bd9Sstevel@tonic-gate hadr.adr_now = (char *)NULL; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* append body of audit record */ 5507c478bd9Sstevel@tonic-gate (void) au_append_rec(record, dchain, AU_PACK); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* add (optional) zonename token */ 5537c478bd9Sstevel@tonic-gate if (zone_length > 0) { 5541d7bfecdStz m = au_to_zonename(zone_length, NULL); 5557c478bd9Sstevel@tonic-gate (void) au_append_rec(record, m, AU_PACK); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /* Add an (optional) sequence token. NULL offset if none */ 5597c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_SEQ) { 5607c478bd9Sstevel@tonic-gate /* get the sequence token */ 5617c478bd9Sstevel@tonic-gate m = au_to_seq(); 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* link to audit record (i.e. don't pack the data) */ 5647c478bd9Sstevel@tonic-gate (void) au_append_rec(record, m, AU_LINK); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * advance to count field of sequence token by skipping 5687c478bd9Sstevel@tonic-gate * the token type byte. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate adr_start(&sadr, memtod(m, char *)); 5717c478bd9Sstevel@tonic-gate sadr.adr_now += 1; 5727c478bd9Sstevel@tonic-gate } else { 5737c478bd9Sstevel@tonic-gate sadr.adr_now = NULL; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate /* add (optional) trailer token */ 5767c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_TRAIL) { 5777c478bd9Sstevel@tonic-gate (void) au_append_rec(record, au_to_trailer(byte_count), 5787c478bd9Sstevel@tonic-gate AU_PACK); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * 1 - use 64 bit version of audit tokens for 64 bit kernels. 5837c478bd9Sstevel@tonic-gate * 0 - use 32 bit version of audit tokens for 32 bit kernels. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate #ifdef _LP64 5867c478bd9Sstevel@tonic-gate au_enqueue(kctx, record, &hadr, &sadr, 1, flag & AU_DONTBLOCK); 5877c478bd9Sstevel@tonic-gate #else 5887c478bd9Sstevel@tonic-gate au_enqueue(kctx, record, &hadr, &sadr, 0, flag & AU_DONTBLOCK); 5897c478bd9Sstevel@tonic-gate #endif 5907c478bd9Sstevel@tonic-gate AS_INC(as_totalsize, byte_count, kctx); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5947c478bd9Sstevel@tonic-gate void 5957c478bd9Sstevel@tonic-gate au_enqueue(au_kcontext_t *kctx, au_buff_t *m, adr_t *hadrp, adr_t *sadrp, 5967c478bd9Sstevel@tonic-gate int size, int dontblock) 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate if (kctx == NULL) 5997c478bd9Sstevel@tonic-gate return; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock)); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate if (!dontblock && (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) && 6047c478bd9Sstevel@tonic-gate audit_sync_block(kctx)) { 6057c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 6067c478bd9Sstevel@tonic-gate au_free_rec(m); 6077c478bd9Sstevel@tonic-gate return; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* Fill in date and time if needed */ 6117c478bd9Sstevel@tonic-gate if (hadrp->adr_now) { 6127c478bd9Sstevel@tonic-gate au_save_time(hadrp, NULL, size); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate /* address will be non-zero only if AUDIT_SEQ set */ 6167c478bd9Sstevel@tonic-gate if (sadrp->adr_now) { 6177c478bd9Sstevel@tonic-gate kctx->auk_sequence++; 6187c478bd9Sstevel@tonic-gate adr_int32(sadrp, (int32_t *)&(kctx->auk_sequence), 1); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate if (kctx->auk_queue.head) 6227c478bd9Sstevel@tonic-gate kctx->auk_queue.tail->next_rec = m; 6237c478bd9Sstevel@tonic-gate else 6247c478bd9Sstevel@tonic-gate kctx->auk_queue.head = m; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate kctx->auk_queue.tail = m; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate if (++(kctx->auk_queue.cnt) > 6297c478bd9Sstevel@tonic-gate kctx->auk_queue.lowater && kctx->auk_queue.rd_block) 6307c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.read_cv)); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* count # audit records put onto kernel audit queue */ 6357c478bd9Sstevel@tonic-gate AS_INC(as_enqueue, 1, kctx); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * Dequeue and free buffers upto and including "freeto" 6407c478bd9Sstevel@tonic-gate * Keeps the queue lock long but acquires it only once when doing 6417c478bd9Sstevel@tonic-gate * bulk dequeueing. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate static void 6447c478bd9Sstevel@tonic-gate au_dequeue(au_kcontext_t *kctx, au_buff_t *freeto) 6457c478bd9Sstevel@tonic-gate { 6467c478bd9Sstevel@tonic-gate au_buff_t *m, *l, *lastl; 6477c478bd9Sstevel@tonic-gate int n = 0; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock)); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate ASSERT(kctx->auk_queue.head != NULL); 6547c478bd9Sstevel@tonic-gate ASSERT(freeto != NULL); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate l = m = kctx->auk_queue.head; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate do { 6597c478bd9Sstevel@tonic-gate n++; 6607c478bd9Sstevel@tonic-gate lastl = l; 6617c478bd9Sstevel@tonic-gate l = l->next_rec; 6627c478bd9Sstevel@tonic-gate } while (l != NULL && freeto != lastl); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate kctx->auk_queue.cnt -= n; 6657c478bd9Sstevel@tonic-gate lastl->next_rec = NULL; 6667c478bd9Sstevel@tonic-gate kctx->auk_queue.head = l; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Freeto must exist in the list */ 6697c478bd9Sstevel@tonic-gate ASSERT(freeto == lastl); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate if (kctx->auk_queue.cnt <= kctx->auk_queue.lowater && 6727c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block) 6737c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.write_cv)); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate while (m) { 6787c478bd9Sstevel@tonic-gate l = m->next_rec; 6797c478bd9Sstevel@tonic-gate au_free_rec(m); 6807c478bd9Sstevel@tonic-gate m = l; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate AS_INC(as_written, n, kctx); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * audit_sync_block() 6877c478bd9Sstevel@tonic-gate * If we've reached the high water mark, we look at the policy to see 6887c478bd9Sstevel@tonic-gate * if we sleep or we should drop the audit record. 6897c478bd9Sstevel@tonic-gate * This function is called with the auk_queue.lock held and the check 6907c478bd9Sstevel@tonic-gate * performed one time already as an optimization. Caller should unlock. 6917c478bd9Sstevel@tonic-gate * Returns 1 if the caller needs to free the record. 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate static int 6947c478bd9Sstevel@tonic-gate audit_sync_block(au_kcontext_t *kctx) 6957c478bd9Sstevel@tonic-gate { 6967c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(kctx->auk_queue.lock))); 6977c478bd9Sstevel@tonic-gate /* 6987c478bd9Sstevel@tonic-gate * Loop while we are at the high watermark. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate do { 7017c478bd9Sstevel@tonic-gate if ((kctx->auk_auditstate != AUC_AUDITING) || 7027c478bd9Sstevel@tonic-gate (kctx->auk_policy & AUDIT_CNT)) { 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* just count # of dropped audit records */ 7057c478bd9Sstevel@tonic-gate AS_INC(as_dropped, 1, kctx); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate return (1); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* kick reader awake if its asleep */ 7117c478bd9Sstevel@tonic-gate if (kctx->auk_queue.rd_block && 7127c478bd9Sstevel@tonic-gate kctx->auk_queue.cnt > kctx->auk_queue.lowater) 7137c478bd9Sstevel@tonic-gate cv_broadcast(&(kctx->auk_queue.read_cv)); 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* keep count of # times blocked */ 7167c478bd9Sstevel@tonic-gate AS_INC(as_wblocked, 1, kctx); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* sleep now, until woken by reader */ 7197c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block++; 7207c478bd9Sstevel@tonic-gate cv_wait(&(kctx->auk_queue.write_cv), &(kctx->auk_queue.lock)); 7217c478bd9Sstevel@tonic-gate kctx->auk_queue.wt_block--; 7227c478bd9Sstevel@tonic-gate } while (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate return (0); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * audit_async_block() 7297c478bd9Sstevel@tonic-gate * if we've reached the high water mark, we look at the ahlt policy to see 7307c478bd9Sstevel@tonic-gate * if we reboot we should drop the audit record. 7317c478bd9Sstevel@tonic-gate * Returns 1 if blocked. 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate static int 7347c478bd9Sstevel@tonic-gate audit_async_block(au_kcontext_t *kctx, caddr_t *rpp) 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate ASSERT(kctx != NULL); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock)); 7397c478bd9Sstevel@tonic-gate /* see if we've reached high water mark */ 7407c478bd9Sstevel@tonic-gate if (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) { 7417c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate audit_async_drop(rpp, AU_BACKEND); 7447c478bd9Sstevel@tonic-gate return (1); 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 7477c478bd9Sstevel@tonic-gate return (0); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * au_door_upcall. auditdoor() may change vp without notice, so 7527c478bd9Sstevel@tonic-gate * some locking seems in order. 7537c478bd9Sstevel@tonic-gate * 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate #define AGAIN_TICKS 10 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate static int 7587c478bd9Sstevel@tonic-gate au_door_upcall(au_kcontext_t *kctx, au_dbuf_t *aubuf) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate int rc; 7617c478bd9Sstevel@tonic-gate door_arg_t darg; 7627c478bd9Sstevel@tonic-gate int retry = 1; 7637c478bd9Sstevel@tonic-gate int ticks_to_wait; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate darg.data_ptr = (char *)aubuf; 7667c478bd9Sstevel@tonic-gate darg.data_size = AU_DBUF_HEADER + aubuf->aub_size; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate darg.desc_ptr = NULL; 7697c478bd9Sstevel@tonic-gate darg.desc_num = 0; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate while (retry == 1) { 7727c478bd9Sstevel@tonic-gate /* non-zero means return results expected */ 7737c478bd9Sstevel@tonic-gate darg.rbuf = (char *)aubuf; 7747c478bd9Sstevel@tonic-gate darg.rsize = darg.data_size; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate retry = 0; 7777c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_svc_lock)); 7787c478bd9Sstevel@tonic-gate if ((rc = door_upcall(kctx->auk_current_vp, &darg)) != 0) { 7797c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock)); 7807c478bd9Sstevel@tonic-gate if (rc == EAGAIN) 7817c478bd9Sstevel@tonic-gate ticks_to_wait = AGAIN_TICKS; 7827c478bd9Sstevel@tonic-gate else 7837c478bd9Sstevel@tonic-gate return (rc); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_eagain_mutex)); 7867c478bd9Sstevel@tonic-gate (void) cv_timedwait(&(kctx->auk_eagain_cv), 7877c478bd9Sstevel@tonic-gate &(kctx->auk_eagain_mutex), 7887c478bd9Sstevel@tonic-gate lbolt + ticks_to_wait); 7897c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_eagain_mutex)); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate retry = 1; 7927c478bd9Sstevel@tonic-gate } else 7937c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock)); /* no retry */ 7947c478bd9Sstevel@tonic-gate } /* end while (retry == 1) */ 7957c478bd9Sstevel@tonic-gate if (darg.rbuf == NULL) 7967c478bd9Sstevel@tonic-gate return (-1); 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* return code from door server */ 7997c478bd9Sstevel@tonic-gate return (*(int *)darg.rbuf); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * Write an audit control message to the door handle. The message 8047c478bd9Sstevel@tonic-gate * structure depends on message_code and at present the only control 8057c478bd9Sstevel@tonic-gate * message defined is for a policy change. These are infrequent, 8067c478bd9Sstevel@tonic-gate * so no memory is held for control messages. 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate int 8097c478bd9Sstevel@tonic-gate au_doormsg(au_kcontext_t *kctx, uint32_t message_code, void *message) 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate int rc; 8127c478bd9Sstevel@tonic-gate au_dbuf_t *buf; 8137c478bd9Sstevel@tonic-gate size_t alloc_size; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate switch (message_code) { 8167c478bd9Sstevel@tonic-gate case AU_DBUF_POLICY: 8177c478bd9Sstevel@tonic-gate alloc_size = AU_DBUF_HEADER + sizeof (uint32_t); 8187c478bd9Sstevel@tonic-gate buf = kmem_alloc(alloc_size, KM_SLEEP); 8197c478bd9Sstevel@tonic-gate buf->aub_size = sizeof (uint32_t); 8207c478bd9Sstevel@tonic-gate *(uint32_t *)buf->aub_buf = *(uint32_t *)message; 8217c478bd9Sstevel@tonic-gate break; 8227c478bd9Sstevel@tonic-gate case AU_DBUF_SHUTDOWN: 8237c478bd9Sstevel@tonic-gate alloc_size = AU_DBUF_HEADER; 8247c478bd9Sstevel@tonic-gate buf = kmem_alloc(alloc_size, KM_SLEEP); 8257c478bd9Sstevel@tonic-gate buf->aub_size = 0; 8267c478bd9Sstevel@tonic-gate break; 8277c478bd9Sstevel@tonic-gate default: 8287c478bd9Sstevel@tonic-gate return (1); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate buf->aub_type = AU_DBUF_NOTIFY | message_code; 8327c478bd9Sstevel@tonic-gate rc = au_door_upcall(kctx, buf); 8337c478bd9Sstevel@tonic-gate kmem_free(buf, alloc_size); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate return (rc); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Write audit information to the door handle. au_doorio is called with 8407c478bd9Sstevel@tonic-gate * one or more complete audit records on the queue and outputs those 8417c478bd9Sstevel@tonic-gate * records in buffers of up to auk_queue.buflen in size. 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate int 8447c478bd9Sstevel@tonic-gate au_doorio(au_kcontext_t *kctx) { 8457c478bd9Sstevel@tonic-gate off_t off; /* space used in buffer */ 8467c478bd9Sstevel@tonic-gate ssize_t used; /* space used in au_membuf */ 8477c478bd9Sstevel@tonic-gate token_t *cAR; /* current AR being processed */ 8487c478bd9Sstevel@tonic-gate token_t *cMB; /* current au_membuf being processed */ 8497c478bd9Sstevel@tonic-gate token_t *sp; /* last AR processed */ 8507c478bd9Sstevel@tonic-gate char *bp; /* start of free space in staging buffer */ 8517c478bd9Sstevel@tonic-gate unsigned char *cp; /* ptr to data to be moved */ 8527c478bd9Sstevel@tonic-gate int error; /* return from door upcall */ 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * size (data left in au_membuf - space in buffer) 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate ssize_t sz; 8587c478bd9Sstevel@tonic-gate ssize_t len; /* len of data to move, size of AR */ 8597c478bd9Sstevel@tonic-gate ssize_t curr_sz = 0; /* amount of data written during now */ 8607c478bd9Sstevel@tonic-gate /* 8617c478bd9Sstevel@tonic-gate * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h 8627c478bd9Sstevel@tonic-gate */ 8637c478bd9Sstevel@tonic-gate int part = 0; /* partial audit record written */ 8647c478bd9Sstevel@tonic-gate int partial_state = AU_DBUF_COMPLETE; 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * Has the write buffer changed length due to a auditctl(2)? 8677c478bd9Sstevel@tonic-gate * Initial allocation is from audit_start.c/audit_init() 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) { 8707c478bd9Sstevel@tonic-gate kmem_free(kctx->auk_dbuffer, AU_DBUF_HEADER + 8717c478bd9Sstevel@tonic-gate kctx->auk_queue.buflen); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate kctx->auk_dbuffer = kmem_alloc(AU_DBUF_HEADER + 8747c478bd9Sstevel@tonic-gate kctx->auk_queue.bufsz, KM_SLEEP); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate /* omit the 64 bit header */ 8777c478bd9Sstevel@tonic-gate kctx->auk_queue.buflen = kctx->auk_queue.bufsz; 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate if (!kctx->auk_queue.head) 8807c478bd9Sstevel@tonic-gate goto nodata; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate sp = NULL; /* no record copied */ 8837c478bd9Sstevel@tonic-gate off = 0; /* no space used in buffer */ 8847c478bd9Sstevel@tonic-gate used = 0; /* no data processed in au_membuf */ 8857c478bd9Sstevel@tonic-gate cAR = kctx->auk_queue.head; /* start at head of queue */ 8867c478bd9Sstevel@tonic-gate cMB = cAR; /* start with first au_membuf of record */ 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate /* start at beginning of buffer */ 8897c478bd9Sstevel@tonic-gate bp = &(kctx->auk_dbuffer->aub_buf[0]); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate while (cMB) { 8927c478bd9Sstevel@tonic-gate part = 1; /* indicate audit record being processed */ 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate cp = memtod(cMB, unsigned char *); /* buffer ptr */ 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate sz = (ssize_t)cMB->len - used; /* data left in au_membuf */ 8977c478bd9Sstevel@tonic-gate /* len to move */ 8987c478bd9Sstevel@tonic-gate len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* move the data */ 9017c478bd9Sstevel@tonic-gate bcopy(cp + used, bp + off, len); 9027c478bd9Sstevel@tonic-gate used += len; /* update used au_membuf */ 9037c478bd9Sstevel@tonic-gate off += len; /* update offset into buffer */ 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate if (used >= (ssize_t)cMB->len) { 9067c478bd9Sstevel@tonic-gate /* advance to next au_membuf */ 9077c478bd9Sstevel@tonic-gate used = 0; 9087c478bd9Sstevel@tonic-gate cMB = cMB->next_buf; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate if (cMB == NULL) { 9117c478bd9Sstevel@tonic-gate /* advance to next audit record */ 9127c478bd9Sstevel@tonic-gate sp = cAR; 9137c478bd9Sstevel@tonic-gate cAR = cAR->next_rec; 9147c478bd9Sstevel@tonic-gate cMB = cAR; 9157c478bd9Sstevel@tonic-gate part = 0; /* have a complete record */ 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate error = 0; 9187c478bd9Sstevel@tonic-gate if ((kctx->auk_queue.buflen == off) || (part == 0)) { 9197c478bd9Sstevel@tonic-gate if (part) 9207c478bd9Sstevel@tonic-gate partial_state = state_if_part[partial_state]; 9217c478bd9Sstevel@tonic-gate else 9227c478bd9Sstevel@tonic-gate partial_state = 9237c478bd9Sstevel@tonic-gate state_if_not_part[partial_state]; 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate kctx->auk_dbuffer->aub_type = partial_state; 9267c478bd9Sstevel@tonic-gate kctx->auk_dbuffer->aub_size = off; 9277c478bd9Sstevel@tonic-gate error = au_door_upcall(kctx, kctx->auk_dbuffer); 9287c478bd9Sstevel@tonic-gate if (error != 0) 9297c478bd9Sstevel@tonic-gate goto nodata; 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * if we've successfully written an audit record, 9327c478bd9Sstevel@tonic-gate * free records up to last full record copied 9337c478bd9Sstevel@tonic-gate */ 9347c478bd9Sstevel@tonic-gate if (sp) 9357c478bd9Sstevel@tonic-gate au_dequeue(kctx, sp); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* Update size */ 9387c478bd9Sstevel@tonic-gate curr_sz += off; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate /* reset auk_dbuffer pointers */ 9417c478bd9Sstevel@tonic-gate sp = NULL; 9427c478bd9Sstevel@tonic-gate off = 0; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate } /* while(cMB) */ 9457c478bd9Sstevel@tonic-gate nodata: 9467c478bd9Sstevel@tonic-gate return (error); 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* 9507c478bd9Sstevel@tonic-gate * Clean up thread audit state to clear out asynchronous audit record 9517c478bd9Sstevel@tonic-gate * generation error recovery processing. Note that this is done on a 9527c478bd9Sstevel@tonic-gate * per-thread basis and thus does not need any locking. 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate void 9557c478bd9Sstevel@tonic-gate audit_async_done(caddr_t *rpp, int flags) 9567c478bd9Sstevel@tonic-gate { 9577c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* clean up the tad unless called from softcall backend */ 9607c478bd9Sstevel@tonic-gate if (!(flags & AU_BACKEND)) { 9617c478bd9Sstevel@tonic-gate ASSERT(tad != NULL); 9627c478bd9Sstevel@tonic-gate ASSERT(tad->tad_ctrl & PAD_ERRJMP); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate tad->tad_ctrl &= ~PAD_ERRJMP; 9657c478bd9Sstevel@tonic-gate tad->tad_errjmp = NULL; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* clean out partial audit record */ 9697c478bd9Sstevel@tonic-gate if ((rpp != NULL) && (*rpp != NULL)) { 9707c478bd9Sstevel@tonic-gate au_toss_token((au_buff_t *)*rpp); 9717c478bd9Sstevel@tonic-gate *rpp = NULL; 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * implement the audit policy for asynchronous events generated within 9777c478bd9Sstevel@tonic-gate * the kernel. 9787c478bd9Sstevel@tonic-gate * XXX might need locks around audit_policy check. 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate void 9817c478bd9Sstevel@tonic-gate audit_async_drop(caddr_t *rpp, int flags) 9827c478bd9Sstevel@tonic-gate { 9837c478bd9Sstevel@tonic-gate au_kcontext_t *kctx; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* could not generate audit record, clean up */ 9867c478bd9Sstevel@tonic-gate audit_async_done((caddr_t *)rpp, flags); 9877c478bd9Sstevel@tonic-gate 988*9e9e6ab8Spaulson kctx = GET_KCTX_GZ; 989*9e9e6ab8Spaulson 9907c478bd9Sstevel@tonic-gate /* just drop the record and return */ 9917c478bd9Sstevel@tonic-gate if (((audit_policy & AUDIT_AHLT) == 0) || 9927c478bd9Sstevel@tonic-gate (kctx->auk_auditstate == AUC_INIT_AUDIT)) { 9937c478bd9Sstevel@tonic-gate /* just count # of dropped audit records */ 9947c478bd9Sstevel@tonic-gate AS_INC(as_dropped, 1, kctx); 9957c478bd9Sstevel@tonic-gate return; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* 9997c478bd9Sstevel@tonic-gate * There can be a lot of data in the audit queue. We 10007c478bd9Sstevel@tonic-gate * will first sync the file systems then attempt to 10017c478bd9Sstevel@tonic-gate * shutdown the kernel so that a memory dump is 10027c478bd9Sstevel@tonic-gate * performed. 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate sync(); 10057c478bd9Sstevel@tonic-gate sync(); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * now shut down. What a cruel world it has been 10097c478bd9Sstevel@tonic-gate */ 10107c478bd9Sstevel@tonic-gate panic("non-attributable halt. should dump core"); 10117c478bd9Sstevel@tonic-gate /* No return */ 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate int 10157c478bd9Sstevel@tonic-gate audit_async_start(label_t *jb, int event, int sorf) 10167c478bd9Sstevel@tonic-gate { 10177c478bd9Sstevel@tonic-gate t_audit_data_t *tad = U2A(u); 10187c478bd9Sstevel@tonic-gate au_state_t estate; 10197c478bd9Sstevel@tonic-gate int success = 0, failure = 0; 1020*9e9e6ab8Spaulson au_kcontext_t *kctx = GET_KCTX_GZ; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* if audit state off, then no audit record generation */ 10237c478bd9Sstevel@tonic-gate if ((kctx->auk_auditstate != AUC_AUDITING) && 10247c478bd9Sstevel@tonic-gate (kctx->auk_auditstate != AUC_INIT_AUDIT)) 10257c478bd9Sstevel@tonic-gate return (1); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * preselect asynchronous event 10297c478bd9Sstevel@tonic-gate * XXX should we check for out-of-range??? 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate estate = kctx->auk_ets[event]; 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate if (sorf & AUM_SUCC) 10347c478bd9Sstevel@tonic-gate success = kctx->auk_info.ai_mask.as_success & estate; 10357c478bd9Sstevel@tonic-gate if (sorf & AUM_FAIL) 10367c478bd9Sstevel@tonic-gate failure = kctx->auk_info.ai_mask.as_failure & estate; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate if ((success | failure) == NULL) 10397c478bd9Sstevel@tonic-gate return (1); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate ASSERT(tad->tad_errjmp == NULL); 10427c478bd9Sstevel@tonic-gate tad->tad_errjmp = (void *)jb; 10437c478bd9Sstevel@tonic-gate tad->tad_ctrl |= PAD_ERRJMP; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate return (0); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* 10497c478bd9Sstevel@tonic-gate * Complete auditing of an async event. The AU_DONTBLOCK flag to au_close will 10507c478bd9Sstevel@tonic-gate * result in the backend routine being invoked from softcall, so all the real 10517c478bd9Sstevel@tonic-gate * work can be done in a safe context. 10527c478bd9Sstevel@tonic-gate */ 10537c478bd9Sstevel@tonic-gate void 10547c478bd9Sstevel@tonic-gate audit_async_finish(caddr_t *ad, int aid, int amod) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate au_kcontext_t *kctx; 10577c478bd9Sstevel@tonic-gate 1058*9e9e6ab8Spaulson kctx = GET_KCTX_GZ; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate au_close(kctx, ad, AU_DONTBLOCK | AU_OK, aid, PAD_NONATTR|amod); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* 10647c478bd9Sstevel@tonic-gate * Backend routine to complete an async audit. Invoked from softcall. 10657c478bd9Sstevel@tonic-gate * (Note: the blocking and the queuing below both involve locking which can't 10667c478bd9Sstevel@tonic-gate * be done safely in high interrupt context due to the chance of sleeping on 10677c478bd9Sstevel@tonic-gate * the corresponding adaptive mutex. Hence the softcall.) 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate static void 10707c478bd9Sstevel@tonic-gate audit_async_finish_backend(void *addr) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate au_kcontext_t *kctx; 10737c478bd9Sstevel@tonic-gate au_defer_info_t *attr = (au_defer_info_t *)addr; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if (attr == NULL) 10767c478bd9Sstevel@tonic-gate return; /* won't happen unless softcall is broken */ 10777c478bd9Sstevel@tonic-gate 1078*9e9e6ab8Spaulson kctx = GET_KCTX_GZ; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (audit_async_block(kctx, (caddr_t *)&attr->audi_ad)) { 10817c478bd9Sstevel@tonic-gate kmem_free(attr, sizeof (au_defer_info_t)); 10827c478bd9Sstevel@tonic-gate return; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * Call au_close_time to complete the audit with the saved values. 10877c478bd9Sstevel@tonic-gate * 10887c478bd9Sstevel@tonic-gate * For the exit-prom event, use the current time instead of the 10897c478bd9Sstevel@tonic-gate * saved time as a better approximation. (Because the time saved via 10907c478bd9Sstevel@tonic-gate * gethrestime during prom-exit handling would not yet be caught up 10917c478bd9Sstevel@tonic-gate * after the system was idled in the debugger for a period of time.) 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate if (attr->audi_e_type == AUE_EXITPROM) { 10947c478bd9Sstevel@tonic-gate au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag, 10957c478bd9Sstevel@tonic-gate attr->audi_e_type, attr->audi_e_mod, NULL); 10967c478bd9Sstevel@tonic-gate } else { 10977c478bd9Sstevel@tonic-gate au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag, 10987c478bd9Sstevel@tonic-gate attr->audi_e_type, attr->audi_e_mod, &attr->audi_atime); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate AS_INC(as_generated, 1, kctx); 11027c478bd9Sstevel@tonic-gate AS_INC(as_nonattrib, 1, kctx); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate kmem_free(attr, sizeof (au_defer_info_t)); 11057c478bd9Sstevel@tonic-gate } 1106