Deleted Added
full compact
audit_worker.c (159332) audit_worker.c (162380)
1/*
2 * Copyright (c) 1999-2005 Apple Computer, Inc.
3 * Copyright (c) 2006 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
1/*
2 * Copyright (c) 1999-2005 Apple Computer, Inc.
3 * Copyright (c) 2006 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: head/sys/security/audit/audit_worker.c 159332 2006-06-06 08:43:27Z rwatson $
30 * $FreeBSD: head/sys/security/audit/audit_worker.c 162380 2006-09-17 17:52:57Z csjp $
31 */
32
33#include <sys/param.h>
34#include <sys/condvar.h>
35#include <sys/conf.h>
36#include <sys/file.h>
37#include <sys/filedesc.h>
38#include <sys/fcntl.h>
39#include <sys/ipc.h>
40#include <sys/kernel.h>
41#include <sys/kthread.h>
42#include <sys/malloc.h>
43#include <sys/mount.h>
44#include <sys/namei.h>
45#include <sys/proc.h>
46#include <sys/queue.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49#include <sys/protosw.h>
50#include <sys/domain.h>
51#include <sys/sysproto.h>
52#include <sys/sysent.h>
53#include <sys/systm.h>
54#include <sys/ucred.h>
55#include <sys/uio.h>
56#include <sys/un.h>
57#include <sys/unistd.h>
58#include <sys/vnode.h>
59
60#include <bsm/audit.h>
61#include <bsm/audit_internal.h>
62#include <bsm/audit_kevents.h>
63
64#include <netinet/in.h>
65#include <netinet/in_pcb.h>
66
67#include <security/audit/audit.h>
68#include <security/audit/audit_private.h>
69
70#include <vm/uma.h>
71
72/*
73 * Worker thread that will schedule disk I/O, etc.
74 */
75static struct proc *audit_thread;
76
77/*
78 * When an audit log is rotated, the actual rotation must be performed by the
79 * audit worker thread, as it may have outstanding writes on the current
80 * audit log. audit_replacement_vp holds the vnode replacing the current
81 * vnode. We can't let more than one replacement occur at a time, so if more
82 * than one thread requests a replacement, only one can have the replacement
83 * "in progress" at any given moment. If a thread tries to replace the audit
84 * vnode and discovers a replacement is already in progress (i.e.,
85 * audit_replacement_flag != 0), then it will sleep on audit_replacement_cv
86 * waiting its turn to perform a replacement. When a replacement is
87 * completed, this cv is signalled by the worker thread so a waiting thread
88 * can start another replacement. We also store a credential to perform
89 * audit log write operations with.
90 *
91 * The current credential and vnode are thread-local to audit_worker.
92 */
93static struct cv audit_replacement_cv;
94
95static int audit_replacement_flag;
96static struct vnode *audit_replacement_vp;
97static struct ucred *audit_replacement_cred;
98
99/*
100 * Flags related to Kernel->user-space communication.
101 */
102static int audit_file_rotate_wait;
103
104/*
105 * XXXAUDIT: Should adjust comments below to make it clear that we get to
106 * this point only if we believe we have storage, so not having space here is
107 * a violation of invariants derived from administrative procedures. I.e.,
108 * someone else has written to the audit partition, leaving less space than
109 * we accounted for.
110 */
111static int
112audit_record_write(struct vnode *vp, struct ucred *cred, struct thread *td,
113 void *data, size_t len)
114{
115 int ret;
116 long temp;
117 struct vattr vattr;
118 struct statfs *mnt_stat;
119 int vfslocked;
120
121 if (vp == NULL)
122 return (0);
123
124 mnt_stat = &vp->v_mount->mnt_stat;
125 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
126
127 /*
128 * First, gather statistics on the audit log file and file system so
129 * that we know how we're doing on space. In both cases, if we're
130 * unable to perform the operation, we drop the record and return.
131 * However, this is arguably an assertion failure.
132 * XXX Need a FreeBSD equivalent.
133 */
134 ret = VFS_STATFS(vp->v_mount, mnt_stat, td);
135 if (ret)
136 goto out;
137
138 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
139 ret = VOP_GETATTR(vp, &vattr, cred, td);
140 VOP_UNLOCK(vp, 0, td);
141 if (ret)
142 goto out;
143
144 /* update the global stats struct */
145 audit_fstat.af_currsz = vattr.va_size;
146
147 /*
148 * XXX Need to decide what to do if the trigger to the audit daemon
149 * fails.
150 */
151
152 /*
153 * If we fall below minimum free blocks (hard limit), tell the audit
154 * daemon to force a rotation off of the file system. We also stop
155 * writing, which means this audit record is probably lost. If we
156 * fall below the minimum percent free blocks (soft limit), then
157 * kindly suggest to the audit daemon to do something.
158 */
159 if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) {
160 (void)send_trigger(AUDIT_TRIGGER_NO_SPACE);
161 /*
162 * Hopefully userspace did something about all the previous
163 * triggers that were sent prior to this critical condition.
164 * If fail-stop is set, then we're done; goodnight Gracie.
165 */
166 if (audit_fail_stop)
167 panic("Audit log space exhausted and fail-stop set.");
168 else {
169 audit_suspended = 1;
170 ret = ENOSPC;
171 goto out;
172 }
173 } else
174 /*
175 * Send a message to the audit daemon that disk space is
176 * getting low.
177 *
178 * XXXAUDIT: Check math and block size calculation here.
179 */
180 if (audit_qctrl.aq_minfree != 0) {
181 temp = mnt_stat->f_blocks / (100 /
182 audit_qctrl.aq_minfree);
183 if (mnt_stat->f_bfree < temp)
184 (void)send_trigger(AUDIT_TRIGGER_LOW_SPACE);
185 }
186
187 /*
188 * Check if the current log file is full; if so, call for a log
189 * rotate. This is not an exact comparison; we may write some records
190 * over the limit. If that's not acceptable, then add a fudge factor
191 * here.
192 */
193 if ((audit_fstat.af_filesz != 0) &&
194 (audit_file_rotate_wait == 0) &&
195 (vattr.va_size >= audit_fstat.af_filesz)) {
196 audit_file_rotate_wait = 1;
197 (void)send_trigger(AUDIT_TRIGGER_OPEN_NEW);
198 }
199
200 /*
201 * If the estimated amount of audit data in the audit event queue
202 * (plus records allocated but not yet queued) has reached the amount
203 * of free space on the disk, then we need to go into an audit fail
204 * stop state, in which we do not permit the allocation/committing of
205 * any new audit records. We continue to process packets but don't
206 * allow any activities that might generate new records. In the
207 * future, we might want to detect when space is available again and
208 * allow operation to continue, but this behavior is sufficient to
209 * meet fail stop requirements in CAPP.
210 */
211 if (audit_fail_stop &&
212 (unsigned long)
213 ((audit_q_len + audit_pre_q_len + 1) * MAX_AUDIT_RECORD_SIZE) /
214 mnt_stat->f_bsize >= (unsigned long)(mnt_stat->f_bfree)) {
215 printf("audit_record_write: free space below size of audit "
216 "queue, failing stop\n");
217 audit_in_failure = 1;
218 }
219
220 ret = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE,
221 IO_APPEND|IO_UNIT, cred, NULL, NULL, td);
222
223out:
224 /*
225 * When we're done processing the current record, we have to check to
226 * see if we're in a failure mode, and if so, whether this was the
227 * last record left to be drained. If we're done draining, then we
228 * fsync the vnode and panic.
229 */
230 if (audit_in_failure && audit_q_len == 0 && audit_pre_q_len == 0) {
231 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
232 (void)VOP_FSYNC(vp, MNT_WAIT, td);
233 VOP_UNLOCK(vp, 0, td);
234 panic("Audit store overflow; record queue drained.");
235 }
236
237 VFS_UNLOCK_GIANT(vfslocked);
238
239 return (ret);
240}
241
242/*
243 * If an appropriate signal has been received rotate the audit log based on
244 * the global replacement variables. Signal consumers as needed that the
245 * rotation has taken place.
246 *
247 * XXXRW: The global variables and CVs used to signal the audit_worker to
248 * perform a rotation are essentially a message queue of depth 1. It would
249 * be much nicer to actually use a message queue.
250 */
251static void
252audit_worker_rotate(struct ucred **audit_credp, struct vnode **audit_vpp,
253 struct thread *audit_td)
254{
255 int do_replacement_signal, vfslocked;
256 struct ucred *old_cred;
257 struct vnode *old_vp;
258
259 mtx_assert(&audit_mtx, MA_OWNED);
260
261 do_replacement_signal = 0;
262 while (audit_replacement_flag != 0) {
263 old_cred = *audit_credp;
264 old_vp = *audit_vpp;
265 *audit_credp = audit_replacement_cred;
266 *audit_vpp = audit_replacement_vp;
267 audit_replacement_cred = NULL;
268 audit_replacement_vp = NULL;
269 audit_replacement_flag = 0;
270
271 audit_enabled = (*audit_vpp != NULL);
272
273 /*
274 * XXX: What to do about write failures here?
275 */
276 if (old_vp != NULL) {
277 AUDIT_PRINTF(("Closing old audit file\n"));
278 mtx_unlock(&audit_mtx);
279 vfslocked = VFS_LOCK_GIANT(old_vp->v_mount);
280 vn_close(old_vp, AUDIT_CLOSE_FLAGS, old_cred,
281 audit_td);
282 VFS_UNLOCK_GIANT(vfslocked);
283 crfree(old_cred);
284 mtx_lock(&audit_mtx);
285 old_cred = NULL;
286 old_vp = NULL;
287 AUDIT_PRINTF(("Audit file closed\n"));
288 }
289 if (*audit_vpp != NULL) {
290 AUDIT_PRINTF(("Opening new audit file\n"));
291 }
292 do_replacement_signal = 1;
293 }
294
295 /*
296 * Signal that replacement have occurred to wake up and
297 * start any other replacements started in parallel. We can
298 * continue about our business in the mean time. We
299 * broadcast so that both new replacements can be inserted,
300 * but also so that the source(s) of replacement can return
301 * successfully.
302 */
303 if (do_replacement_signal)
304 cv_broadcast(&audit_replacement_cv);
305}
306
307/*
308 * Given a kernel audit record, process as required. Kernel audit records
309 * are converted to one, or possibly two, BSM records, depending on whether
310 * there is a user audit record present also. Kernel records need be
311 * converted to BSM before they can be written out. Both types will be
312 * written to disk, and audit pipes.
313 */
314static void
315audit_worker_process_record(struct vnode *audit_vp, struct ucred *audit_cred,
316 struct thread *audit_td, struct kaudit_record *ar)
317{
318 struct au_record *bsm;
319 au_class_t class;
320 au_event_t event;
321 int error, ret;
322 au_id_t auid;
323 int sorf;
324
325 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
31 */
32
33#include <sys/param.h>
34#include <sys/condvar.h>
35#include <sys/conf.h>
36#include <sys/file.h>
37#include <sys/filedesc.h>
38#include <sys/fcntl.h>
39#include <sys/ipc.h>
40#include <sys/kernel.h>
41#include <sys/kthread.h>
42#include <sys/malloc.h>
43#include <sys/mount.h>
44#include <sys/namei.h>
45#include <sys/proc.h>
46#include <sys/queue.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49#include <sys/protosw.h>
50#include <sys/domain.h>
51#include <sys/sysproto.h>
52#include <sys/sysent.h>
53#include <sys/systm.h>
54#include <sys/ucred.h>
55#include <sys/uio.h>
56#include <sys/un.h>
57#include <sys/unistd.h>
58#include <sys/vnode.h>
59
60#include <bsm/audit.h>
61#include <bsm/audit_internal.h>
62#include <bsm/audit_kevents.h>
63
64#include <netinet/in.h>
65#include <netinet/in_pcb.h>
66
67#include <security/audit/audit.h>
68#include <security/audit/audit_private.h>
69
70#include <vm/uma.h>
71
72/*
73 * Worker thread that will schedule disk I/O, etc.
74 */
75static struct proc *audit_thread;
76
77/*
78 * When an audit log is rotated, the actual rotation must be performed by the
79 * audit worker thread, as it may have outstanding writes on the current
80 * audit log. audit_replacement_vp holds the vnode replacing the current
81 * vnode. We can't let more than one replacement occur at a time, so if more
82 * than one thread requests a replacement, only one can have the replacement
83 * "in progress" at any given moment. If a thread tries to replace the audit
84 * vnode and discovers a replacement is already in progress (i.e.,
85 * audit_replacement_flag != 0), then it will sleep on audit_replacement_cv
86 * waiting its turn to perform a replacement. When a replacement is
87 * completed, this cv is signalled by the worker thread so a waiting thread
88 * can start another replacement. We also store a credential to perform
89 * audit log write operations with.
90 *
91 * The current credential and vnode are thread-local to audit_worker.
92 */
93static struct cv audit_replacement_cv;
94
95static int audit_replacement_flag;
96static struct vnode *audit_replacement_vp;
97static struct ucred *audit_replacement_cred;
98
99/*
100 * Flags related to Kernel->user-space communication.
101 */
102static int audit_file_rotate_wait;
103
104/*
105 * XXXAUDIT: Should adjust comments below to make it clear that we get to
106 * this point only if we believe we have storage, so not having space here is
107 * a violation of invariants derived from administrative procedures. I.e.,
108 * someone else has written to the audit partition, leaving less space than
109 * we accounted for.
110 */
111static int
112audit_record_write(struct vnode *vp, struct ucred *cred, struct thread *td,
113 void *data, size_t len)
114{
115 int ret;
116 long temp;
117 struct vattr vattr;
118 struct statfs *mnt_stat;
119 int vfslocked;
120
121 if (vp == NULL)
122 return (0);
123
124 mnt_stat = &vp->v_mount->mnt_stat;
125 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
126
127 /*
128 * First, gather statistics on the audit log file and file system so
129 * that we know how we're doing on space. In both cases, if we're
130 * unable to perform the operation, we drop the record and return.
131 * However, this is arguably an assertion failure.
132 * XXX Need a FreeBSD equivalent.
133 */
134 ret = VFS_STATFS(vp->v_mount, mnt_stat, td);
135 if (ret)
136 goto out;
137
138 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
139 ret = VOP_GETATTR(vp, &vattr, cred, td);
140 VOP_UNLOCK(vp, 0, td);
141 if (ret)
142 goto out;
143
144 /* update the global stats struct */
145 audit_fstat.af_currsz = vattr.va_size;
146
147 /*
148 * XXX Need to decide what to do if the trigger to the audit daemon
149 * fails.
150 */
151
152 /*
153 * If we fall below minimum free blocks (hard limit), tell the audit
154 * daemon to force a rotation off of the file system. We also stop
155 * writing, which means this audit record is probably lost. If we
156 * fall below the minimum percent free blocks (soft limit), then
157 * kindly suggest to the audit daemon to do something.
158 */
159 if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) {
160 (void)send_trigger(AUDIT_TRIGGER_NO_SPACE);
161 /*
162 * Hopefully userspace did something about all the previous
163 * triggers that were sent prior to this critical condition.
164 * If fail-stop is set, then we're done; goodnight Gracie.
165 */
166 if (audit_fail_stop)
167 panic("Audit log space exhausted and fail-stop set.");
168 else {
169 audit_suspended = 1;
170 ret = ENOSPC;
171 goto out;
172 }
173 } else
174 /*
175 * Send a message to the audit daemon that disk space is
176 * getting low.
177 *
178 * XXXAUDIT: Check math and block size calculation here.
179 */
180 if (audit_qctrl.aq_minfree != 0) {
181 temp = mnt_stat->f_blocks / (100 /
182 audit_qctrl.aq_minfree);
183 if (mnt_stat->f_bfree < temp)
184 (void)send_trigger(AUDIT_TRIGGER_LOW_SPACE);
185 }
186
187 /*
188 * Check if the current log file is full; if so, call for a log
189 * rotate. This is not an exact comparison; we may write some records
190 * over the limit. If that's not acceptable, then add a fudge factor
191 * here.
192 */
193 if ((audit_fstat.af_filesz != 0) &&
194 (audit_file_rotate_wait == 0) &&
195 (vattr.va_size >= audit_fstat.af_filesz)) {
196 audit_file_rotate_wait = 1;
197 (void)send_trigger(AUDIT_TRIGGER_OPEN_NEW);
198 }
199
200 /*
201 * If the estimated amount of audit data in the audit event queue
202 * (plus records allocated but not yet queued) has reached the amount
203 * of free space on the disk, then we need to go into an audit fail
204 * stop state, in which we do not permit the allocation/committing of
205 * any new audit records. We continue to process packets but don't
206 * allow any activities that might generate new records. In the
207 * future, we might want to detect when space is available again and
208 * allow operation to continue, but this behavior is sufficient to
209 * meet fail stop requirements in CAPP.
210 */
211 if (audit_fail_stop &&
212 (unsigned long)
213 ((audit_q_len + audit_pre_q_len + 1) * MAX_AUDIT_RECORD_SIZE) /
214 mnt_stat->f_bsize >= (unsigned long)(mnt_stat->f_bfree)) {
215 printf("audit_record_write: free space below size of audit "
216 "queue, failing stop\n");
217 audit_in_failure = 1;
218 }
219
220 ret = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE,
221 IO_APPEND|IO_UNIT, cred, NULL, NULL, td);
222
223out:
224 /*
225 * When we're done processing the current record, we have to check to
226 * see if we're in a failure mode, and if so, whether this was the
227 * last record left to be drained. If we're done draining, then we
228 * fsync the vnode and panic.
229 */
230 if (audit_in_failure && audit_q_len == 0 && audit_pre_q_len == 0) {
231 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
232 (void)VOP_FSYNC(vp, MNT_WAIT, td);
233 VOP_UNLOCK(vp, 0, td);
234 panic("Audit store overflow; record queue drained.");
235 }
236
237 VFS_UNLOCK_GIANT(vfslocked);
238
239 return (ret);
240}
241
242/*
243 * If an appropriate signal has been received rotate the audit log based on
244 * the global replacement variables. Signal consumers as needed that the
245 * rotation has taken place.
246 *
247 * XXXRW: The global variables and CVs used to signal the audit_worker to
248 * perform a rotation are essentially a message queue of depth 1. It would
249 * be much nicer to actually use a message queue.
250 */
251static void
252audit_worker_rotate(struct ucred **audit_credp, struct vnode **audit_vpp,
253 struct thread *audit_td)
254{
255 int do_replacement_signal, vfslocked;
256 struct ucred *old_cred;
257 struct vnode *old_vp;
258
259 mtx_assert(&audit_mtx, MA_OWNED);
260
261 do_replacement_signal = 0;
262 while (audit_replacement_flag != 0) {
263 old_cred = *audit_credp;
264 old_vp = *audit_vpp;
265 *audit_credp = audit_replacement_cred;
266 *audit_vpp = audit_replacement_vp;
267 audit_replacement_cred = NULL;
268 audit_replacement_vp = NULL;
269 audit_replacement_flag = 0;
270
271 audit_enabled = (*audit_vpp != NULL);
272
273 /*
274 * XXX: What to do about write failures here?
275 */
276 if (old_vp != NULL) {
277 AUDIT_PRINTF(("Closing old audit file\n"));
278 mtx_unlock(&audit_mtx);
279 vfslocked = VFS_LOCK_GIANT(old_vp->v_mount);
280 vn_close(old_vp, AUDIT_CLOSE_FLAGS, old_cred,
281 audit_td);
282 VFS_UNLOCK_GIANT(vfslocked);
283 crfree(old_cred);
284 mtx_lock(&audit_mtx);
285 old_cred = NULL;
286 old_vp = NULL;
287 AUDIT_PRINTF(("Audit file closed\n"));
288 }
289 if (*audit_vpp != NULL) {
290 AUDIT_PRINTF(("Opening new audit file\n"));
291 }
292 do_replacement_signal = 1;
293 }
294
295 /*
296 * Signal that replacement have occurred to wake up and
297 * start any other replacements started in parallel. We can
298 * continue about our business in the mean time. We
299 * broadcast so that both new replacements can be inserted,
300 * but also so that the source(s) of replacement can return
301 * successfully.
302 */
303 if (do_replacement_signal)
304 cv_broadcast(&audit_replacement_cv);
305}
306
307/*
308 * Given a kernel audit record, process as required. Kernel audit records
309 * are converted to one, or possibly two, BSM records, depending on whether
310 * there is a user audit record present also. Kernel records need be
311 * converted to BSM before they can be written out. Both types will be
312 * written to disk, and audit pipes.
313 */
314static void
315audit_worker_process_record(struct vnode *audit_vp, struct ucred *audit_cred,
316 struct thread *audit_td, struct kaudit_record *ar)
317{
318 struct au_record *bsm;
319 au_class_t class;
320 au_event_t event;
321 int error, ret;
322 au_id_t auid;
323 int sorf;
324
325 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
326 (ar->k_ar_commit & AR_PRESELECT_TRAIL)) {
326 (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) {
327 error = audit_record_write(audit_vp, audit_cred, audit_td,
328 ar->k_udata, ar->k_ulen);
329 if (error && audit_panic_on_write_fail)
330 panic("audit_worker: write error %d\n", error);
331 else if (error)
332 printf("audit_worker: write error %d\n", error);
333 }
327 error = audit_record_write(audit_vp, audit_cred, audit_td,
328 ar->k_udata, ar->k_ulen);
329 if (error && audit_panic_on_write_fail)
330 panic("audit_worker: write error %d\n", error);
331 else if (error)
332 printf("audit_worker: write error %d\n", error);
333 }
334
334 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
335 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
335 (ar->k_ar_commit & AR_PRESELECT_PIPE))
336 (ar->k_ar_commit & AR_PRESELECT_USER_PIPE))
336 audit_pipe_submit_user(ar->k_udata, ar->k_ulen);
337
337 audit_pipe_submit_user(ar->k_udata, ar->k_ulen);
338
338 if (!(ar->k_ar_commit & AR_COMMIT_KERNEL))
339 if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) ||
340 ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 &&
341 (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0))
339 return;
340
341 auid = ar->k_ar.ar_subj_auid;
342 event = ar->k_ar.ar_event;
343 class = au_event_class(event);
344 if (ar->k_ar.ar_errno == 0)
345 sorf = AU_PRS_SUCCESS;
346 else
347 sorf = AU_PRS_FAILURE;
348
349 ret = kaudit_to_bsm(ar, &bsm);
350 switch (ret) {
351 case BSM_NOAUDIT:
352 return;
353
354 case BSM_FAILURE:
355 printf("audit_worker_process_record: BSM_FAILURE\n");
356 return;
357
358 case BSM_SUCCESS:
359 break;
360
361 default:
362 panic("kaudit_to_bsm returned %d", ret);
363 }
364
365 if (ar->k_ar_commit & AR_PRESELECT_TRAIL) {
366 error = audit_record_write(audit_vp, audit_cred,
367 audit_td, bsm->data, bsm->len);
368 if (error && audit_panic_on_write_fail)
369 panic("audit_worker: write error %d\n",
370 error);
371 else if (error)
372 printf("audit_worker: write error %d\n",
373 error);
374 }
342 return;
343
344 auid = ar->k_ar.ar_subj_auid;
345 event = ar->k_ar.ar_event;
346 class = au_event_class(event);
347 if (ar->k_ar.ar_errno == 0)
348 sorf = AU_PRS_SUCCESS;
349 else
350 sorf = AU_PRS_FAILURE;
351
352 ret = kaudit_to_bsm(ar, &bsm);
353 switch (ret) {
354 case BSM_NOAUDIT:
355 return;
356
357 case BSM_FAILURE:
358 printf("audit_worker_process_record: BSM_FAILURE\n");
359 return;
360
361 case BSM_SUCCESS:
362 break;
363
364 default:
365 panic("kaudit_to_bsm returned %d", ret);
366 }
367
368 if (ar->k_ar_commit & AR_PRESELECT_TRAIL) {
369 error = audit_record_write(audit_vp, audit_cred,
370 audit_td, bsm->data, bsm->len);
371 if (error && audit_panic_on_write_fail)
372 panic("audit_worker: write error %d\n",
373 error);
374 else if (error)
375 printf("audit_worker: write error %d\n",
376 error);
377 }
378
375 if (ar->k_ar_commit & AR_PRESELECT_PIPE)
376 audit_pipe_submit(auid, event, class, sorf,
377 ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data,
378 bsm->len);
379 kau_free(bsm);
380}
381
382/*
383 * The audit_worker thread is responsible for watching the event queue,
384 * dequeueing records, converting them to BSM format, and committing them to
385 * disk. In order to minimize lock thrashing, records are dequeued in sets
386 * to a thread-local work queue. In addition, the audit_work performs the
387 * actual exchange of audit log vnode pointer, as audit_vp is a thread-local
388 * variable.
389 */
390static void
391audit_worker(void *arg)
392{
393 struct kaudit_queue ar_worklist;
394 struct kaudit_record *ar;
395 struct ucred *audit_cred;
396 struct thread *audit_td;
397 struct vnode *audit_vp;
398 int lowater_signal;
399
400 AUDIT_PRINTF(("audit_worker starting\n"));
401
402 /*
403 * These are thread-local variables requiring no synchronization.
404 */
405 TAILQ_INIT(&ar_worklist);
406 audit_cred = NULL;
407 audit_td = curthread;
408 audit_vp = NULL;
409
410 mtx_lock(&audit_mtx);
411 while (1) {
412 mtx_assert(&audit_mtx, MA_OWNED);
413
414 /*
415 * Wait for record or rotation events.
416 */
417 while (!audit_replacement_flag && TAILQ_EMPTY(&audit_q)) {
418 AUDIT_PRINTF(("audit_worker waiting\n"));
419 cv_wait(&audit_worker_cv, &audit_mtx);
420 AUDIT_PRINTF(("audit_worker woken up\n"));
421 AUDIT_PRINTF(("audit_worker: new vp = %p; value of "
422 "flag %d\n", audit_replacement_vp,
423 audit_replacement_flag));
424 }
425
426 /*
427 * First priority: replace the audit log target if requested.
428 */
429 audit_worker_rotate(&audit_cred, &audit_vp, audit_td);
430
431 /*
432 * If there are records in the global audit record queue,
433 * transfer them to a thread-local queue and process them
434 * one by one. If we cross the low watermark threshold,
435 * signal any waiting processes that they may wake up and
436 * continue generating records.
437 */
438 lowater_signal = 0;
439 while ((ar = TAILQ_FIRST(&audit_q))) {
440 TAILQ_REMOVE(&audit_q, ar, k_q);
441 audit_q_len--;
442 if (audit_q_len == audit_qctrl.aq_lowater)
443 lowater_signal++;
444 TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q);
445 }
446 if (lowater_signal)
447 cv_broadcast(&audit_watermark_cv);
448
449 mtx_unlock(&audit_mtx);
450 while ((ar = TAILQ_FIRST(&ar_worklist))) {
451 TAILQ_REMOVE(&ar_worklist, ar, k_q);
452 audit_worker_process_record(audit_vp, audit_cred,
453 audit_td, ar);
454 audit_free(ar);
455 }
456 mtx_lock(&audit_mtx);
457 }
458}
459
460/*
461 * audit_rotate_vnode() is called by a user or kernel thread to configure or
462 * de-configure auditing on a vnode. The arguments are the replacement
463 * credential and vnode to substitute for the current credential and vnode,
464 * if any. If either is set to NULL, both should be NULL, and this is used
465 * to indicate that audit is being disabled. The real work is done in the
466 * audit_worker thread, but audit_rotate_vnode() waits synchronously for that
467 * to complete.
468 *
469 * The vnode should be referenced and opened by the caller. The credential
470 * should be referenced. audit_rotate_vnode() will own both references as of
471 * this call, so the caller should not release either.
472 *
473 * XXXAUDIT: Review synchronize communication logic. Really, this is a
474 * message queue of depth 1.
475 *
476 * XXXAUDIT: Enhance the comments below to indicate that we are basically
477 * acquiring ownership of the communications queue, inserting our message,
478 * and waiting for an acknowledgement.
479 */
480void
481audit_rotate_vnode(struct ucred *cred, struct vnode *vp)
482{
483
484 /*
485 * If other parallel log replacements have been requested, we wait
486 * until they've finished before continuing.
487 */
488 mtx_lock(&audit_mtx);
489 while (audit_replacement_flag != 0) {
490 AUDIT_PRINTF(("audit_rotate_vnode: sleeping to wait for "
491 "flag\n"));
492 cv_wait(&audit_replacement_cv, &audit_mtx);
493 AUDIT_PRINTF(("audit_rotate_vnode: woken up (flag %d)\n",
494 audit_replacement_flag));
495 }
496 audit_replacement_cred = cred;
497 audit_replacement_flag = 1;
498 audit_replacement_vp = vp;
499
500 /*
501 * Wake up the audit worker to perform the exchange once we
502 * release the mutex.
503 */
504 cv_signal(&audit_worker_cv);
505
506 /*
507 * Wait for the audit_worker to broadcast that a replacement has
508 * taken place; we know that once this has happened, our vnode
509 * has been replaced in, so we can return successfully.
510 */
511 AUDIT_PRINTF(("audit_rotate_vnode: waiting for news of "
512 "replacement\n"));
513 cv_wait(&audit_replacement_cv, &audit_mtx);
514 AUDIT_PRINTF(("audit_rotate_vnode: change acknowledged by "
515 "audit_worker (flag " "now %d)\n", audit_replacement_flag));
516 mtx_unlock(&audit_mtx);
517
518 audit_file_rotate_wait = 0; /* We can now request another rotation */
519}
520
521void
522audit_worker_init(void)
523{
524 int error;
525
526 cv_init(&audit_replacement_cv, "audit_replacement_cv");
527 error = kthread_create(audit_worker, NULL, &audit_thread, RFHIGHPID,
528 0, "audit_worker");
529 if (error)
530 panic("audit_worker_init: kthread_create returned %d", error);
531}
379 if (ar->k_ar_commit & AR_PRESELECT_PIPE)
380 audit_pipe_submit(auid, event, class, sorf,
381 ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data,
382 bsm->len);
383 kau_free(bsm);
384}
385
386/*
387 * The audit_worker thread is responsible for watching the event queue,
388 * dequeueing records, converting them to BSM format, and committing them to
389 * disk. In order to minimize lock thrashing, records are dequeued in sets
390 * to a thread-local work queue. In addition, the audit_work performs the
391 * actual exchange of audit log vnode pointer, as audit_vp is a thread-local
392 * variable.
393 */
394static void
395audit_worker(void *arg)
396{
397 struct kaudit_queue ar_worklist;
398 struct kaudit_record *ar;
399 struct ucred *audit_cred;
400 struct thread *audit_td;
401 struct vnode *audit_vp;
402 int lowater_signal;
403
404 AUDIT_PRINTF(("audit_worker starting\n"));
405
406 /*
407 * These are thread-local variables requiring no synchronization.
408 */
409 TAILQ_INIT(&ar_worklist);
410 audit_cred = NULL;
411 audit_td = curthread;
412 audit_vp = NULL;
413
414 mtx_lock(&audit_mtx);
415 while (1) {
416 mtx_assert(&audit_mtx, MA_OWNED);
417
418 /*
419 * Wait for record or rotation events.
420 */
421 while (!audit_replacement_flag && TAILQ_EMPTY(&audit_q)) {
422 AUDIT_PRINTF(("audit_worker waiting\n"));
423 cv_wait(&audit_worker_cv, &audit_mtx);
424 AUDIT_PRINTF(("audit_worker woken up\n"));
425 AUDIT_PRINTF(("audit_worker: new vp = %p; value of "
426 "flag %d\n", audit_replacement_vp,
427 audit_replacement_flag));
428 }
429
430 /*
431 * First priority: replace the audit log target if requested.
432 */
433 audit_worker_rotate(&audit_cred, &audit_vp, audit_td);
434
435 /*
436 * If there are records in the global audit record queue,
437 * transfer them to a thread-local queue and process them
438 * one by one. If we cross the low watermark threshold,
439 * signal any waiting processes that they may wake up and
440 * continue generating records.
441 */
442 lowater_signal = 0;
443 while ((ar = TAILQ_FIRST(&audit_q))) {
444 TAILQ_REMOVE(&audit_q, ar, k_q);
445 audit_q_len--;
446 if (audit_q_len == audit_qctrl.aq_lowater)
447 lowater_signal++;
448 TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q);
449 }
450 if (lowater_signal)
451 cv_broadcast(&audit_watermark_cv);
452
453 mtx_unlock(&audit_mtx);
454 while ((ar = TAILQ_FIRST(&ar_worklist))) {
455 TAILQ_REMOVE(&ar_worklist, ar, k_q);
456 audit_worker_process_record(audit_vp, audit_cred,
457 audit_td, ar);
458 audit_free(ar);
459 }
460 mtx_lock(&audit_mtx);
461 }
462}
463
464/*
465 * audit_rotate_vnode() is called by a user or kernel thread to configure or
466 * de-configure auditing on a vnode. The arguments are the replacement
467 * credential and vnode to substitute for the current credential and vnode,
468 * if any. If either is set to NULL, both should be NULL, and this is used
469 * to indicate that audit is being disabled. The real work is done in the
470 * audit_worker thread, but audit_rotate_vnode() waits synchronously for that
471 * to complete.
472 *
473 * The vnode should be referenced and opened by the caller. The credential
474 * should be referenced. audit_rotate_vnode() will own both references as of
475 * this call, so the caller should not release either.
476 *
477 * XXXAUDIT: Review synchronize communication logic. Really, this is a
478 * message queue of depth 1.
479 *
480 * XXXAUDIT: Enhance the comments below to indicate that we are basically
481 * acquiring ownership of the communications queue, inserting our message,
482 * and waiting for an acknowledgement.
483 */
484void
485audit_rotate_vnode(struct ucred *cred, struct vnode *vp)
486{
487
488 /*
489 * If other parallel log replacements have been requested, we wait
490 * until they've finished before continuing.
491 */
492 mtx_lock(&audit_mtx);
493 while (audit_replacement_flag != 0) {
494 AUDIT_PRINTF(("audit_rotate_vnode: sleeping to wait for "
495 "flag\n"));
496 cv_wait(&audit_replacement_cv, &audit_mtx);
497 AUDIT_PRINTF(("audit_rotate_vnode: woken up (flag %d)\n",
498 audit_replacement_flag));
499 }
500 audit_replacement_cred = cred;
501 audit_replacement_flag = 1;
502 audit_replacement_vp = vp;
503
504 /*
505 * Wake up the audit worker to perform the exchange once we
506 * release the mutex.
507 */
508 cv_signal(&audit_worker_cv);
509
510 /*
511 * Wait for the audit_worker to broadcast that a replacement has
512 * taken place; we know that once this has happened, our vnode
513 * has been replaced in, so we can return successfully.
514 */
515 AUDIT_PRINTF(("audit_rotate_vnode: waiting for news of "
516 "replacement\n"));
517 cv_wait(&audit_replacement_cv, &audit_mtx);
518 AUDIT_PRINTF(("audit_rotate_vnode: change acknowledged by "
519 "audit_worker (flag " "now %d)\n", audit_replacement_flag));
520 mtx_unlock(&audit_mtx);
521
522 audit_file_rotate_wait = 0; /* We can now request another rotation */
523}
524
525void
526audit_worker_init(void)
527{
528 int error;
529
530 cv_init(&audit_replacement_cv, "audit_replacement_cv");
531 error = kthread_create(audit_worker, NULL, &audit_thread, RFHIGHPID,
532 0, "audit_worker");
533 if (error)
534 panic("audit_worker_init: kthread_create returned %d", error);
535}