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