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