audit_io.c revision 787b48eaa495c619f2cbed6175e0fead6a840516
d51e90740114c60620c0febffd4d3ce6e280a107ab * CDDL HEADER START
d51e90740114c60620c0febffd4d3ce6e280a107ab * The contents of this file are subject to the terms of the
d51e90740114c60620c0febffd4d3ce6e280a107ab * Common Development and Distribution License (the "License").
d51e90740114c60620c0febffd4d3ce6e280a107ab * You may not use this file except in compliance with the License.
d51e90740114c60620c0febffd4d3ce6e280a107ab * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d51e90740114c60620c0febffd4d3ce6e280a107ab * See the License for the specific language governing permissions
d51e90740114c60620c0febffd4d3ce6e280a107ab * and limitations under the License.
d51e90740114c60620c0febffd4d3ce6e280a107ab * When distributing Covered Code, include this CDDL HEADER in each
d51e90740114c60620c0febffd4d3ce6e280a107ab * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d51e90740114c60620c0febffd4d3ce6e280a107ab * If applicable, add the following below this CDDL HEADER, with the
d51e90740114c60620c0febffd4d3ce6e280a107ab * fields enclosed by brackets "[]" replaced with your own identifying
d51e90740114c60620c0febffd4d3ce6e280a107ab * information: Portions Copyright [yyyy] [name of copyright owner]
d51e90740114c60620c0febffd4d3ce6e280a107ab * CDDL HEADER END
d51e90740114c60620c0febffd4d3ce6e280a107ab * Routines for writing audit records.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Use is subject to license terms.
beee6fc0eea41662170c4dea38a7e5605ab59507Bryan Cantrill#pragma ident "%Z%%M% %I% %E% SMI"
d51e90740114c60620c0febffd4d3ce6e280a107abstatic void audit_async_finish_backend(void *);
d51e90740114c60620c0febffd4d3ce6e280a107ab * each of these two tables are indexed by the values AU_DBUF_COMPLETE
d51e90740114c60620c0febffd4d3ce6e280a107ab * through AU_DBUF_LAST; the content is the next state value. The
d51e90740114c60620c0febffd4d3ce6e280a107ab * first table determines the next state for a buffer which is not the
d51e90740114c60620c0febffd4d3ce6e280a107ab * end of a record and the second table determines the state for a
d51e90740114c60620c0febffd4d3ce6e280a107ab * buffer which is the end of a record. The initial state is
d51e90740114c60620c0febffd4d3ce6e280a107ab * AU_DBUF_COMPLETE.
d51e90740114c60620c0febffd4d3ce6e280a107abstatic int state_if_part[] = {
d51e90740114c60620c0febffd4d3ce6e280a107ab AU_DBUF_FIRST, AU_DBUF_MIDDLE, AU_DBUF_MIDDLE, AU_DBUF_FIRST};
d51e90740114c60620c0febffd4d3ce6e280a107abstatic int state_if_not_part[] = {
d51e90740114c60620c0febffd4d3ce6e280a107ab AU_DBUF_COMPLETE, AU_DBUF_LAST, AU_DBUF_LAST, AU_DBUF_COMPLETE};
d51e90740114c60620c0febffd4d3ce6e280a107ab * Write to an audit descriptor.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Add the au_membuf to the descriptor chain and free the chain passed in.
d51e90740114c60620c0febffd4d3ce6e280a107ab if (d == NULL) {
d51e90740114c60620c0febffd4d3ce6e280a107ab if (m == (token_t *)0) {
d51e90740114c60620c0febffd4d3ce6e280a107ab if (*d == NULL)
d51e90740114c60620c0febffd4d3ce6e280a107ab * Close an audit descriptor.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Use the second parameter to indicate if it should be written or not.
d51e90740114c60620c0febffd4d3ce6e280a107abau_close(au_kcontext_t *kctx, caddr_t *d, int flag, short e_type, short e_mod)
d51e90740114c60620c0febffd4d3ce6e280a107ab token_t *dchain; /* au_membuf chain which is the tokens */
d51e90740114c60620c0febffd4d3ce6e280a107ab * If async then defer; or if requested, defer the closing/queueing to
d51e90740114c60620c0febffd4d3ce6e280a107ab * syscall end, unless no syscall is active or the syscall is _exit.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Defer closing/queueing of an audit descriptor. For async events, queue
d51e90740114c60620c0febffd4d3ce6e280a107ab * via softcall. Otherwise, defer by queueing the record onto the tad; at
d51e90740114c60620c0febffd4d3ce6e280a107ab * syscall end time it will be pulled off.
d51e90740114c60620c0febffd4d3ce6e280a107abau_close_defer(token_t *dchain, int flag, short e_type, short e_mod)
d51e90740114c60620c0febffd4d3ce6e280a107ab /* If not to be written, toss the record. */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* If no mem available, failing silently is the best recourse */
d51e90740114c60620c0febffd4d3ce6e280a107ab * All async events must be queued via softcall to avoid possible
d51e90740114c60620c0febffd4d3ce6e280a107ab * sleeping in high interrupt context. softcall will ensure it's
d51e90740114c60620c0febffd4d3ce6e280a107ab * done on a dedicated software-level interrupt thread.
d51e90740114c60620c0febffd4d3ce6e280a107ab * If not an async event, defer by queuing onto the tad until
d51e90740114c60620c0febffd4d3ce6e280a107ab * syscall end. No locking is needed because the tad is per-thread.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Save the time in the event header. If time is not specified (i.e., pointer
d51e90740114c60620c0febffd4d3ce6e280a107ab * is NULL), use the current time. This code is fairly ugly since it needs
d51e90740114c60620c0febffd4d3ce6e280a107ab * to support both 32- and 64-bit environments and can be called indirectly
d51e90740114c60620c0febffd4d3ce6e280a107ab * from both au_close() (for kernel audit) and from audit() (userland audit).
b93b7f88faf1df7e4a0046bc3fa6f74516688d16jj/*ARGSUSED*/
b93b7f88faf1df7e4a0046bc3fa6f74516688d16jjstatic void
d51e90740114c60620c0febffd4d3ce6e280a107ab * Close an audit descriptor.
d51e90740114c60620c0febffd4d3ce6e280a107ab * If time of event is specified, use it in the record, otherwise use the
d51e90740114c60620c0febffd4d3ce6e280a107ab * current time.
d51e90740114c60620c0febffd4d3ce6e280a107abau_close_time(au_kcontext_t *kctx, token_t *dchain, int flag, short e_type,
d51e90740114c60620c0febffd4d3ce6e280a107ab /* If not to be written, toss the record */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* if auditing not enabled, then don't generate an audit record */
d51e90740114c60620c0febffd4d3ce6e280a107ab * at system boot, neither is set yet we want to generate
d51e90740114c60620c0febffd4d3ce6e280a107ab * an audit record.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* Count up the bytes used in the record. */
d51e90740114c60620c0febffd4d3ce6e280a107ab * add in size of header token (always present).
d51e90740114c60620c0febffd4d3ce6e280a107ab sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t);
22872efb9462b28180d11ea401344608e641a5aaedp * add in size of zonename token (zero if !AUDIT_ZONENAME)
d51e90740114c60620c0febffd4d3ce6e280a107ab /* add in size of (optional) trailer token */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* add in size of (optional) sequence token */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* build the header */
d51e90740114c60620c0febffd4d3ce6e280a107ab * If timestamp was specified, save it in header now. Otherwise,
d51e90740114c60620c0febffd4d3ce6e280a107ab * save reference to header so we can update time/data later
d51e90740114c60620c0febffd4d3ce6e280a107ab * and artificially adjust pointer to the time/date field of header.
d51e90740114c60620c0febffd4d3ce6e280a107ab sizeof (char) + 2 * sizeof (short);
d51e90740114c60620c0febffd4d3ce6e280a107ab /* append body of audit record */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* add (optional) zonename token */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* Add an (optional) sequence token. NULL offset if none */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* get the sequence token */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* link to audit record (i.e. don't pack the data) */
d51e90740114c60620c0febffd4d3ce6e280a107ab * advance to count field of sequence token by skipping
d51e90740114c60620c0febffd4d3ce6e280a107ab * the token type byte.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* add (optional) trailer token */
d51e90740114c60620c0febffd4d3ce6e280a107ab * 1 - use 64 bit version of audit tokens for 64 bit kernels.
d51e90740114c60620c0febffd4d3ce6e280a107ab * 0 - use 32 bit version of audit tokens for 32 bit kernels.
d51e90740114c60620c0febffd4d3ce6e280a107ab au_enqueue(kctx, record, &hadr, &sadr, 1, flag & AU_DONTBLOCK);
d51e90740114c60620c0febffd4d3ce6e280a107ab au_enqueue(kctx, record, &hadr, &sadr, 0, flag & AU_DONTBLOCK);
d51e90740114c60620c0febffd4d3ce6e280a107ab/*ARGSUSED*/
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowiczau_enqueue(au_kcontext_t *kctx, au_buff_t *m, adr_t *hadrp, adr_t *sadrp,
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz if (!dontblock && (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) &&
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* Fill in date and time if needed */
de1f518f033a642fe7aa3c2b59429241a01e387fRichard Lowe /* address will be non-zero only if AUDIT_SEQ set */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* count # audit records put onto kernel audit queue */
d51e90740114c60620c0febffd4d3ce6e280a107ab * Dequeue and free buffers upto and including "freeto"
d51e90740114c60620c0febffd4d3ce6e280a107ab * Keeps the queue lock long but acquires it only once when doing
d51e90740114c60620c0febffd4d3ce6e280a107ab * bulk dequeueing.
d51e90740114c60620c0febffd4d3ce6e280a107abstatic void
d51e90740114c60620c0febffd4d3ce6e280a107ab int n = 0;
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* Freeto must exist in the list */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz if (kctx->auk_queue.cnt <= kctx->auk_queue.lowater &&
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz cv_broadcast(&(kctx->auk_queue.write_cv));
d51e90740114c60620c0febffd4d3ce6e280a107ab * audit_sync_block()
b93b7f88faf1df7e4a0046bc3fa6f74516688d16jj * If we've reached the high water mark, we look at the policy to see
d51e90740114c60620c0febffd4d3ce6e280a107ab * if we sleep or we should drop the audit record.
d51e90740114c60620c0febffd4d3ce6e280a107ab * This function is called with the auk_queue.lock held and the check
d51e90740114c60620c0febffd4d3ce6e280a107ab * performed one time already as an optimization. Caller should unlock.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Returns 1 if the caller needs to free the record.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Loop while we are at the high watermark.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* just count # of dropped audit records */
d51e90740114c60620c0febffd4d3ce6e280a107ab return (1);
d51e90740114c60620c0febffd4d3ce6e280a107ab /* kick reader awake if its asleep */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* keep count of # times blocked */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* sleep now, until woken by reader */
d51e90740114c60620c0febffd4d3ce6e280a107ab cv_wait(&(kctx->auk_queue.write_cv), &(kctx->auk_queue.lock));
d51e90740114c60620c0febffd4d3ce6e280a107ab } while (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater);
d51e90740114c60620c0febffd4d3ce6e280a107ab return (0);
d51e90740114c60620c0febffd4d3ce6e280a107ab * audit_async_block()
d51e90740114c60620c0febffd4d3ce6e280a107ab * if we've reached the high water mark, we look at the ahlt policy to see
d51e90740114c60620c0febffd4d3ce6e280a107ab * if we reboot we should drop the audit record.
d51e90740114c60620c0febffd4d3ce6e280a107ab * Returns 1 if blocked.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* see if we've reached high water mark */
d51e90740114c60620c0febffd4d3ce6e280a107ab return (1);
d51e90740114c60620c0febffd4d3ce6e280a107ab return (0);
d51e90740114c60620c0febffd4d3ce6e280a107ab * au_door_upcall. auditdoor() may change vp without notice, so
d51e90740114c60620c0febffd4d3ce6e280a107ab * some locking seems in order.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* non-zero means return results expected */
d51e90740114c60620c0febffd4d3ce6e280a107ab if ((rc = door_upcall(kctx->auk_current_vp, &darg)) != 0) {
d51e90740114c60620c0febffd4d3ce6e280a107ab return (rc);
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz } /* end while (retry == 1) */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* return code from door server */
d51e90740114c60620c0febffd4d3ce6e280a107ab * Write an audit control message to the door handle. The message
d51e90740114c60620c0febffd4d3ce6e280a107ab * structure depends on message_code and at present the only control
d51e90740114c60620c0febffd4d3ce6e280a107ab * message defined is for a policy change. These are infrequent,
d51e90740114c60620c0febffd4d3ce6e280a107ab * so no memory is held for control messages.
d51e90740114c60620c0febffd4d3ce6e280a107abau_doormsg(au_kcontext_t *kctx, uint32_t message_code, void *message)
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz *(uint32_t *)buf->aub_buf = *(uint32_t *)message;
d51e90740114c60620c0febffd4d3ce6e280a107ab return (1);
d51e90740114c60620c0febffd4d3ce6e280a107ab return (rc);
d51e90740114c60620c0febffd4d3ce6e280a107ab * Write audit information to the door handle. au_doorio is called with
d51e90740114c60620c0febffd4d3ce6e280a107ab * one or more complete audit records on the queue and outputs those
d51e90740114c60620c0febffd4d3ce6e280a107ab * records in buffers of up to auk_queue.buflen in size.
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz unsigned char *cp; /* ptr to data to be moved */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * size (data left in au_membuf - space in buffer)
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz ssize_t len; /* len of data to move, size of AR */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz ssize_t curr_sz = 0; /* amount of data written during now */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz int part = 0; /* partial audit record written */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * Has the write buffer changed length due to a auditctl(2)?
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * Initial allocation is from audit_start.c/audit_init()
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) {
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz kmem_free(kctx->auk_dbuffer, AU_DBUF_HEADER +
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz kctx->auk_dbuffer = kmem_alloc(AU_DBUF_HEADER +
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* omit the 64 bit header */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz kctx->auk_queue.buflen = kctx->auk_queue.bufsz;
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz used = 0; /* no data processed in au_membuf */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz cAR = kctx->auk_queue.head; /* start at head of queue */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz cMB = cAR; /* start with first au_membuf of record */
beee6fc0eea41662170c4dea38a7e5605ab59507Bryan Cantrill /* start at beginning of buffer */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz part = 1; /* indicate audit record being processed */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz cp = memtod(cMB, unsigned char *); /* buffer ptr */
beee6fc0eea41662170c4dea38a7e5605ab59507Bryan Cantrill sz = (ssize_t)cMB->len - used; /* data left in au_membuf */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* len to move */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off);
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* move the data */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz off += len; /* update offset into buffer */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* advance to next au_membuf */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* advance to next audit record */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz if ((kctx->auk_queue.buflen == off) || (part == 0)) {
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz partial_state = state_if_part[partial_state];
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz kctx->auk_dbuffer->aub_type = partial_state;
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * if we've successfully written an audit record,
d51e90740114c60620c0febffd4d3ce6e280a107ab * free records up to last full record copied
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* Update size */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz /* reset auk_dbuffer pointers */
d51e90740114c60620c0febffd4d3ce6e280a107ab } /* while(cMB) */
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * Clean up thread audit state to clear out asynchronous audit record
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * generation error recovery processing. Note that this is done on a
d9452f237f843c1321abb5810d2f9ee6cbeae43cEdward Pilatowicz * per-thread basis and thus does not need any locking.
d51e90740114c60620c0febffd4d3ce6e280a107ab /* clean up the tad unless called from softcall backend */
d51e90740114c60620c0febffd4d3ce6e280a107ab /* clean out partial audit record */
sync();
sync();