xref: /illumos-gate/usr/src/uts/common/c2/audit_io.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Routines for writing audit records.
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/door.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>	/* for statfs */
36*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/reboot.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>		/* for KM_SLEEP */
43*7c478bd9Sstevel@tonic-gate #include <sys/resource.h>	/* for RLIM_INFINITY */
44*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>	/* panic */
45*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <c2/audit.h>
52*7c478bd9Sstevel@tonic-gate #include <c2/audit_kernel.h>
53*7c478bd9Sstevel@tonic-gate #include <c2/audit_record.h>
54*7c478bd9Sstevel@tonic-gate #include <c2/audit_kevents.h>
55*7c478bd9Sstevel@tonic-gate #include <c2/audit_door_infc.h>
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static void	au_dequeue(au_kcontext_t *, au_buff_t *);
58*7c478bd9Sstevel@tonic-gate static void	audit_async_finish_backend(void *);
59*7c478bd9Sstevel@tonic-gate static int	audit_sync_block(au_kcontext_t *);
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * each of these two tables are indexed by the values AU_DBUF_COMPLETE
62*7c478bd9Sstevel@tonic-gate  * through AU_DBUF_LAST; the content is the next state value.  The
63*7c478bd9Sstevel@tonic-gate  * first table determines the next state for a buffer which is not the
64*7c478bd9Sstevel@tonic-gate  * end of a record and the second table determines the state for a
65*7c478bd9Sstevel@tonic-gate  * buffer which is the end of a record.  The initial state is
66*7c478bd9Sstevel@tonic-gate  * AU_DBUF_COMPLETE.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate static int state_if_part[] = {
69*7c478bd9Sstevel@tonic-gate     AU_DBUF_FIRST, AU_DBUF_MIDDLE, AU_DBUF_MIDDLE, AU_DBUF_FIRST};
70*7c478bd9Sstevel@tonic-gate static int state_if_not_part[] = {
71*7c478bd9Sstevel@tonic-gate     AU_DBUF_COMPLETE, AU_DBUF_LAST, AU_DBUF_LAST, AU_DBUF_COMPLETE};
72*7c478bd9Sstevel@tonic-gate /*
73*7c478bd9Sstevel@tonic-gate  * Write to an audit descriptor.
74*7c478bd9Sstevel@tonic-gate  * Add the au_membuf to the descriptor chain and free the chain passed in.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate void
77*7c478bd9Sstevel@tonic-gate au_uwrite(m)
78*7c478bd9Sstevel@tonic-gate 	token_t *m;
79*7c478bd9Sstevel@tonic-gate {
80*7c478bd9Sstevel@tonic-gate 	au_write(&(u_ad), m);
81*7c478bd9Sstevel@tonic-gate }
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate void
84*7c478bd9Sstevel@tonic-gate au_write(caddr_t *d, token_t *m)
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	if (d == NULL) {
87*7c478bd9Sstevel@tonic-gate 		au_toss_token(m);
88*7c478bd9Sstevel@tonic-gate 		return;
89*7c478bd9Sstevel@tonic-gate 	}
90*7c478bd9Sstevel@tonic-gate 	if (m == (token_t *)0) {
91*7c478bd9Sstevel@tonic-gate 		printf("au_write: null token\n");
92*7c478bd9Sstevel@tonic-gate 		return;
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	if (*d == NULL)
96*7c478bd9Sstevel@tonic-gate 		*d = (caddr_t)m;
97*7c478bd9Sstevel@tonic-gate 	else
98*7c478bd9Sstevel@tonic-gate 		(void) au_append_rec((au_buff_t *)*d, m, AU_PACK);
99*7c478bd9Sstevel@tonic-gate }
100*7c478bd9Sstevel@tonic-gate #define	AU_INTERVAL 120
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * Write audit information to the disk.
104*7c478bd9Sstevel@tonic-gate  * Called from auditsvc(); EOL'd as of Sol 10.
105*7c478bd9Sstevel@tonic-gate  * Local zones are not allowed; the caller (auditsvc()) enforces the
106*7c478bd9Sstevel@tonic-gate  * restriction.
107*7c478bd9Sstevel@tonic-gate  */
108*7c478bd9Sstevel@tonic-gate int
109*7c478bd9Sstevel@tonic-gate au_doio(vp, limit)
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	struct vnode *vp;
112*7c478bd9Sstevel@tonic-gate 	int limit;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate {	/* AU_DOIO */
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	off_t		off;	/* space used in buffer */
117*7c478bd9Sstevel@tonic-gate 	size_t		used;	/* space used in au_membuf */
118*7c478bd9Sstevel@tonic-gate 	token_t		*cAR;	/* current AR being processed */
119*7c478bd9Sstevel@tonic-gate 	token_t		*cMB;	/* current au_membuf being processed */
120*7c478bd9Sstevel@tonic-gate 	token_t		*sp;	/* last AR processed */
121*7c478bd9Sstevel@tonic-gate 	char		*bp;	/* start of free space in staging buffer */
122*7c478bd9Sstevel@tonic-gate 	unsigned char	*cp;	/* ptr to data to be moved */
123*7c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
124*7c478bd9Sstevel@tonic-gate 	/*
125*7c478bd9Sstevel@tonic-gate 	 * size (data left in au_membuf - space in buffer)
126*7c478bd9Sstevel@tonic-gate 	 */
127*7c478bd9Sstevel@tonic-gate 	ssize_t		sz;
128*7c478bd9Sstevel@tonic-gate 	ssize_t		len;	/* len of data to move, size of AR */
129*7c478bd9Sstevel@tonic-gate 	int		error;	/* error return */
130*7c478bd9Sstevel@tonic-gate 	ssize_t		left;	/* data not xfered by write to disk */
131*7c478bd9Sstevel@tonic-gate 	statvfs64_t	sb;	/* buffer for statfs */
132*7c478bd9Sstevel@tonic-gate 	size_t		curr_sz = 0;	/* amount of data written during now */
133*7c478bd9Sstevel@tonic-gate 	int		part    = 0;	/* partial audit record written */
134*7c478bd9Sstevel@tonic-gate 	int		partial = 0;	/* flag to force partial AR to file */
135*7c478bd9Sstevel@tonic-gate 					/* 0 - idle, ignore */
136*7c478bd9Sstevel@tonic-gate 					/* 1 - force write of audit record */
137*7c478bd9Sstevel@tonic-gate 					/* 2 - finished writing AR, commit */
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_GZ;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * Check to ensure enough free space on audit device.
145*7c478bd9Sstevel@tonic-gate 	 */
146*7c478bd9Sstevel@tonic-gate 	bzero(&sb, sizeof (statvfs64_t));
147*7c478bd9Sstevel@tonic-gate 	(void) VFS_STATVFS(vp->v_vfsp, &sb);
148*7c478bd9Sstevel@tonic-gate 	/*
149*7c478bd9Sstevel@tonic-gate 	 * Large Files: We do not convert any of this part of kernel
150*7c478bd9Sstevel@tonic-gate 	 * to be large file aware. Original behaviour should be
151*7c478bd9Sstevel@tonic-gate 	 * maintained. This function is called from audit_svc and
152*7c478bd9Sstevel@tonic-gate 	 * it already checks for negative values of limit.
153*7c478bd9Sstevel@tonic-gate 	 */
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if (sb.f_blocks && (fsblkcnt64_t)limit > sb.f_bavail)
156*7c478bd9Sstevel@tonic-gate 		return (ENOSPC);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_file_stat.af_filesz &&
159*7c478bd9Sstevel@tonic-gate 		(kctx->auk_file_stat.af_currsz >=
160*7c478bd9Sstevel@tonic-gate 		kctx->auk_file_stat.af_filesz))
161*7c478bd9Sstevel@tonic-gate 		return (EFBIG);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	/*
164*7c478bd9Sstevel@tonic-gate 	 * has the write buffer changed length due to a auditctl(2)?
165*7c478bd9Sstevel@tonic-gate 	 * (remember that auk_buffer is an element of auk_dbuffer)
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) {
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		kmem_free(kctx->auk_buffer, kctx->auk_queue.buflen);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 		/* bad, should not sleep here. Testing only */
172*7c478bd9Sstevel@tonic-gate 		kctx->auk_buffer = kmem_alloc(kctx->auk_queue.bufsz, KM_SLEEP);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.buflen = kctx->auk_queue.bufsz;
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	if (!kctx->auk_queue.head) {
178*7c478bd9Sstevel@tonic-gate 		goto nodata;
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 	sp   = (token_t *)0; /* no AR copied */
181*7c478bd9Sstevel@tonic-gate 	off  = 0;	/* no space used in buffer */
182*7c478bd9Sstevel@tonic-gate 	used = 0;	/* no data processed in au_membuf */
183*7c478bd9Sstevel@tonic-gate 	cAR  = kctx->auk_queue.head;	/* start at head of queue */
184*7c478bd9Sstevel@tonic-gate 	cMB  = cAR;	/* start with first au_membuf of record */
185*7c478bd9Sstevel@tonic-gate 	bp = &(kctx->auk_buffer[0]);	/* start at beginning of buffer */
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	while (cMB) {
188*7c478bd9Sstevel@tonic-gate 		ASSERT(kctx->auk_queue.head != NULL);
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 		/* indicate audit record being processed */
191*7c478bd9Sstevel@tonic-gate 		part = 1;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		/* pointer to buffer data */
194*7c478bd9Sstevel@tonic-gate 		cp  = memtod(cMB, unsigned char *);
195*7c478bd9Sstevel@tonic-gate 		/* data left in au_membuf */
196*7c478bd9Sstevel@tonic-gate 		sz  = (ssize_t)cMB->len - used;
197*7c478bd9Sstevel@tonic-gate 		/* len to move */
198*7c478bd9Sstevel@tonic-gate 		len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 		/* move the data */
201*7c478bd9Sstevel@tonic-gate 		bcopy(cp + used, bp + off, len);
202*7c478bd9Sstevel@tonic-gate 		used += len; /* update used au_membuf */
203*7c478bd9Sstevel@tonic-gate 		off  += len; /* update offset into buffer */
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		if (used >= (ssize_t)cMB->len) {
206*7c478bd9Sstevel@tonic-gate 			/* advance to next au_membuf */
207*7c478bd9Sstevel@tonic-gate 			used = 0;
208*7c478bd9Sstevel@tonic-gate 			cMB  = cMB->next_buf;
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 		if (cMB == (au_buff_t *)0) {
211*7c478bd9Sstevel@tonic-gate 			/* advance to next AR */
212*7c478bd9Sstevel@tonic-gate 			sp   = cAR;
213*7c478bd9Sstevel@tonic-gate 			cAR  = cAR->next_rec;
214*7c478bd9Sstevel@tonic-gate 			cMB  = cAR;
215*7c478bd9Sstevel@tonic-gate 			/* reached end of an audit record */
216*7c478bd9Sstevel@tonic-gate 			part = 0;
217*7c478bd9Sstevel@tonic-gate 			/* force abort at end of audit record? */
218*7c478bd9Sstevel@tonic-gate 			if (partial == 1)
219*7c478bd9Sstevel@tonic-gate 				partial = 2;
220*7c478bd9Sstevel@tonic-gate 		}
221*7c478bd9Sstevel@tonic-gate 		/*
222*7c478bd9Sstevel@tonic-gate 		 * If we've reached end of buffer, or have run out of
223*7c478bd9Sstevel@tonic-gate 		 * audit records on the queue or we've processed a
224*7c478bd9Sstevel@tonic-gate 		 * partial audit record to complete the audit file,
225*7c478bd9Sstevel@tonic-gate 		 * then its time to flush the holding buffer to the
226*7c478bd9Sstevel@tonic-gate 		 * audit trail.
227*7c478bd9Sstevel@tonic-gate 		 */
228*7c478bd9Sstevel@tonic-gate 		if ((kctx->auk_queue.buflen == off) ||
229*7c478bd9Sstevel@tonic-gate 		    (cAR == (au_buff_t *)0) ||
230*7c478bd9Sstevel@tonic-gate 		    (partial == 2)) {
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 			left = 0;
233*7c478bd9Sstevel@tonic-gate 			/*
234*7c478bd9Sstevel@tonic-gate 			 * Largefiles: We purposely pass a value of
235*7c478bd9Sstevel@tonic-gate 			 * MAXOFF_T as we do not want any of the
236*7c478bd9Sstevel@tonic-gate 			 * auditing files to exceed 2GB. May be we will
237*7c478bd9Sstevel@tonic-gate 			 * support this in future.
238*7c478bd9Sstevel@tonic-gate 			 */
239*7c478bd9Sstevel@tonic-gate 			error = vn_rdwr(UIO_WRITE, vp, kctx->auk_buffer,
240*7c478bd9Sstevel@tonic-gate 				off, 0LL, UIO_SYSSPACE, FAPPEND,
241*7c478bd9Sstevel@tonic-gate 				(rlim64_t)MAXOFF_T, CRED(), &left);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 			/* error on write */
244*7c478bd9Sstevel@tonic-gate 			if (error != 0) {
245*7c478bd9Sstevel@tonic-gate 				if (error == EDQUOT)
246*7c478bd9Sstevel@tonic-gate 					error = ENOSPC;
247*7c478bd9Sstevel@tonic-gate 				return (error);
248*7c478bd9Sstevel@tonic-gate 			}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 			/* end of file system? */
251*7c478bd9Sstevel@tonic-gate 			if (left) {
252*7c478bd9Sstevel@tonic-gate 				au_buff_t *b = NULL;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 				sz = off - left; /* how much written */
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 				/* update space counters */
257*7c478bd9Sstevel@tonic-gate 				kctx->auk_file_stat.af_currsz += sz;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 				/* which AR are done */
260*7c478bd9Sstevel@tonic-gate 				cAR = kctx->auk_queue.head;
261*7c478bd9Sstevel@tonic-gate 				while (sz) {
262*7c478bd9Sstevel@tonic-gate 					cp  = memtod(cAR, unsigned char *);
263*7c478bd9Sstevel@tonic-gate 					len = (ssize_t)((cp[1]<<24 | cp[2]<<16 |
264*7c478bd9Sstevel@tonic-gate 						cp[3]<<8 | cp[4]) &
265*7c478bd9Sstevel@tonic-gate 						0xffffffffU);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 					if (len > sz)
268*7c478bd9Sstevel@tonic-gate 						break;
269*7c478bd9Sstevel@tonic-gate 					b = cAR;
270*7c478bd9Sstevel@tonic-gate 					cAR = cAR->next_rec;
271*7c478bd9Sstevel@tonic-gate 					sz -= len;
272*7c478bd9Sstevel@tonic-gate 				}
273*7c478bd9Sstevel@tonic-gate 				if (b != NULL)
274*7c478bd9Sstevel@tonic-gate 					au_dequeue(kctx, b);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 				return (ENOSPC);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 			} else {	/* still space in file system */
279*7c478bd9Sstevel@tonic-gate 				/* if we've written an AR */
280*7c478bd9Sstevel@tonic-gate 				if (sp) {
281*7c478bd9Sstevel@tonic-gate 					/*
282*7c478bd9Sstevel@tonic-gate 					 * free records up to last one copied.
283*7c478bd9Sstevel@tonic-gate 					 */
284*7c478bd9Sstevel@tonic-gate 					au_dequeue(kctx, sp);
285*7c478bd9Sstevel@tonic-gate 				}
286*7c478bd9Sstevel@tonic-gate 				/* Update sizes */
287*7c478bd9Sstevel@tonic-gate 				curr_sz += off;
288*7c478bd9Sstevel@tonic-gate 				kctx->auk_file_stat.af_currsz += (uint_t)off;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 				/* reset auk_buffer pointers */
291*7c478bd9Sstevel@tonic-gate 				sp = (token_t *)0;
292*7c478bd9Sstevel@tonic-gate 				off  = 0;
293*7c478bd9Sstevel@tonic-gate 				bp   = &(kctx->auk_buffer[0]);
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 				/* check exit conditions */
296*7c478bd9Sstevel@tonic-gate 				if (sb.f_blocks) {
297*7c478bd9Sstevel@tonic-gate 					ulong_t blks_used;
298*7c478bd9Sstevel@tonic-gate 					blks_used = (curr_sz / sb.f_bsize);
299*7c478bd9Sstevel@tonic-gate 					if ((fsblkcnt64_t)limit >
300*7c478bd9Sstevel@tonic-gate 				(sb.f_bavail - (fsblkcnt64_t)blks_used)) {
301*7c478bd9Sstevel@tonic-gate 						/*
302*7c478bd9Sstevel@tonic-gate 						 * if we haven't put out a
303*7c478bd9Sstevel@tonic-gate 						 * complete audit record,
304*7c478bd9Sstevel@tonic-gate 						 * continue to process the
305*7c478bd9Sstevel@tonic-gate 						 * audit queue until we reach
306*7c478bd9Sstevel@tonic-gate 						 * the end of the record.
307*7c478bd9Sstevel@tonic-gate 						 */
308*7c478bd9Sstevel@tonic-gate 						if (part && (partial == 0)) {
309*7c478bd9Sstevel@tonic-gate 							partial = 1;
310*7c478bd9Sstevel@tonic-gate 							continue;
311*7c478bd9Sstevel@tonic-gate 						}
312*7c478bd9Sstevel@tonic-gate 						/*
313*7c478bd9Sstevel@tonic-gate 						 * exit if complete record
314*7c478bd9Sstevel@tonic-gate 						 */
315*7c478bd9Sstevel@tonic-gate 						if (partial != 1)
316*7c478bd9Sstevel@tonic-gate 							return (ENOSPC);
317*7c478bd9Sstevel@tonic-gate 					}
318*7c478bd9Sstevel@tonic-gate 				}
319*7c478bd9Sstevel@tonic-gate 				if (kctx->auk_file_stat.af_filesz &&
320*7c478bd9Sstevel@tonic-gate 					(kctx->auk_file_stat.af_currsz
321*7c478bd9Sstevel@tonic-gate 					>= kctx->auk_file_stat.af_filesz)) {
322*7c478bd9Sstevel@tonic-gate 						/*
323*7c478bd9Sstevel@tonic-gate 						 * force a complete audit
324*7c478bd9Sstevel@tonic-gate 						 * record to the trail.
325*7c478bd9Sstevel@tonic-gate 						 */
326*7c478bd9Sstevel@tonic-gate 						if (partial == 0)
327*7c478bd9Sstevel@tonic-gate 							partial = 1;
328*7c478bd9Sstevel@tonic-gate 						/*
329*7c478bd9Sstevel@tonic-gate 						 * Written data to AR boundry.
330*7c478bd9Sstevel@tonic-gate 						 */
331*7c478bd9Sstevel@tonic-gate 						if (partial != 1)
332*7c478bd9Sstevel@tonic-gate 							return (EFBIG);
333*7c478bd9Sstevel@tonic-gate 				}
334*7c478bd9Sstevel@tonic-gate 			}
335*7c478bd9Sstevel@tonic-gate 		}
336*7c478bd9Sstevel@tonic-gate 	}	/* while(cMB) */
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate nodata:
339*7c478bd9Sstevel@tonic-gate 	return (0);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate /*
343*7c478bd9Sstevel@tonic-gate  * Close an audit descriptor.
344*7c478bd9Sstevel@tonic-gate  * Use the second parameter to indicate if it should be written or not.
345*7c478bd9Sstevel@tonic-gate  */
346*7c478bd9Sstevel@tonic-gate void
347*7c478bd9Sstevel@tonic-gate au_close(au_kcontext_t *kctx, caddr_t *d, int flag, short e_type, short e_mod)
348*7c478bd9Sstevel@tonic-gate {
349*7c478bd9Sstevel@tonic-gate 	token_t *dchain;	/* au_membuf chain which is the tokens */
350*7c478bd9Sstevel@tonic-gate 	t_audit_data_t *tad = U2A(u);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	ASSERT(tad != NULL);
353*7c478bd9Sstevel@tonic-gate 	ASSERT(d != NULL);
354*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if ((dchain = (token_t *)*d) == (token_t *)NULL)
357*7c478bd9Sstevel@tonic-gate 		return;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	*d = NULL;
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	/*
362*7c478bd9Sstevel@tonic-gate 	 * If async then defer; or if requested, defer the closing/queueing to
363*7c478bd9Sstevel@tonic-gate 	 * syscall end, unless no syscall is active or the syscall is _exit.
364*7c478bd9Sstevel@tonic-gate 	 */
365*7c478bd9Sstevel@tonic-gate 	if ((flag & AU_DONTBLOCK) || ((flag & AU_DEFER) &&
366*7c478bd9Sstevel@tonic-gate 	    (tad->tad_scid != 0) && (tad->tad_scid != SYS_exit))) {
367*7c478bd9Sstevel@tonic-gate 		au_close_defer(dchain, flag, e_type, e_mod);
368*7c478bd9Sstevel@tonic-gate 		return;
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 	au_close_time(kctx, dchain, flag, e_type, e_mod, NULL);
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /*
374*7c478bd9Sstevel@tonic-gate  * Defer closing/queueing of an audit descriptor. For async events, queue
375*7c478bd9Sstevel@tonic-gate  * via softcall. Otherwise, defer by queueing the record onto the tad; at
376*7c478bd9Sstevel@tonic-gate  * syscall end time it will be pulled off.
377*7c478bd9Sstevel@tonic-gate  */
378*7c478bd9Sstevel@tonic-gate void
379*7c478bd9Sstevel@tonic-gate au_close_defer(token_t *dchain, int flag, short e_type, short e_mod)
380*7c478bd9Sstevel@tonic-gate {
381*7c478bd9Sstevel@tonic-gate 	au_defer_info_t	*attr;
382*7c478bd9Sstevel@tonic-gate 	t_audit_data_t *tad = U2A(u);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	ASSERT(tad != NULL);
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	/* If not to be written, toss the record. */
387*7c478bd9Sstevel@tonic-gate 	if ((flag & AU_OK) == 0) {
388*7c478bd9Sstevel@tonic-gate 		au_toss_token(dchain);
389*7c478bd9Sstevel@tonic-gate 		return;
390*7c478bd9Sstevel@tonic-gate 	}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	attr = kmem_alloc(sizeof (au_defer_info_t), KM_NOSLEEP);
393*7c478bd9Sstevel@tonic-gate 	/* If no mem available, failing silently is the best recourse */
394*7c478bd9Sstevel@tonic-gate 	if (attr == NULL) {
395*7c478bd9Sstevel@tonic-gate 		au_toss_token(dchain);
396*7c478bd9Sstevel@tonic-gate 		return;
397*7c478bd9Sstevel@tonic-gate 	}
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	attr->audi_next = NULL;
400*7c478bd9Sstevel@tonic-gate 	attr->audi_ad = dchain;
401*7c478bd9Sstevel@tonic-gate 	attr->audi_e_type = e_type;
402*7c478bd9Sstevel@tonic-gate 	attr->audi_e_mod = e_mod;
403*7c478bd9Sstevel@tonic-gate 	attr->audi_flag = flag;
404*7c478bd9Sstevel@tonic-gate 	gethrestime(&attr->audi_atime);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/*
407*7c478bd9Sstevel@tonic-gate 	 * All async events must be queued via softcall to avoid possible
408*7c478bd9Sstevel@tonic-gate 	 * sleeping in high interrupt context. softcall will ensure it's
409*7c478bd9Sstevel@tonic-gate 	 * done on a dedicated software-level interrupt thread.
410*7c478bd9Sstevel@tonic-gate 	 */
411*7c478bd9Sstevel@tonic-gate 	if (flag & AU_DONTBLOCK) {
412*7c478bd9Sstevel@tonic-gate 		softcall(audit_async_finish_backend, attr);
413*7c478bd9Sstevel@tonic-gate 		audit_async_done(NULL, 0);
414*7c478bd9Sstevel@tonic-gate 		return;
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/*
418*7c478bd9Sstevel@tonic-gate 	 * If not an async event, defer by queuing onto the tad until
419*7c478bd9Sstevel@tonic-gate 	 * syscall end. No locking is needed because the tad is per-thread.
420*7c478bd9Sstevel@tonic-gate 	 */
421*7c478bd9Sstevel@tonic-gate 	if (tad->tad_defer_head)
422*7c478bd9Sstevel@tonic-gate 		tad->tad_defer_tail->audi_next = attr;
423*7c478bd9Sstevel@tonic-gate 	else
424*7c478bd9Sstevel@tonic-gate 		tad->tad_defer_head = attr;
425*7c478bd9Sstevel@tonic-gate 	tad->tad_defer_tail = attr;
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate  * Save the time in the event header. If time is not specified (i.e., pointer
431*7c478bd9Sstevel@tonic-gate  * is NULL), use the current time.  This code is fairly ugly since it needs
432*7c478bd9Sstevel@tonic-gate  * to support both 32- and 64-bit environments and can be called indirectly
433*7c478bd9Sstevel@tonic-gate  * from both au_close() (for kernel audit) and from audit() (userland audit).
434*7c478bd9Sstevel@tonic-gate  */
435*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
436*7c478bd9Sstevel@tonic-gate static void
437*7c478bd9Sstevel@tonic-gate au_save_time(adr_t *hadrp, timestruc_t *time, int size)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	struct {
440*7c478bd9Sstevel@tonic-gate 		uint32_t sec;
441*7c478bd9Sstevel@tonic-gate 		uint32_t usec;
442*7c478bd9Sstevel@tonic-gate 	} tv;
443*7c478bd9Sstevel@tonic-gate 	timestruc_t	now;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	if (time == NULL) {
446*7c478bd9Sstevel@tonic-gate 		gethrestime(&now);
447*7c478bd9Sstevel@tonic-gate 		time = &now;
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate #ifdef _LP64
451*7c478bd9Sstevel@tonic-gate 	if (size)
452*7c478bd9Sstevel@tonic-gate 		adr_int64(hadrp, (int64_t *)time, 2);
453*7c478bd9Sstevel@tonic-gate 	else
454*7c478bd9Sstevel@tonic-gate #endif
455*7c478bd9Sstevel@tonic-gate 	{
456*7c478bd9Sstevel@tonic-gate 		tv.sec = (uint32_t)time->tv_sec;
457*7c478bd9Sstevel@tonic-gate 		tv.usec = (uint32_t)time->tv_nsec;
458*7c478bd9Sstevel@tonic-gate 		adr_int32(hadrp, (int32_t *)&tv, 2);
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate /*
464*7c478bd9Sstevel@tonic-gate  * Close an audit descriptor.
465*7c478bd9Sstevel@tonic-gate  * If time of event is specified, use it in the record, otherwise use the
466*7c478bd9Sstevel@tonic-gate  * current time.
467*7c478bd9Sstevel@tonic-gate  */
468*7c478bd9Sstevel@tonic-gate void
469*7c478bd9Sstevel@tonic-gate au_close_time(au_kcontext_t *kctx, token_t *dchain, int flag, short e_type,
470*7c478bd9Sstevel@tonic-gate     short e_mod, timestruc_t *etime)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	token_t 	*record;	/* au_membuf chain == the record */
473*7c478bd9Sstevel@tonic-gate 	int		byte_count;
474*7c478bd9Sstevel@tonic-gate 	token_t 	*m;		/* for potential sequence token */
475*7c478bd9Sstevel@tonic-gate 	adr_t		hadr;		/* handle for header token */
476*7c478bd9Sstevel@tonic-gate 	adr_t		sadr;		/* handle for sequence token */
477*7c478bd9Sstevel@tonic-gate 	size_t		zone_length;	/* length of zonename token */
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	ASSERT(dchain != NULL);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	/* If not to be written, toss the record */
482*7c478bd9Sstevel@tonic-gate 	if ((flag & AU_OK) == 0) {
483*7c478bd9Sstevel@tonic-gate 		au_toss_token(dchain);
484*7c478bd9Sstevel@tonic-gate 		return;
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	/* if auditing not enabled, then don't generate an audit record */
487*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	if ((kctx->auk_auditstate != AUC_AUDITING) &&
490*7c478bd9Sstevel@tonic-gate 	    (kctx->auk_auditstate != AUC_INIT_AUDIT)) {
491*7c478bd9Sstevel@tonic-gate 		/*
492*7c478bd9Sstevel@tonic-gate 		 * at system boot, neither is set yet we want to generate
493*7c478bd9Sstevel@tonic-gate 		 * an audit record.
494*7c478bd9Sstevel@tonic-gate 		 */
495*7c478bd9Sstevel@tonic-gate 		if (e_type != AUE_SYSTEMBOOT) {
496*7c478bd9Sstevel@tonic-gate 			au_toss_token(dchain);
497*7c478bd9Sstevel@tonic-gate 			return;
498*7c478bd9Sstevel@tonic-gate 		}
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	/* Count up the bytes used in the record. */
502*7c478bd9Sstevel@tonic-gate 	byte_count = au_token_size(dchain);
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	/*
505*7c478bd9Sstevel@tonic-gate 	 * add in size of header token (always present).
506*7c478bd9Sstevel@tonic-gate 	 */
507*7c478bd9Sstevel@tonic-gate 	byte_count += sizeof (char) + sizeof (int32_t) +
508*7c478bd9Sstevel@tonic-gate 	    sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_hostaddr_valid)
511*7c478bd9Sstevel@tonic-gate 	    byte_count += sizeof (int32_t) + kctx->auk_info.ai_termid.at_type;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	/*
514*7c478bd9Sstevel@tonic-gate 	 * add in size of zonename token (zero if !AUDIT_ZONENAME)
515*7c478bd9Sstevel@tonic-gate 	 */
516*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_ZONENAME) {
517*7c478bd9Sstevel@tonic-gate 		zone_length = au_zonename_length();
518*7c478bd9Sstevel@tonic-gate 		byte_count += zone_length;
519*7c478bd9Sstevel@tonic-gate 	} else {
520*7c478bd9Sstevel@tonic-gate 		zone_length = 0;
521*7c478bd9Sstevel@tonic-gate 	}
522*7c478bd9Sstevel@tonic-gate 	/* add in size of (optional) trailer token */
523*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_TRAIL)
524*7c478bd9Sstevel@tonic-gate 		byte_count += 7;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	/* add in size of (optional) sequence token */
527*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_SEQ)
528*7c478bd9Sstevel@tonic-gate 		byte_count += 5;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	/* build the header */
531*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_hostaddr_valid)
532*7c478bd9Sstevel@tonic-gate 		record = au_to_header_ex(byte_count, e_type, e_mod);
533*7c478bd9Sstevel@tonic-gate 	else
534*7c478bd9Sstevel@tonic-gate 		record = au_to_header(byte_count, e_type, e_mod);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/*
537*7c478bd9Sstevel@tonic-gate 	 * If timestamp was specified, save it in header now. Otherwise,
538*7c478bd9Sstevel@tonic-gate 	 * save reference to header so we can update time/data later
539*7c478bd9Sstevel@tonic-gate 	 * and artificially adjust pointer to the time/date field of header.
540*7c478bd9Sstevel@tonic-gate 	 */
541*7c478bd9Sstevel@tonic-gate 	adr_start(&hadr, memtod(record, char *));
542*7c478bd9Sstevel@tonic-gate 	hadr.adr_now += sizeof (char) + sizeof (int32_t) +
543*7c478bd9Sstevel@tonic-gate 	    sizeof (char) + 2 * sizeof (short);
544*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_hostaddr_valid)
545*7c478bd9Sstevel@tonic-gate 		hadr.adr_now += sizeof (int32_t) +
546*7c478bd9Sstevel@tonic-gate 		    kctx->auk_info.ai_termid.at_type;
547*7c478bd9Sstevel@tonic-gate 	if (etime != NULL) {
548*7c478bd9Sstevel@tonic-gate 		au_save_time(&hadr, etime, 1);
549*7c478bd9Sstevel@tonic-gate 		hadr.adr_now = (char *)NULL;
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	/* append body of audit record */
553*7c478bd9Sstevel@tonic-gate 	(void) au_append_rec(record, dchain, AU_PACK);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	/* add (optional) zonename token */
556*7c478bd9Sstevel@tonic-gate 	if (zone_length > 0) {
557*7c478bd9Sstevel@tonic-gate 		m = au_to_zonename(zone_length);
558*7c478bd9Sstevel@tonic-gate 		(void) au_append_rec(record, m, AU_PACK);
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/* Add an (optional) sequence token. NULL offset if none */
562*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_SEQ) {
563*7c478bd9Sstevel@tonic-gate 		/* get the sequence token */
564*7c478bd9Sstevel@tonic-gate 		m = au_to_seq();
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		/* link to audit record (i.e. don't pack the data) */
567*7c478bd9Sstevel@tonic-gate 		(void) au_append_rec(record, m, AU_LINK);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 		/*
570*7c478bd9Sstevel@tonic-gate 		 * advance to count field of sequence token by skipping
571*7c478bd9Sstevel@tonic-gate 		 * the token type byte.
572*7c478bd9Sstevel@tonic-gate 		 */
573*7c478bd9Sstevel@tonic-gate 		adr_start(&sadr, memtod(m, char *));
574*7c478bd9Sstevel@tonic-gate 		sadr.adr_now += 1;
575*7c478bd9Sstevel@tonic-gate 	} else {
576*7c478bd9Sstevel@tonic-gate 		sadr.adr_now = NULL;
577*7c478bd9Sstevel@tonic-gate 	}
578*7c478bd9Sstevel@tonic-gate 	/* add (optional) trailer token */
579*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_TRAIL) {
580*7c478bd9Sstevel@tonic-gate 		(void) au_append_rec(record, au_to_trailer(byte_count),
581*7c478bd9Sstevel@tonic-gate 		    AU_PACK);
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/*
585*7c478bd9Sstevel@tonic-gate 	 * 1 - use 64 bit version of audit tokens for 64 bit kernels.
586*7c478bd9Sstevel@tonic-gate 	 * 0 - use 32 bit version of audit tokens for 32 bit kernels.
587*7c478bd9Sstevel@tonic-gate 	 */
588*7c478bd9Sstevel@tonic-gate #ifdef _LP64
589*7c478bd9Sstevel@tonic-gate 	au_enqueue(kctx, record, &hadr, &sadr, 1, flag & AU_DONTBLOCK);
590*7c478bd9Sstevel@tonic-gate #else
591*7c478bd9Sstevel@tonic-gate 	au_enqueue(kctx, record, &hadr, &sadr, 0, flag & AU_DONTBLOCK);
592*7c478bd9Sstevel@tonic-gate #endif
593*7c478bd9Sstevel@tonic-gate 	AS_INC(as_totalsize, byte_count, kctx);
594*7c478bd9Sstevel@tonic-gate }
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
597*7c478bd9Sstevel@tonic-gate void
598*7c478bd9Sstevel@tonic-gate au_enqueue(au_kcontext_t *kctx, au_buff_t *m, adr_t *hadrp, adr_t *sadrp,
599*7c478bd9Sstevel@tonic-gate     int size, int dontblock)
600*7c478bd9Sstevel@tonic-gate {
601*7c478bd9Sstevel@tonic-gate 	if (kctx == NULL)
602*7c478bd9Sstevel@tonic-gate 		return;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	if (!dontblock && (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) &&
607*7c478bd9Sstevel@tonic-gate 	    audit_sync_block(kctx)) {
608*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_queue.lock));
609*7c478bd9Sstevel@tonic-gate 		au_free_rec(m);
610*7c478bd9Sstevel@tonic-gate 		return;
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	/* Fill in date and time if needed */
614*7c478bd9Sstevel@tonic-gate 	if (hadrp->adr_now) {
615*7c478bd9Sstevel@tonic-gate 		au_save_time(hadrp, NULL, size);
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	/* address will be non-zero only if AUDIT_SEQ set */
619*7c478bd9Sstevel@tonic-gate 	if (sadrp->adr_now) {
620*7c478bd9Sstevel@tonic-gate 		kctx->auk_sequence++;
621*7c478bd9Sstevel@tonic-gate 		adr_int32(sadrp, (int32_t *)&(kctx->auk_sequence), 1);
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.head)
625*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.tail->next_rec = m;
626*7c478bd9Sstevel@tonic-gate 	else
627*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.head = m;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	kctx->auk_queue.tail = m;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	if (++(kctx->auk_queue.cnt) >
632*7c478bd9Sstevel@tonic-gate 	    kctx->auk_queue.lowater && kctx->auk_queue.rd_block)
633*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.read_cv));
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	/* count # audit records put onto kernel audit queue */
638*7c478bd9Sstevel@tonic-gate 	AS_INC(as_enqueue, 1, kctx);
639*7c478bd9Sstevel@tonic-gate }
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate /*
642*7c478bd9Sstevel@tonic-gate  * Dequeue and free buffers upto and including "freeto"
643*7c478bd9Sstevel@tonic-gate  * Keeps the queue lock long but acquires it only once when doing
644*7c478bd9Sstevel@tonic-gate  * bulk dequeueing.
645*7c478bd9Sstevel@tonic-gate  */
646*7c478bd9Sstevel@tonic-gate static void
647*7c478bd9Sstevel@tonic-gate au_dequeue(au_kcontext_t *kctx, au_buff_t *freeto)
648*7c478bd9Sstevel@tonic-gate {
649*7c478bd9Sstevel@tonic-gate 	au_buff_t *m, *l, *lastl;
650*7c478bd9Sstevel@tonic-gate 	int n = 0;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx->auk_queue.head != NULL);
657*7c478bd9Sstevel@tonic-gate 	ASSERT(freeto != NULL);
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	l = m = kctx->auk_queue.head;
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	do {
662*7c478bd9Sstevel@tonic-gate 		n++;
663*7c478bd9Sstevel@tonic-gate 		lastl = l;
664*7c478bd9Sstevel@tonic-gate 		l = l->next_rec;
665*7c478bd9Sstevel@tonic-gate 	} while (l != NULL && freeto != lastl);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	kctx->auk_queue.cnt -= n;
668*7c478bd9Sstevel@tonic-gate 	lastl->next_rec = NULL;
669*7c478bd9Sstevel@tonic-gate 	kctx->auk_queue.head = l;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	/* Freeto must exist in the list */
672*7c478bd9Sstevel@tonic-gate 	ASSERT(freeto == lastl);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.cnt <= kctx->auk_queue.lowater &&
675*7c478bd9Sstevel@tonic-gate 	    kctx->auk_queue.wt_block)
676*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.write_cv));
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	while (m) {
681*7c478bd9Sstevel@tonic-gate 		l = m->next_rec;
682*7c478bd9Sstevel@tonic-gate 		au_free_rec(m);
683*7c478bd9Sstevel@tonic-gate 		m = l;
684*7c478bd9Sstevel@tonic-gate 	}
685*7c478bd9Sstevel@tonic-gate 	AS_INC(as_written, n, kctx);
686*7c478bd9Sstevel@tonic-gate }
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate /*
689*7c478bd9Sstevel@tonic-gate  * audit_sync_block()
690*7c478bd9Sstevel@tonic-gate  * If we've reached the high water mark, we look at the policy to see
691*7c478bd9Sstevel@tonic-gate  * if we sleep or we should drop the audit record.
692*7c478bd9Sstevel@tonic-gate  * This function is called with the auk_queue.lock held and the check
693*7c478bd9Sstevel@tonic-gate  * performed one time already as an optimization.  Caller should unlock.
694*7c478bd9Sstevel@tonic-gate  * Returns 1 if the caller needs to free the record.
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate static int
697*7c478bd9Sstevel@tonic-gate audit_sync_block(au_kcontext_t *kctx)
698*7c478bd9Sstevel@tonic-gate {
699*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&(kctx->auk_queue.lock)));
700*7c478bd9Sstevel@tonic-gate 	/*
701*7c478bd9Sstevel@tonic-gate 	 * Loop while we are at the high watermark.
702*7c478bd9Sstevel@tonic-gate 	 */
703*7c478bd9Sstevel@tonic-gate 	do {
704*7c478bd9Sstevel@tonic-gate 		if ((kctx->auk_auditstate != AUC_AUDITING) ||
705*7c478bd9Sstevel@tonic-gate 		    (kctx->auk_policy & AUDIT_CNT)) {
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 			/* just count # of dropped audit records */
708*7c478bd9Sstevel@tonic-gate 			AS_INC(as_dropped, 1, kctx);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 			return (1);
711*7c478bd9Sstevel@tonic-gate 		}
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		/* kick reader awake if its asleep */
714*7c478bd9Sstevel@tonic-gate 		if (kctx->auk_queue.rd_block &&
715*7c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.cnt > kctx->auk_queue.lowater)
716*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&(kctx->auk_queue.read_cv));
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		/* keep count of # times blocked */
719*7c478bd9Sstevel@tonic-gate 		AS_INC(as_wblocked, 1, kctx);
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 		/* sleep now, until woken by reader */
722*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.wt_block++;
723*7c478bd9Sstevel@tonic-gate 		cv_wait(&(kctx->auk_queue.write_cv), &(kctx->auk_queue.lock));
724*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.wt_block--;
725*7c478bd9Sstevel@tonic-gate 	} while (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater);
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	return (0);
728*7c478bd9Sstevel@tonic-gate }
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate /*
731*7c478bd9Sstevel@tonic-gate  * audit_async_block()
732*7c478bd9Sstevel@tonic-gate  * if we've reached the high water mark, we look at the ahlt policy to see
733*7c478bd9Sstevel@tonic-gate  * if we reboot we should drop the audit record.
734*7c478bd9Sstevel@tonic-gate  * Returns 1 if blocked.
735*7c478bd9Sstevel@tonic-gate  */
736*7c478bd9Sstevel@tonic-gate static int
737*7c478bd9Sstevel@tonic-gate audit_async_block(au_kcontext_t *kctx, caddr_t *rpp)
738*7c478bd9Sstevel@tonic-gate {
739*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
742*7c478bd9Sstevel@tonic-gate 	/* see if we've reached high water mark */
743*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) {
744*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_queue.lock));
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 		audit_async_drop(rpp, AU_BACKEND);
747*7c478bd9Sstevel@tonic-gate 		return (1);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
750*7c478bd9Sstevel@tonic-gate 	return (0);
751*7c478bd9Sstevel@tonic-gate }
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate /*
754*7c478bd9Sstevel@tonic-gate  * au_door_upcall.  auditdoor() may change vp without notice, so
755*7c478bd9Sstevel@tonic-gate  * some locking seems in order.
756*7c478bd9Sstevel@tonic-gate  *
757*7c478bd9Sstevel@tonic-gate  */
758*7c478bd9Sstevel@tonic-gate #define	AGAIN_TICKS	10
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate static int
761*7c478bd9Sstevel@tonic-gate au_door_upcall(au_kcontext_t *kctx, au_dbuf_t *aubuf)
762*7c478bd9Sstevel@tonic-gate {
763*7c478bd9Sstevel@tonic-gate 	int		rc;
764*7c478bd9Sstevel@tonic-gate 	door_arg_t	darg;
765*7c478bd9Sstevel@tonic-gate 	int		retry = 1;
766*7c478bd9Sstevel@tonic-gate 	int		ticks_to_wait;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	darg.data_ptr = (char *)aubuf;
769*7c478bd9Sstevel@tonic-gate 	darg.data_size = AU_DBUF_HEADER + aubuf->aub_size;
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	darg.desc_ptr = NULL;
772*7c478bd9Sstevel@tonic-gate 	darg.desc_num = 0;
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	while (retry == 1) {
775*7c478bd9Sstevel@tonic-gate 		/* non-zero means return results expected */
776*7c478bd9Sstevel@tonic-gate 		darg.rbuf = (char *)aubuf;
777*7c478bd9Sstevel@tonic-gate 		darg.rsize = darg.data_size;
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 		retry = 0;
780*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_svc_lock));
781*7c478bd9Sstevel@tonic-gate 		if ((rc = door_upcall(kctx->auk_current_vp, &darg)) != 0) {
782*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_svc_lock));
783*7c478bd9Sstevel@tonic-gate 			if (rc == EAGAIN)
784*7c478bd9Sstevel@tonic-gate 				ticks_to_wait = AGAIN_TICKS;
785*7c478bd9Sstevel@tonic-gate 			else
786*7c478bd9Sstevel@tonic-gate 				return (rc);
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 			mutex_enter(&(kctx->auk_eagain_mutex));
789*7c478bd9Sstevel@tonic-gate 			(void) cv_timedwait(&(kctx->auk_eagain_cv),
790*7c478bd9Sstevel@tonic-gate 			    &(kctx->auk_eagain_mutex),
791*7c478bd9Sstevel@tonic-gate 			    lbolt + ticks_to_wait);
792*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_eagain_mutex));
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 			retry = 1;
795*7c478bd9Sstevel@tonic-gate 		} else
796*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_svc_lock));	/* no retry */
797*7c478bd9Sstevel@tonic-gate 	}	/* end while (retry == 1) */
798*7c478bd9Sstevel@tonic-gate 	if (darg.rbuf == NULL)
799*7c478bd9Sstevel@tonic-gate 		return (-1);
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	/* return code from door server */
802*7c478bd9Sstevel@tonic-gate 	return (*(int *)darg.rbuf);
803*7c478bd9Sstevel@tonic-gate }
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate /*
806*7c478bd9Sstevel@tonic-gate  * Write an audit control message to the door handle.  The message
807*7c478bd9Sstevel@tonic-gate  * structure depends on message_code and at present the only control
808*7c478bd9Sstevel@tonic-gate  * message defined is for a policy change.  These are infrequent,
809*7c478bd9Sstevel@tonic-gate  * so no memory is held for control messages.
810*7c478bd9Sstevel@tonic-gate  */
811*7c478bd9Sstevel@tonic-gate int
812*7c478bd9Sstevel@tonic-gate au_doormsg(au_kcontext_t *kctx, uint32_t message_code, void *message)
813*7c478bd9Sstevel@tonic-gate {
814*7c478bd9Sstevel@tonic-gate 	int		rc;
815*7c478bd9Sstevel@tonic-gate 	au_dbuf_t	*buf;
816*7c478bd9Sstevel@tonic-gate 	size_t		alloc_size;
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	switch (message_code) {
819*7c478bd9Sstevel@tonic-gate 	case AU_DBUF_POLICY:
820*7c478bd9Sstevel@tonic-gate 		alloc_size = AU_DBUF_HEADER + sizeof (uint32_t);
821*7c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(alloc_size, KM_SLEEP);
822*7c478bd9Sstevel@tonic-gate 		buf->aub_size = sizeof (uint32_t);
823*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)buf->aub_buf = *(uint32_t *)message;
824*7c478bd9Sstevel@tonic-gate 		break;
825*7c478bd9Sstevel@tonic-gate 	case AU_DBUF_SHUTDOWN:
826*7c478bd9Sstevel@tonic-gate 		alloc_size = AU_DBUF_HEADER;
827*7c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(alloc_size, KM_SLEEP);
828*7c478bd9Sstevel@tonic-gate 		buf->aub_size = 0;
829*7c478bd9Sstevel@tonic-gate 		break;
830*7c478bd9Sstevel@tonic-gate 	default:
831*7c478bd9Sstevel@tonic-gate 		return (1);
832*7c478bd9Sstevel@tonic-gate 	}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	buf->aub_type = AU_DBUF_NOTIFY | message_code;
835*7c478bd9Sstevel@tonic-gate 	rc = au_door_upcall(kctx, buf);
836*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, alloc_size);
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	return (rc);
839*7c478bd9Sstevel@tonic-gate }
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate /*
842*7c478bd9Sstevel@tonic-gate  * Write audit information to the door handle.  au_doorio is called with
843*7c478bd9Sstevel@tonic-gate  * one or more complete audit records on the queue and outputs those
844*7c478bd9Sstevel@tonic-gate  * records in buffers of up to auk_queue.buflen in size.
845*7c478bd9Sstevel@tonic-gate  */
846*7c478bd9Sstevel@tonic-gate int
847*7c478bd9Sstevel@tonic-gate au_doorio(au_kcontext_t *kctx) {
848*7c478bd9Sstevel@tonic-gate 	off_t		off;	/* space used in buffer */
849*7c478bd9Sstevel@tonic-gate 	ssize_t		used;	/* space used in au_membuf */
850*7c478bd9Sstevel@tonic-gate 	token_t		*cAR;	/* current AR being processed */
851*7c478bd9Sstevel@tonic-gate 	token_t		*cMB;	/* current au_membuf being processed */
852*7c478bd9Sstevel@tonic-gate 	token_t		*sp;	/* last AR processed */
853*7c478bd9Sstevel@tonic-gate 	char		*bp;	/* start of free space in staging buffer */
854*7c478bd9Sstevel@tonic-gate 	unsigned char	*cp;	/* ptr to data to be moved */
855*7c478bd9Sstevel@tonic-gate 	int		error;  /* return from door upcall */
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * size (data left in au_membuf - space in buffer)
859*7c478bd9Sstevel@tonic-gate 	 */
860*7c478bd9Sstevel@tonic-gate 	ssize_t		sz;
861*7c478bd9Sstevel@tonic-gate 	ssize_t		len;	/* len of data to move, size of AR */
862*7c478bd9Sstevel@tonic-gate 	ssize_t		curr_sz = 0;	/* amount of data written during now */
863*7c478bd9Sstevel@tonic-gate 	/*
864*7c478bd9Sstevel@tonic-gate 	 * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h
865*7c478bd9Sstevel@tonic-gate 	 */
866*7c478bd9Sstevel@tonic-gate 	int		part    = 0;	/* partial audit record written */
867*7c478bd9Sstevel@tonic-gate 	int		partial_state = AU_DBUF_COMPLETE;
868*7c478bd9Sstevel@tonic-gate 	/*
869*7c478bd9Sstevel@tonic-gate 	 * Has the write buffer changed length due to a auditctl(2)?
870*7c478bd9Sstevel@tonic-gate 	 * Initial allocation is from audit_start.c/audit_init()
871*7c478bd9Sstevel@tonic-gate 	 */
872*7c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) {
873*7c478bd9Sstevel@tonic-gate 		kmem_free(kctx->auk_dbuffer, AU_DBUF_HEADER +
874*7c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.buflen);
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 		kctx->auk_dbuffer = kmem_alloc(AU_DBUF_HEADER +
877*7c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.bufsz, KM_SLEEP);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 		/* omit the 64 bit header */
880*7c478bd9Sstevel@tonic-gate 		kctx->auk_queue.buflen = kctx->auk_queue.bufsz;
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 	if (!kctx->auk_queue.head)
883*7c478bd9Sstevel@tonic-gate 		goto nodata;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	sp   = NULL;	/* no record copied */
886*7c478bd9Sstevel@tonic-gate 	off  = 0;	/* no space used in buffer */
887*7c478bd9Sstevel@tonic-gate 	used = 0;	/* no data processed in au_membuf */
888*7c478bd9Sstevel@tonic-gate 	cAR  = kctx->auk_queue.head;	/* start at head of queue */
889*7c478bd9Sstevel@tonic-gate 	cMB  = cAR;	/* start with first au_membuf of record */
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	/* start at beginning of buffer */
892*7c478bd9Sstevel@tonic-gate 	bp   = &(kctx->auk_dbuffer->aub_buf[0]);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	while (cMB) {
895*7c478bd9Sstevel@tonic-gate 		part = 1;	/* indicate audit record being processed */
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 		cp  = memtod(cMB, unsigned char *); /* buffer ptr */
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 		sz  = (ssize_t)cMB->len - used;	/* data left in au_membuf */
900*7c478bd9Sstevel@tonic-gate 		/* len to move */
901*7c478bd9Sstevel@tonic-gate 		len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off);
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 		/* move the data */
904*7c478bd9Sstevel@tonic-gate 		bcopy(cp + used, bp + off, len);
905*7c478bd9Sstevel@tonic-gate 		used += len; /* update used au_membuf */
906*7c478bd9Sstevel@tonic-gate 		off  += len; /* update offset into buffer */
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 		if (used >= (ssize_t)cMB->len) {
909*7c478bd9Sstevel@tonic-gate 			/* advance to next au_membuf */
910*7c478bd9Sstevel@tonic-gate 			used = 0;
911*7c478bd9Sstevel@tonic-gate 			cMB  = cMB->next_buf;
912*7c478bd9Sstevel@tonic-gate 		}
913*7c478bd9Sstevel@tonic-gate 		if (cMB == NULL) {
914*7c478bd9Sstevel@tonic-gate 			/* advance to next audit record */
915*7c478bd9Sstevel@tonic-gate 			sp   = cAR;
916*7c478bd9Sstevel@tonic-gate 			cAR  = cAR->next_rec;
917*7c478bd9Sstevel@tonic-gate 			cMB  = cAR;
918*7c478bd9Sstevel@tonic-gate 			part = 0;	/* have a complete record */
919*7c478bd9Sstevel@tonic-gate 		}
920*7c478bd9Sstevel@tonic-gate 		error = 0;
921*7c478bd9Sstevel@tonic-gate 		if ((kctx->auk_queue.buflen == off) || (part == 0)) {
922*7c478bd9Sstevel@tonic-gate 			if (part)
923*7c478bd9Sstevel@tonic-gate 				partial_state = state_if_part[partial_state];
924*7c478bd9Sstevel@tonic-gate 			else
925*7c478bd9Sstevel@tonic-gate 				partial_state =
926*7c478bd9Sstevel@tonic-gate 				    state_if_not_part[partial_state];
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 			kctx->auk_dbuffer->aub_type = partial_state;
929*7c478bd9Sstevel@tonic-gate 			kctx->auk_dbuffer->aub_size = off;
930*7c478bd9Sstevel@tonic-gate 			error = au_door_upcall(kctx, kctx->auk_dbuffer);
931*7c478bd9Sstevel@tonic-gate 			if (error != 0)
932*7c478bd9Sstevel@tonic-gate 				goto nodata;
933*7c478bd9Sstevel@tonic-gate 			/*
934*7c478bd9Sstevel@tonic-gate 			 * if we've successfully written an audit record,
935*7c478bd9Sstevel@tonic-gate 			 * free records up to last full record copied
936*7c478bd9Sstevel@tonic-gate 			 */
937*7c478bd9Sstevel@tonic-gate 			if (sp)
938*7c478bd9Sstevel@tonic-gate 				au_dequeue(kctx, sp);
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 				/* Update size */
941*7c478bd9Sstevel@tonic-gate 			curr_sz += off;
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 				/* reset auk_dbuffer pointers */
944*7c478bd9Sstevel@tonic-gate 			sp = NULL;
945*7c478bd9Sstevel@tonic-gate 			off  = 0;
946*7c478bd9Sstevel@tonic-gate 		}
947*7c478bd9Sstevel@tonic-gate 	}	/* while(cMB) */
948*7c478bd9Sstevel@tonic-gate nodata:
949*7c478bd9Sstevel@tonic-gate 	return (error);
950*7c478bd9Sstevel@tonic-gate }
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate /*
953*7c478bd9Sstevel@tonic-gate  * Clean up thread audit state to clear out asynchronous audit record
954*7c478bd9Sstevel@tonic-gate  * generation error recovery processing. Note that this is done on a
955*7c478bd9Sstevel@tonic-gate  * per-thread basis and thus does not need any locking.
956*7c478bd9Sstevel@tonic-gate  */
957*7c478bd9Sstevel@tonic-gate void
958*7c478bd9Sstevel@tonic-gate audit_async_done(caddr_t *rpp, int flags)
959*7c478bd9Sstevel@tonic-gate {
960*7c478bd9Sstevel@tonic-gate 	t_audit_data_t *tad = U2A(u);
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	/* clean up the tad unless called from softcall backend */
963*7c478bd9Sstevel@tonic-gate 	if (!(flags & AU_BACKEND)) {
964*7c478bd9Sstevel@tonic-gate 		ASSERT(tad != NULL);
965*7c478bd9Sstevel@tonic-gate 		ASSERT(tad->tad_ctrl & PAD_ERRJMP);
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 		tad->tad_ctrl &= ~PAD_ERRJMP;
968*7c478bd9Sstevel@tonic-gate 		tad->tad_errjmp = NULL;
969*7c478bd9Sstevel@tonic-gate 	}
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate 	/* clean out partial audit record */
972*7c478bd9Sstevel@tonic-gate 	if ((rpp != NULL) && (*rpp != NULL)) {
973*7c478bd9Sstevel@tonic-gate 		au_toss_token((au_buff_t *)*rpp);
974*7c478bd9Sstevel@tonic-gate 		*rpp = NULL;
975*7c478bd9Sstevel@tonic-gate 	}
976*7c478bd9Sstevel@tonic-gate }
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate /*
979*7c478bd9Sstevel@tonic-gate  * implement the audit policy for asynchronous events generated within
980*7c478bd9Sstevel@tonic-gate  * the kernel.
981*7c478bd9Sstevel@tonic-gate  * XXX might need locks around audit_policy check.
982*7c478bd9Sstevel@tonic-gate  */
983*7c478bd9Sstevel@tonic-gate void
984*7c478bd9Sstevel@tonic-gate audit_async_drop(caddr_t *rpp, int flags)
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 	/* could not generate audit record, clean up */
989*7c478bd9Sstevel@tonic-gate 	audit_async_done((caddr_t *)rpp, flags);
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_GZ;
992*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
993*7c478bd9Sstevel@tonic-gate 	/* just drop the record and return */
994*7c478bd9Sstevel@tonic-gate 	if (((audit_policy & AUDIT_AHLT) == 0) ||
995*7c478bd9Sstevel@tonic-gate 	    (kctx->auk_auditstate == AUC_INIT_AUDIT)) {
996*7c478bd9Sstevel@tonic-gate 		/* just count # of dropped audit records */
997*7c478bd9Sstevel@tonic-gate 		AS_INC(as_dropped, 1, kctx);
998*7c478bd9Sstevel@tonic-gate 		return;
999*7c478bd9Sstevel@tonic-gate 	}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	/*
1002*7c478bd9Sstevel@tonic-gate 	 * There can be a lot of data in the audit queue. We
1003*7c478bd9Sstevel@tonic-gate 	 * will first sync the file systems then attempt to
1004*7c478bd9Sstevel@tonic-gate 	 * shutdown the kernel so that a memory dump is
1005*7c478bd9Sstevel@tonic-gate 	 * performed.
1006*7c478bd9Sstevel@tonic-gate 	 */
1007*7c478bd9Sstevel@tonic-gate 	sync();
1008*7c478bd9Sstevel@tonic-gate 	sync();
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	/*
1011*7c478bd9Sstevel@tonic-gate 	 * now shut down. What a cruel world it has been
1012*7c478bd9Sstevel@tonic-gate 	 */
1013*7c478bd9Sstevel@tonic-gate 	panic("non-attributable halt. should dump core");
1014*7c478bd9Sstevel@tonic-gate 	/* No return */
1015*7c478bd9Sstevel@tonic-gate }
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate int
1018*7c478bd9Sstevel@tonic-gate audit_async_start(label_t *jb, int event, int sorf)
1019*7c478bd9Sstevel@tonic-gate {
1020*7c478bd9Sstevel@tonic-gate 	t_audit_data_t *tad = U2A(u);
1021*7c478bd9Sstevel@tonic-gate 	au_state_t estate;
1022*7c478bd9Sstevel@tonic-gate 	int success = 0, failure = 0;
1023*7c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_GZ;
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 	/* if audit state off, then no audit record generation */
1028*7c478bd9Sstevel@tonic-gate 	if ((kctx->auk_auditstate != AUC_AUDITING) &&
1029*7c478bd9Sstevel@tonic-gate 	    (kctx->auk_auditstate != AUC_INIT_AUDIT))
1030*7c478bd9Sstevel@tonic-gate 		return (1);
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	/*
1033*7c478bd9Sstevel@tonic-gate 	 * preselect asynchronous event
1034*7c478bd9Sstevel@tonic-gate 	 * XXX should we check for out-of-range???
1035*7c478bd9Sstevel@tonic-gate 	 */
1036*7c478bd9Sstevel@tonic-gate 	estate = kctx->auk_ets[event];
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	if (sorf & AUM_SUCC)
1039*7c478bd9Sstevel@tonic-gate 		success = kctx->auk_info.ai_mask.as_success & estate;
1040*7c478bd9Sstevel@tonic-gate 	if (sorf & AUM_FAIL)
1041*7c478bd9Sstevel@tonic-gate 		failure = kctx->auk_info.ai_mask.as_failure & estate;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	if ((success | failure) == NULL)
1044*7c478bd9Sstevel@tonic-gate 		return (1);
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	ASSERT(tad->tad_errjmp == NULL);
1047*7c478bd9Sstevel@tonic-gate 	tad->tad_errjmp = (void *)jb;
1048*7c478bd9Sstevel@tonic-gate 	tad->tad_ctrl |= PAD_ERRJMP;
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	return (0);
1051*7c478bd9Sstevel@tonic-gate }
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate /*
1054*7c478bd9Sstevel@tonic-gate  * Complete auditing of an async event. The AU_DONTBLOCK flag to au_close will
1055*7c478bd9Sstevel@tonic-gate  * result in the backend routine being invoked from softcall, so all the real
1056*7c478bd9Sstevel@tonic-gate  * work can be done in a safe context.
1057*7c478bd9Sstevel@tonic-gate  */
1058*7c478bd9Sstevel@tonic-gate void
1059*7c478bd9Sstevel@tonic-gate audit_async_finish(caddr_t *ad, int aid, int amod)
1060*7c478bd9Sstevel@tonic-gate {
1061*7c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	kctx  = SET_KCTX_GZ;
1064*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	au_close(kctx, ad, AU_DONTBLOCK | AU_OK, aid, PAD_NONATTR|amod);
1067*7c478bd9Sstevel@tonic-gate }
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate /*
1070*7c478bd9Sstevel@tonic-gate  * Backend routine to complete an async audit. Invoked from softcall.
1071*7c478bd9Sstevel@tonic-gate  * (Note: the blocking and the queuing below both involve locking which can't
1072*7c478bd9Sstevel@tonic-gate  * be done safely in high interrupt context due to the chance of sleeping on
1073*7c478bd9Sstevel@tonic-gate  * the corresponding adaptive mutex. Hence the softcall.)
1074*7c478bd9Sstevel@tonic-gate  */
1075*7c478bd9Sstevel@tonic-gate static void
1076*7c478bd9Sstevel@tonic-gate audit_async_finish_backend(void *addr)
1077*7c478bd9Sstevel@tonic-gate {
1078*7c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
1079*7c478bd9Sstevel@tonic-gate 	au_defer_info_t	*attr = (au_defer_info_t *)addr;
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	if (attr == NULL)
1082*7c478bd9Sstevel@tonic-gate 		return;		/* won't happen unless softcall is broken */
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	kctx  = SET_KCTX_GZ;
1085*7c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	if (audit_async_block(kctx, (caddr_t *)&attr->audi_ad)) {
1088*7c478bd9Sstevel@tonic-gate 		kmem_free(attr, sizeof (au_defer_info_t));
1089*7c478bd9Sstevel@tonic-gate 		return;
1090*7c478bd9Sstevel@tonic-gate 	}
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	/*
1093*7c478bd9Sstevel@tonic-gate 	 * Call au_close_time to complete the audit with the saved values.
1094*7c478bd9Sstevel@tonic-gate 	 *
1095*7c478bd9Sstevel@tonic-gate 	 * For the exit-prom event, use the current time instead of the
1096*7c478bd9Sstevel@tonic-gate 	 * saved time as a better approximation. (Because the time saved via
1097*7c478bd9Sstevel@tonic-gate 	 * gethrestime during prom-exit handling would not yet be caught up
1098*7c478bd9Sstevel@tonic-gate 	 * after the system was idled in the debugger for a period of time.)
1099*7c478bd9Sstevel@tonic-gate 	 */
1100*7c478bd9Sstevel@tonic-gate 	if (attr->audi_e_type == AUE_EXITPROM) {
1101*7c478bd9Sstevel@tonic-gate 		au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag,
1102*7c478bd9Sstevel@tonic-gate 		    attr->audi_e_type, attr->audi_e_mod, NULL);
1103*7c478bd9Sstevel@tonic-gate 	} else {
1104*7c478bd9Sstevel@tonic-gate 		au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag,
1105*7c478bd9Sstevel@tonic-gate 		    attr->audi_e_type, attr->audi_e_mod, &attr->audi_atime);
1106*7c478bd9Sstevel@tonic-gate 	}
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	AS_INC(as_generated, 1, kctx);
1109*7c478bd9Sstevel@tonic-gate 	AS_INC(as_nonattrib, 1, kctx);
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	kmem_free(attr, sizeof (au_defer_info_t));
1112*7c478bd9Sstevel@tonic-gate }
1113