1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/param.h>
26 #include <sys/types.h>
27 #include <sys/kmem.h>
28 #include <sys/t_lock.h>
29 #include <sys/thread.h>
30 #include <sys/systm.h>
31 #include <c2/audit.h>
32 #include <c2/audit_kernel.h>
33 #include <c2/audit_record.h>
34
35 static kmem_cache_t *au_buf_cache;
36
37 /*
38 * au_buff_t and token_t are equivalent (see audit_record.h). Don't
39 * confuse this token_t with the one that is defined for userspace
40 * in the same header file.
41 */
42
43 /*
44 * Function: au_get_buff
45 * args:
46 */
47 struct au_buff *
au_get_buff(void)48 au_get_buff(void)
49 {
50 au_buff_t *buffer;
51 t_audit_data_t *tad = U2A(u);
52
53 ASSERT(tad);
54
55 /*
56 * If asynchronous (interrupt) thread, then we can't sleep
57 * (the tad ERRJMP flag is set at the start of async processing).
58 */
59 if (tad->tad_ctrl & TAD_ERRJMP) {
60 buffer = kmem_cache_alloc(au_buf_cache, KM_NOSLEEP);
61 if (buffer == NULL) {
62 /* return to top of stack & report an error */
63 ASSERT(tad->tad_errjmp);
64 longjmp(tad->tad_errjmp);
65 }
66 } else {
67 buffer = kmem_cache_alloc(au_buf_cache, KM_SLEEP);
68 }
69 /* Never gets here when buffer == NULL */
70 bzero(buffer, sizeof (*buffer));
71 return (buffer);
72 }
73
74 /*
75 * Function: au_free_rec
76 * args:
77 * au_buff_t *buf; start of the record chain
78 */
79 void
au_free_rec(au_buff_t * buf)80 au_free_rec(au_buff_t *buf)
81 {
82 au_buff_t *next;
83 t_audit_data_t *tad = U2A(u);
84
85 ASSERT(tad);
86
87 /*
88 * If asynchronous (interrupt) thread, schedule the release
89 * (the tad ERRJMP flag is set at the start of async processing).
90 */
91 if (tad->tad_ctrl & TAD_ERRJMP) {
92 /* Discard async events via softcall. */
93 softcall(audit_async_discard_backend, buf);
94 }
95
96 while (buf != NULL) {
97 next = buf->next_buf;
98 kmem_cache_free(au_buf_cache, buf);
99 buf = next;
100 }
101 }
102
103 /*
104 * Backend routine to discard an async event. Invoked from softcall.
105 * (Note: the freeing of memory for the event can't be done safely in high
106 * interrupt context due to the chance of sleeping on an adaptive mutex.
107 * Hence the softcall.)
108 */
109 void
audit_async_discard_backend(void * addr)110 audit_async_discard_backend(void *addr)
111 {
112 au_toss_token(addr);
113 }
114
115 /*
116 * Function: au_append_rec
117 * args:
118 * au_buff_t *rec; start of the record chain
119 * au_buff_t *buf; buffer to append
120 * int pack; AU_PACK/1 - pack data, AU_LINK/0 - link buffer
121 */
122 int
au_append_rec(au_buff_t * rec,au_buff_t * buf,int pack)123 au_append_rec(au_buff_t *rec, au_buff_t *buf, int pack)
124 {
125 if (!rec)
126 return (-1);
127
128 while (rec->next_buf)
129 rec = rec->next_buf;
130 if (((int)(rec->len + buf->len) <= AU_BUFSIZE) && pack) {
131 bcopy(buf->buf, (char *)(rec->buf + rec->len),
132 (uint_t)buf->len);
133 rec->len += buf->len;
134 rec->next_buf = buf->next_buf;
135 kmem_cache_free(au_buf_cache, buf);
136 } else {
137 rec->next_buf = buf;
138 }
139 return (0);
140 }
141
142 /*
143 * Function: au_append_buf
144 * args:
145 * char *data; data buffer to append
146 * int len; size of data to append
147 * au_buff_t *buf; buffer to append to
148 */
149 int
au_append_buf(const char * data,int len,au_buff_t * buf)150 au_append_buf(const char *data, int len, au_buff_t *buf)
151 {
152 au_buff_t *new_buf;
153 int new_len;
154
155 while (buf->next_buf != NULL)
156 buf = buf->next_buf;
157
158 new_len = (uint_t)(buf->len + len) > AU_BUFSIZE ?
159 AU_BUFSIZE - buf->len : len;
160 bcopy(data, (buf->buf + buf->len), (uint_t)new_len);
161 buf->len += (uchar_t)new_len;
162 len -= new_len;
163
164 while (len > 0) {
165 data += new_len;
166 if ((new_buf = au_get_buff()) == NULL) {
167 return (-1);
168 }
169 buf->next_buf = new_buf;
170 buf = new_buf;
171 new_len = len > AU_BUFSIZE ? AU_BUFSIZE : len;
172 bcopy(data, buf->buf, (uint_t)new_len);
173 buf->len = (uchar_t)new_len;
174 len -= new_len;
175 }
176 return (0);
177 }
178
179 void
au_mem_init()180 au_mem_init()
181 {
182 au_buf_cache = kmem_cache_create("audit_buffer",
183 sizeof (au_buff_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
184 }
185