4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Routines for writing audit records.
30 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/statvfs.h> /* for statfs */
34 #include <sys/vnode.h>
39 #include <sys/reboot.h>
40 #include <sys/kmem.h> /* for KM_SLEEP */
41 #include <sys/resource.h> /* for RLIM_INFINITY */
42 #include <sys/cmn_err.h> /* panic */
43 #include <sys/systm.h>
44 #include <sys/debug.h>
45 #include <sys/sysmacros.h>
46 #include <sys/syscall.h>
50 #include <c2/audit_kernel.h>
51 #include <c2/audit_record.h>
52 #include <c2/audit_kevents.h>
53 #include <c2/audit_door_infc.h>
55 static void au_dequeue(au_kcontext_t
*, au_buff_t
*);
56 static void audit_async_finish_backend(void *);
57 static int audit_sync_block(au_kcontext_t
*);
59 * each of these two tables are indexed by the values AU_DBUF_COMPLETE
60 * through AU_DBUF_LAST; the content is the next state value. The
61 * first table determines the next state for a buffer which is not the
62 * end of a record and the second table determines the state for a
63 * buffer which is the end of a record. The initial state is
66 static int state_if_part
[] = {
67 AU_DBUF_FIRST
, AU_DBUF_MIDDLE
, AU_DBUF_MIDDLE
, AU_DBUF_FIRST
};
68 static int state_if_not_part
[] = {
69 AU_DBUF_COMPLETE
, AU_DBUF_LAST
, AU_DBUF_LAST
, AU_DBUF_COMPLETE
};
71 * Write to an audit descriptor.
72 * Add the au_membuf to the descriptor chain and free the chain passed in.
82 au_write(caddr_t
*d
, token_t
*m
)
88 if (m
== (token_t
*)0) {
89 printf("au_write: null token\n");
96 (void) au_append_rec((au_buff_t
*)*d
, m
, AU_PACK
);
100 * Close an audit descriptor.
101 * Use the second parameter to indicate if it should be written or not.
104 au_close(au_kcontext_t
*kctx
, caddr_t
*d
, int flag
, au_event_t e_type
,
105 au_emod_t e_mod
, timestruc_t
*e_time
)
107 token_t
*dchain
; /* au_membuf chain which is the tokens */
108 t_audit_data_t
*tad
= U2A(u
);
112 ASSERT(kctx
!= NULL
);
114 if ((dchain
= (token_t
*)*d
) == (token_t
*)NULL
)
120 * If async then defer; or if requested, defer the closing/queueing to
121 * syscall end, unless no syscall is active or the syscall is _exit.
123 if ((flag
& AU_DONTBLOCK
) || ((flag
& AU_DEFER
) &&
124 (tad
->tad_scid
!= 0) && (tad
->tad_scid
!= SYS_exit
))) {
125 au_close_defer(dchain
, flag
, e_type
, e_mod
, e_time
);
128 au_close_time(kctx
, dchain
, flag
, e_type
, e_mod
, e_time
);
132 * Defer closing/queueing of an audit descriptor. For async events, queue
133 * via softcall. Otherwise, defer by queueing the record onto the tad; at
134 * syscall end time it will be pulled off.
137 au_close_defer(token_t
*dchain
, int flag
, au_event_t e_type
, au_emod_t e_mod
,
140 au_defer_info_t
*attr
;
141 t_audit_data_t
*tad
= U2A(u
);
145 /* If not to be written, toss the record. */
146 if ((flag
& AU_OK
) == 0) {
147 au_toss_token(dchain
);
151 attr
= kmem_alloc(sizeof (au_defer_info_t
), KM_NOSLEEP
);
152 /* If no mem available, failing silently is the best recourse */
154 au_toss_token(dchain
);
158 attr
->audi_next
= NULL
;
159 attr
->audi_ad
= dchain
;
160 attr
->audi_e_type
= e_type
;
161 attr
->audi_e_mod
= e_mod
;
162 attr
->audi_flag
= flag
;
164 attr
->audi_atime
= *e_time
;
166 gethrestime(&attr
->audi_atime
);
169 * All async events must be queued via softcall to avoid possible
170 * sleeping in high interrupt context. softcall will ensure it's
171 * done on a dedicated software-level interrupt thread.
173 if (flag
& AU_DONTBLOCK
) {
174 softcall(audit_async_finish_backend
, attr
);
175 audit_async_done(NULL
, 0);
180 * If not an async event, defer by queuing onto the tad until
181 * syscall end. No locking is needed because the tad is per-thread.
183 if (tad
->tad_defer_head
)
184 tad
->tad_defer_tail
->audi_next
= attr
;
186 tad
->tad_defer_head
= attr
;
187 tad
->tad_defer_tail
= attr
;
192 * Save the time in the event header. If time is not specified (i.e., pointer
193 * is NULL), use the current time. This code is fairly ugly since it needs
194 * to support both 32- and 64-bit environments and can be called indirectly
195 * from both au_close() (for kernel audit) and from audit() (userland audit).
199 au_save_time(adr_t
*hadrp
, timestruc_t
*time
, int size
)
214 adr_int64(hadrp
, (int64_t *)time
, 2);
218 tv
.sec
= (uint32_t)time
->tv_sec
;
219 tv
.usec
= (uint32_t)time
->tv_nsec
;
220 adr_int32(hadrp
, (int32_t *)&tv
, 2);
226 * Close an audit descriptor.
227 * If time of event is specified, use it in the record, otherwise use the
231 au_close_time(au_kcontext_t
*kctx
, token_t
*dchain
, int flag
, au_event_t e_type
,
232 au_emod_t e_mod
, timestruc_t
*etime
)
234 token_t
*record
; /* au_membuf chain == the record */
236 token_t
*m
; /* for potential sequence token */
237 adr_t hadr
; /* handle for header token */
238 adr_t sadr
; /* handle for sequence token */
239 size_t zone_length
; /* length of zonename token */
242 ASSERT(dchain
!= NULL
);
244 /* If not to be written, toss the record */
245 if ((flag
& AU_OK
) == 0) {
246 au_toss_token(dchain
);
249 /* if auditing not enabled, then don't generate an audit record */
250 ASSERT(U2A(u
) != NULL
);
251 ASSERT(kctx
!= NULL
);
253 auditing
= (U2A(u
)->tad_audit
== AUC_UNSET
)
254 ? kctx
->auk_auditstate
257 if (auditing
& ~(AUC_AUDITING
| AUC_INIT_AUDIT
)) {
259 * at system boot, neither is set yet we want to generate
262 if (e_type
!= AUE_SYSTEMBOOT
) {
263 au_toss_token(dchain
);
268 /* Count up the bytes used in the record. */
269 byte_count
= au_token_size(dchain
);
272 * add in size of header token (always present).
274 byte_count
+= sizeof (char) + sizeof (int32_t) +
275 sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t
);
277 if (kctx
->auk_hostaddr_valid
)
278 byte_count
+= sizeof (int32_t) +
279 kctx
->auk_info
.ai_termid
.at_type
;
282 * add in size of zonename token (zero if !AUDIT_ZONENAME)
284 if (kctx
->auk_policy
& AUDIT_ZONENAME
) {
285 zone_length
= au_zonename_length(NULL
);
286 byte_count
+= zone_length
;
290 /* add in size of (optional) trailer token */
291 if (kctx
->auk_policy
& AUDIT_TRAIL
)
294 /* add in size of (optional) sequence token */
295 if (kctx
->auk_policy
& AUDIT_SEQ
)
298 /* build the header */
299 if (kctx
->auk_hostaddr_valid
)
300 record
= au_to_header_ex(byte_count
, e_type
, e_mod
);
302 record
= au_to_header(byte_count
, e_type
, e_mod
);
305 * If timestamp was specified, save it in header now. Otherwise,
306 * save reference to header so we can update time/data later
307 * and artificially adjust pointer to the time/date field of header.
309 adr_start(&hadr
, memtod(record
, char *));
310 hadr
.adr_now
+= sizeof (char) + sizeof (int32_t) +
311 sizeof (char) + 2 * sizeof (short);
312 if (kctx
->auk_hostaddr_valid
)
313 hadr
.adr_now
+= sizeof (int32_t) +
314 kctx
->auk_info
.ai_termid
.at_type
;
316 au_save_time(&hadr
, etime
, 1);
317 hadr
.adr_now
= (char *)NULL
;
320 /* append body of audit record */
321 (void) au_append_rec(record
, dchain
, AU_PACK
);
323 /* add (optional) zonename token */
324 if (zone_length
> 0) {
325 m
= au_to_zonename(zone_length
, NULL
);
326 (void) au_append_rec(record
, m
, AU_PACK
);
329 /* Add an (optional) sequence token. NULL offset if none */
330 if (kctx
->auk_policy
& AUDIT_SEQ
) {
331 /* get the sequence token */
334 /* link to audit record (i.e. don't pack the data) */
335 (void) au_append_rec(record
, m
, AU_LINK
);
338 * advance to count field of sequence token by skipping
339 * the token type byte.
341 adr_start(&sadr
, memtod(m
, char *));
346 /* add (optional) trailer token */
347 if (kctx
->auk_policy
& AUDIT_TRAIL
) {
348 (void) au_append_rec(record
, au_to_trailer(byte_count
),
353 * 1 - use 64 bit version of audit tokens for 64 bit kernels.
354 * 0 - use 32 bit version of audit tokens for 32 bit kernels.
357 au_enqueue(kctx
, record
, &hadr
, &sadr
, 1, flag
& AU_DONTBLOCK
);
359 au_enqueue(kctx
, record
, &hadr
, &sadr
, 0, flag
& AU_DONTBLOCK
);
361 AS_INC(as_totalsize
, byte_count
, kctx
);
366 au_enqueue(au_kcontext_t
*kctx
, au_buff_t
*m
, adr_t
*hadrp
, adr_t
*sadrp
,
367 int size
, int dontblock
)
372 mutex_enter(&(kctx
->auk_queue
.lock
));
374 if (!dontblock
&& (kctx
->auk_queue
.cnt
>= kctx
->auk_queue
.hiwater
) &&
375 audit_sync_block(kctx
)) {
376 mutex_exit(&(kctx
->auk_queue
.lock
));
381 /* Fill in date and time if needed */
382 if (hadrp
->adr_now
) {
383 au_save_time(hadrp
, NULL
, size
);
386 /* address will be non-zero only if AUDIT_SEQ set */
387 if (sadrp
->adr_now
) {
388 kctx
->auk_sequence
++;
389 adr_int32(sadrp
, (int32_t *)&(kctx
->auk_sequence
), 1);
392 if (kctx
->auk_queue
.head
)
393 kctx
->auk_queue
.tail
->next_rec
= m
;
395 kctx
->auk_queue
.head
= m
;
397 kctx
->auk_queue
.tail
= m
;
399 if (++(kctx
->auk_queue
.cnt
) >
400 kctx
->auk_queue
.lowater
&& kctx
->auk_queue
.rd_block
)
401 cv_broadcast(&(kctx
->auk_queue
.read_cv
));
403 mutex_exit(&(kctx
->auk_queue
.lock
));
405 /* count # audit records put onto kernel audit queue */
406 AS_INC(as_enqueue
, 1, kctx
);
410 * Dequeue and free buffers upto and including "freeto"
411 * Keeps the queue lock long but acquires it only once when doing
415 au_dequeue(au_kcontext_t
*kctx
, au_buff_t
*freeto
)
417 au_buff_t
*m
, *l
, *lastl
;
420 ASSERT(kctx
!= NULL
);
422 mutex_enter(&(kctx
->auk_queue
.lock
));
424 ASSERT(kctx
->auk_queue
.head
!= NULL
);
425 ASSERT(freeto
!= NULL
);
427 l
= m
= kctx
->auk_queue
.head
;
433 } while (l
!= NULL
&& freeto
!= lastl
);
435 kctx
->auk_queue
.cnt
-= n
;
436 lastl
->next_rec
= NULL
;
437 kctx
->auk_queue
.head
= l
;
439 /* Freeto must exist in the list */
440 ASSERT(freeto
== lastl
);
442 if (kctx
->auk_queue
.cnt
<= kctx
->auk_queue
.lowater
&&
443 kctx
->auk_queue
.wt_block
)
444 cv_broadcast(&(kctx
->auk_queue
.write_cv
));
446 mutex_exit(&(kctx
->auk_queue
.lock
));
453 AS_INC(as_written
, n
, kctx
);
458 * If we've reached the high water mark, we look at the policy to see
459 * if we sleep or we should drop the audit record.
460 * This function is called with the auk_queue.lock held and the check
461 * performed one time already as an optimization. Caller should unlock.
462 * Returns 1 if the caller needs to free the record.
465 audit_sync_block(au_kcontext_t
*kctx
)
467 ASSERT(MUTEX_HELD(&(kctx
->auk_queue
.lock
)));
469 * Loop while we are at the high watermark.
472 if (((U2A(u
)->tad_audit
!= AUC_UNSET
)
473 ? (U2A(u
)->tad_audit
!= AUC_AUDITING
)
474 : (kctx
->auk_auditstate
!= AUC_AUDITING
)) ||
475 (kctx
->auk_policy
& AUDIT_CNT
)) {
477 /* just count # of dropped audit records */
478 AS_INC(as_dropped
, 1, kctx
);
483 /* kick reader awake if its asleep */
484 if (kctx
->auk_queue
.rd_block
&&
485 kctx
->auk_queue
.cnt
> kctx
->auk_queue
.lowater
)
486 cv_broadcast(&(kctx
->auk_queue
.read_cv
));
488 /* keep count of # times blocked */
489 AS_INC(as_wblocked
, 1, kctx
);
491 /* sleep now, until woken by reader */
492 kctx
->auk_queue
.wt_block
++;
493 cv_wait(&(kctx
->auk_queue
.write_cv
), &(kctx
->auk_queue
.lock
));
494 kctx
->auk_queue
.wt_block
--;
495 } while (kctx
->auk_queue
.cnt
>= kctx
->auk_queue
.hiwater
);
501 * audit_async_block()
502 * if we've reached the high water mark, we look at the ahlt policy to see
503 * if we reboot we should drop the audit record.
504 * Returns 1 if blocked.
507 audit_async_block(au_kcontext_t
*kctx
, caddr_t
*rpp
)
509 ASSERT(kctx
!= NULL
);
511 mutex_enter(&(kctx
->auk_queue
.lock
));
512 /* see if we've reached high water mark */
513 if (kctx
->auk_queue
.cnt
>= kctx
->auk_queue
.hiwater
) {
514 mutex_exit(&(kctx
->auk_queue
.lock
));
516 audit_async_drop(rpp
, AU_BACKEND
);
519 mutex_exit(&(kctx
->auk_queue
.lock
));
524 * au_door_upcall. auditdoor() may change vp without notice, so
525 * some locking seems in order.
528 #define AGAIN_TICKS 10
531 au_door_upcall(au_kcontext_t
*kctx
, au_dbuf_t
*aubuf
)
538 darg
.data_ptr
= (char *)aubuf
;
539 darg
.data_size
= AU_DBUF_HEADER
+ aubuf
->aub_size
;
541 darg
.desc_ptr
= NULL
;
545 /* non-zero means return results expected */
546 darg
.rbuf
= (char *)aubuf
;
547 darg
.rsize
= darg
.data_size
;
550 mutex_enter(&(kctx
->auk_svc_lock
));
551 rc
= door_upcall(kctx
->auk_current_vp
, &darg
, NULL
,
554 mutex_exit(&(kctx
->auk_svc_lock
));
556 ticks_to_wait
= AGAIN_TICKS
;
560 mutex_enter(&(kctx
->auk_eagain_mutex
));
561 (void) cv_reltimedwait(&(kctx
->auk_eagain_cv
),
562 &(kctx
->auk_eagain_mutex
), ticks_to_wait
,
564 mutex_exit(&(kctx
->auk_eagain_mutex
));
568 mutex_exit(&(kctx
->auk_svc_lock
)); /* no retry */
569 } /* end while (retry == 1) */
570 if (darg
.rbuf
== NULL
)
573 /* return code from door server */
574 return (*(int *)darg
.rbuf
);
578 * Write an audit control message to the door handle. The message
579 * structure depends on message_code and at present the only control
580 * message defined is for a policy change. These are infrequent,
581 * so no memory is held for control messages.
584 au_doormsg(au_kcontext_t
*kctx
, uint32_t message_code
, void *message
)
590 switch (message_code
) {
592 alloc_size
= AU_DBUF_HEADER
+ sizeof (uint32_t);
593 buf
= kmem_alloc(alloc_size
, KM_SLEEP
);
594 buf
->aub_size
= sizeof (uint32_t);
595 *(uint32_t *)buf
->aub_buf
= *(uint32_t *)message
;
597 case AU_DBUF_SHUTDOWN
:
598 alloc_size
= AU_DBUF_HEADER
;
599 buf
= kmem_alloc(alloc_size
, KM_SLEEP
);
606 buf
->aub_type
= AU_DBUF_NOTIFY
| message_code
;
607 rc
= au_door_upcall(kctx
, buf
);
608 kmem_free(buf
, alloc_size
);
614 * Write audit information to the door handle. au_doorio is called with
615 * one or more complete audit records on the queue and outputs those
616 * records in buffers of up to auk_queue.buflen in size.
619 au_doorio(au_kcontext_t
*kctx
) {
620 off_t off
; /* space used in buffer */
621 ssize_t used
; /* space used in au_membuf */
622 token_t
*cAR
; /* current AR being processed */
623 token_t
*cMB
; /* current au_membuf being processed */
624 token_t
*sp
; /* last AR processed */
625 char *bp
; /* start of free space in staging buffer */
626 unsigned char *cp
; /* ptr to data to be moved */
627 int error
= 0; /* return from door upcall */
630 * size (data left in au_membuf - space in buffer)
633 ssize_t len
; /* len of data to move, size of AR */
634 ssize_t curr_sz
= 0; /* amount of data written during now */
636 * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h
638 int part
= 0; /* partial audit record written */
639 int partial_state
= AU_DBUF_COMPLETE
;
641 * Has the write buffer changed length due to a auditctl(2)?
642 * Initial allocation is from audit_start.c/audit_init()
644 if (kctx
->auk_queue
.bufsz
!= kctx
->auk_queue
.buflen
) {
645 size_t new_sz
= kctx
->auk_queue
.bufsz
;
647 kmem_free(kctx
->auk_dbuffer
, AU_DBUF_HEADER
+
648 kctx
->auk_queue
.buflen
);
650 kctx
->auk_dbuffer
= kmem_alloc(AU_DBUF_HEADER
+ new_sz
,
653 /* omit the 64 bit header */
654 kctx
->auk_queue
.buflen
= new_sz
;
656 if (!kctx
->auk_queue
.head
)
659 sp
= NULL
; /* no record copied */
660 off
= 0; /* no space used in buffer */
661 used
= 0; /* no data processed in au_membuf */
662 cAR
= kctx
->auk_queue
.head
; /* start at head of queue */
663 cMB
= cAR
; /* start with first au_membuf of record */
665 /* start at beginning of buffer */
666 bp
= &(kctx
->auk_dbuffer
->aub_buf
[0]);
669 part
= 1; /* indicate audit record being processed */
671 cp
= memtod(cMB
, unsigned char *); /* buffer ptr */
673 sz
= (ssize_t
)cMB
->len
- used
; /* data left in au_membuf */
675 len
= (ssize_t
)MIN(sz
, kctx
->auk_queue
.buflen
- off
);
678 bcopy(cp
+ used
, bp
+ off
, len
);
679 used
+= len
; /* update used au_membuf */
680 off
+= len
; /* update offset into buffer */
682 if (used
>= (ssize_t
)cMB
->len
) {
683 /* advance to next au_membuf */
688 /* advance to next audit record */
692 part
= 0; /* have a complete record */
695 if ((kctx
->auk_queue
.buflen
== off
) || (part
== 0)) {
697 partial_state
= state_if_part
[partial_state
];
700 state_if_not_part
[partial_state
];
702 kctx
->auk_dbuffer
->aub_type
= partial_state
;
703 kctx
->auk_dbuffer
->aub_size
= off
;
704 error
= au_door_upcall(kctx
, kctx
->auk_dbuffer
);
708 * if we've successfully written an audit record,
709 * free records up to last full record copied
712 au_dequeue(kctx
, sp
);
717 /* reset auk_dbuffer pointers */
727 * Clean up thread audit state to clear out asynchronous audit record
728 * generation error recovery processing. Note that this is done on a
729 * per-thread basis and thus does not need any locking.
732 audit_async_done(caddr_t
*rpp
, int flags
)
734 t_audit_data_t
*tad
= U2A(u
);
736 /* clean up the tad unless called from softcall backend */
737 if (!(flags
& AU_BACKEND
)) {
739 ASSERT(tad
->tad_ctrl
& TAD_ERRJMP
);
741 tad
->tad_ctrl
&= ~TAD_ERRJMP
;
742 tad
->tad_errjmp
= NULL
;
745 /* clean out partial audit record */
746 if ((rpp
!= NULL
) && (*rpp
!= NULL
)) {
747 au_toss_token((au_buff_t
*)*rpp
);
753 * implement the audit policy for asynchronous events generated within
755 * XXX might need locks around audit_policy check.
758 audit_async_drop(caddr_t
*rpp
, int flags
)
762 /* could not generate audit record, clean up */
763 audit_async_done((caddr_t
*)rpp
, flags
);
767 /* just drop the record and return */
768 if (((audit_policy
& AUDIT_AHLT
) == 0) ||
769 (kctx
->auk_auditstate
== AUC_INIT_AUDIT
)) {
770 /* just count # of dropped audit records */
771 AS_INC(as_dropped
, 1, kctx
);
776 * There can be a lot of data in the audit queue. We
777 * will first sync the file systems then attempt to
778 * shutdown the kernel so that a memory dump is
785 * now shut down. What a cruel world it has been
787 panic("non-attributable halt. should dump core");
792 audit_async_start(label_t
*jb
, au_event_t event
, int sorf
)
794 t_audit_data_t
*tad
= U2A(u
);
796 int success
= 0, failure
= 0;
797 au_kcontext_t
*kctx
= GET_KCTX_GZ
;
799 /* if audit state off, then no audit record generation */
800 if ((kctx
->auk_auditstate
!= AUC_AUDITING
) &&
801 (kctx
->auk_auditstate
!= AUC_INIT_AUDIT
))
805 * preselect asynchronous event
806 * XXX should we check for out-of-range???
808 estate
= kctx
->auk_ets
[event
];
811 success
= kctx
->auk_info
.ai_namask
.as_success
& estate
;
813 failure
= kctx
->auk_info
.ai_namask
.as_failure
& estate
;
815 if ((success
| failure
) == NULL
)
818 ASSERT(tad
->tad_errjmp
== NULL
);
819 tad
->tad_errjmp
= (void *)jb
;
820 tad
->tad_ctrl
|= TAD_ERRJMP
;
826 * Complete auditing of an async event. The AU_DONTBLOCK flag to au_close will
827 * result in the backend routine being invoked from softcall, so all the real
828 * work can be done in a safe context.
831 audit_async_finish(caddr_t
*ad
, au_event_t aid
, au_emod_t amod
,
838 au_close(kctx
, ad
, AU_DONTBLOCK
| AU_OK
, aid
, PAD_NONATTR
|amod
, e_time
);
842 * Backend routine to complete an async audit. Invoked from softcall.
843 * (Note: the blocking and the queuing below both involve locking which can't
844 * be done safely in high interrupt context due to the chance of sleeping on
845 * the corresponding adaptive mutex. Hence the softcall.)
848 audit_async_finish_backend(void *addr
)
851 au_defer_info_t
*attr
= (au_defer_info_t
*)addr
;
854 return; /* won't happen unless softcall is broken */
858 if (audit_async_block(kctx
, (caddr_t
*)&attr
->audi_ad
)) {
859 kmem_free(attr
, sizeof (au_defer_info_t
));
864 * Call au_close_time to complete the audit with the saved values.
866 * For the exit-prom event, use the current time instead of the
867 * saved time as a better approximation. (Because the time saved via
868 * gethrestime during prom-exit handling would not yet be caught up
869 * after the system was idled in the debugger for a period of time.)
871 if (attr
->audi_e_type
== AUE_EXITPROM
) {
872 au_close_time(kctx
, (token_t
*)attr
->audi_ad
, attr
->audi_flag
,
873 attr
->audi_e_type
, attr
->audi_e_mod
, NULL
);
875 au_close_time(kctx
, (token_t
*)attr
->audi_ad
, attr
->audi_flag
,
876 attr
->audi_e_type
, attr
->audi_e_mod
, &attr
->audi_atime
);
879 AS_INC(as_generated
, 1, kctx
);
880 AS_INC(as_nonattrib
, 1, kctx
);
882 kmem_free(attr
, sizeof (au_defer_info_t
));