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