Deleted Added
full compact
audit_worker.c (162508) audit_worker.c (162599)
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:

--- 13 unchanged lines hidden (view full) ---

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:

--- 13 unchanged lines hidden (view full) ---

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 162508 2006-09-21 07:27:02Z rwatson $
30 * $FreeBSD: head/sys/security/audit/audit_worker.c 162599 2006-09-24 13:35:58Z rwatson $
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>

--- 58 unchanged lines hidden (view full) ---

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/*
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>

--- 58 unchanged lines hidden (view full) ---

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.
105 * Write an audit record to a file, performed as the last stage after both
106 * preselection and BSM conversion. Both space management and write failures
107 * are handled in this function.
108 *
109 * No attempt is made to deal with possible failure to deliver a trigger to
110 * the audit daemon, since the message is asynchronous anyway.
110 */
111 */
111static int
112static void
112audit_record_write(struct vnode *vp, struct ucred *cred, struct thread *td,
113 void *data, size_t len)
114{
113audit_record_write(struct vnode *vp, struct ucred *cred, struct thread *td,
114 void *data, size_t len)
115{
115 int ret;
116 long temp;
117 struct vattr vattr;
116 static struct timeval last_lowspace_trigger;
117 static struct timeval last_fail;
118 static int cur_lowspace_trigger;
118 struct statfs *mnt_stat;
119 struct statfs *mnt_stat;
119 int vfslocked;
120 int error, vfslocked;
121 static int cur_fail;
122 struct vattr vattr;
123 long temp;
120
121 if (vp == NULL)
124
125 if (vp == NULL)
122 return (0);
126 return;
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
127
128 mnt_stat = &vp->v_mount->mnt_stat;
129 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
130
131 /*
132 * 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 * that we know how we're doing on space. Consider failure of these
134 * operations to indicate a future inability to write to the file.
133 */
135 */
134 ret = VFS_STATFS(vp->v_mount, mnt_stat, td);
135 if (ret)
136 goto out;
137
136 error = VFS_STATFS(vp->v_mount, mnt_stat, td);
137 if (error)
138 goto fail;
138 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
139 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
139 ret = VOP_GETATTR(vp, &vattr, cred, td);
140 error = VOP_GETATTR(vp, &vattr, cred, td);
140 VOP_UNLOCK(vp, 0, td);
141 VOP_UNLOCK(vp, 0, td);
141 if (ret)
142 goto out;
143
144 /* update the global stats struct */
142 if (error)
143 goto fail;
145 audit_fstat.af_currsz = vattr.va_size;
146
147 /*
144 audit_fstat.af_currsz = vattr.va_size;
145
146 /*
148 * XXX Need to decide what to do if the trigger to the audit daemon
149 * fails.
147 * We handle four different space-related limits:
148 *
149 * - A fixed (hard) limit on the minimum free blocks we require on
150 * the file system, and results in record loss, a trigger, and
151 * possible fail stop due to violating invariants.
152 *
153 * - An administrative (soft) limit, which when fallen below, results
154 * in the kernel notifying the audit daemon of low space.
155 *
156 * - An audit trail size limit, which when gone above, results in the
157 * kernel notifying the audit daemon that rotation is desired.
158 *
159 * - The total depth of the kernel audit record exceeding free space,
160 * which can lead to possible fail stop (with drain), in order to
161 * prevent violating invariants. Failure here doesn't halt
162 * immediately, but prevents new records from being generated.
163 *
164 * Possibly, the last of these should be handled differently, always
165 * allowing a full queue to be lost, rather than trying to prevent
166 * loss.
167 *
168 * First, handle the hard limit, which generates a trigger and may
169 * fail stop. This is handled in the same manner as ENOSPC from
170 * VOP_WRITE, and results in record loss.
150 */
171 */
172 if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) {
173 error = ENOSPC;
174 goto fail_enospc;
175 }
151
152 /*
176
177 /*
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.
178 * Second, handle falling below the soft limit, if defined; we send
179 * the daemon a trigger and continue processing the record. Triggers
180 * are limited to 1/sec.
158 */
181 */
159 if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) {
160 (void)send_trigger(AUDIT_TRIGGER_NO_SPACE);
182 if (audit_qctrl.aq_minfree != 0) {
161 /*
183 /*
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.
184 * XXXAUDIT: Check math and block size calculations here.
165 */
185 */
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)
186 temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree);
187 if (mnt_stat->f_bfree < temp) {
188 if (ppsratecheck(&last_lowspace_trigger,
189 &cur_lowspace_trigger, 1)) {
184 (void)send_trigger(AUDIT_TRIGGER_LOW_SPACE);
190 (void)send_trigger(AUDIT_TRIGGER_LOW_SPACE);
191 printf("Warning: audit space low\n");
192 }
185 }
193 }
194 }
186
187 /*
195
196 /*
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.
197 * If the current file is getting full, generate a rotation trigger
198 * to the daemon. This is only approximate, which is fine as more
199 * records may be generated before the daemon rotates the file.
192 */
200 */
193 if ((audit_fstat.af_filesz != 0) &&
194 (audit_file_rotate_wait == 0) &&
201 if ((audit_fstat.af_filesz != 0) && (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_ROTATE_KERNEL);
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
202 (vattr.va_size >= audit_fstat.af_filesz)) {
203 audit_file_rotate_wait = 1;
204 (void)send_trigger(AUDIT_TRIGGER_ROTATE_KERNEL);
205 }
206
207 /*
208 * If the estimated amount of audit data in the audit event queue
209 * (plus records allocated but not yet queued) has reached the amount
210 * of free space on the disk, then we need to go into an audit fail
211 * 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
212 * any new audit records. We continue to process records 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 */
213 * allow any activities that might generate new records. In the
214 * future, we might want to detect when space is available again and
215 * allow operation to continue, but this behavior is sufficient to
216 * meet fail stop requirements in CAPP.
217 */
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 if (audit_fail_stop) {
219 if ((unsigned long)((audit_q_len + audit_pre_q_len + 1) *
220 MAX_AUDIT_RECORD_SIZE) / mnt_stat->f_bsize >=
221 (unsigned long)(mnt_stat->f_bfree)) {
222 if (ppsratecheck(&last_fail, &cur_fail, 1))
223 printf("audit_record_write: free space "
224 "below size of audit queue, failing "
225 "stop\n");
226 audit_in_failure = 1;
227 } else if (audit_in_failure) {
228 /*
229 * XXXRW: If we want to handle recovery, this is the
230 * spot to do it: unset audit_in_failure, and issue a
231 * wakeup on the cv.
232 */
233 }
218 }
219
234 }
235
220 ret = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE,
236 error = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE,
221 IO_APPEND|IO_UNIT, cred, NULL, NULL, td);
237 IO_APPEND|IO_UNIT, cred, NULL, NULL, td);
238 if (error == ENOSPC)
239 goto fail_enospc;
240 else if (error)
241 goto fail;
222
242
223out:
224 /*
243 /*
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.
244 * Catch completion of a queue drain here; if we're draining and the
245 * queue is now empty, fail stop. That audit_fail_stop is implicitly
246 * true, since audit_in_failure can only be set of audit_fail_stop is
247 * set.
248 *
249 * XXXRW: If we handle recovery from audit_in_failure, then we need
250 * to make panic here conditional.
229 */
251 */
230 if (audit_in_failure && audit_q_len == 0 && audit_pre_q_len == 0) {
252 if (audit_in_failure) {
253 if (audit_q_len == 0 && audit_pre_q_len == 0) {
254 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
255 (void)VOP_FSYNC(vp, MNT_WAIT, td);
256 VOP_UNLOCK(vp, 0, td);
257 panic("Audit store overflow; record queue drained.");
258 }
259 }
260
261 VFS_UNLOCK_GIANT(vfslocked);
262 return;
263
264fail_enospc:
265 /*
266 * ENOSPC is considered a special case with respect to failures, as
267 * this can reflect either our preemptive detection of insufficient
268 * space, or ENOSPC returned by the vnode write call.
269 */
270 if (audit_fail_stop) {
231 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
232 (void)VOP_FSYNC(vp, MNT_WAIT, td);
233 VOP_UNLOCK(vp, 0, td);
271 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
272 (void)VOP_FSYNC(vp, MNT_WAIT, td);
273 VOP_UNLOCK(vp, 0, td);
234 panic("Audit store overflow; record queue drained.");
274 panic("Audit log space exhausted and fail-stop set.");
235 }
275 }
276 (void)send_trigger(AUDIT_TRIGGER_NO_SPACE);
277 audit_suspended = 1;
236
278
279 /* FALLTHROUGH */
280fail:
281 /*
282 * We have failed to write to the file, so the current record is
283 * lost, which may require an immediate system halt.
284 */
285 if (audit_panic_on_write_fail) {
286 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
287 (void)VOP_FSYNC(vp, MNT_WAIT, td);
288 VOP_UNLOCK(vp, 0, td);
289 panic("audit_worker: write error %d\n", error);
290 } else if (ppsratecheck(&last_fail, &cur_fail, 1))
291 printf("audit_worker: write error %d\n", error);
237 VFS_UNLOCK_GIANT(vfslocked);
292 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

--- 65 unchanged lines hidden (view full) ---

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;
293}
294
295/*
296 * If an appropriate signal has been received rotate the audit log based on
297 * the global replacement variables. Signal consumers as needed that the
298 * rotation has taken place.
299 *
300 * XXXRW: The global variables and CVs used to signal the audit_worker to

--- 65 unchanged lines hidden (view full) ---

366 */
367static void
368audit_worker_process_record(struct vnode *audit_vp, struct ucred *audit_cred,
369 struct thread *audit_td, struct kaudit_record *ar)
370{
371 struct au_record *bsm;
372 au_class_t class;
373 au_event_t event;
321 int error, ret;
322 au_id_t auid;
374 au_id_t auid;
323 int sorf;
375 int error, sorf;
324
376
377 /*
378 * First, handle the user record, if any: commit to the system trail
379 * and audit pipes as selected.
380 */
325 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
381 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
326 (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) {
327 error = audit_record_write(audit_vp, audit_cred, audit_td,
382 (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL))
383 audit_record_write(audit_vp, audit_cred, audit_td,
328 ar->k_udata, ar->k_ulen);
384 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
335 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
336 (ar->k_ar_commit & AR_PRESELECT_USER_PIPE))
337 audit_pipe_submit_user(ar->k_udata, ar->k_ulen);
338
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))
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
385
386 if ((ar->k_ar_commit & AR_COMMIT_USER) &&
387 (ar->k_ar_commit & AR_PRESELECT_USER_PIPE))
388 audit_pipe_submit_user(ar->k_udata, ar->k_ulen);
389
390 if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) ||
391 ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 &&
392 (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0))
393 return;
394
395 auid = ar->k_ar.ar_subj_auid;
396 event = ar->k_ar.ar_event;
397 class = au_event_class(event);
398 if (ar->k_ar.ar_errno == 0)
399 sorf = AU_PRS_SUCCESS;
400 else
401 sorf = AU_PRS_FAILURE;
402
352 ret = kaudit_to_bsm(ar, &bsm);
353 switch (ret) {
403 error = kaudit_to_bsm(ar, &bsm);
404 switch (error) {
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:
405 case BSM_NOAUDIT:
406 return;
407
408 case BSM_FAILURE:
409 printf("audit_worker_process_record: BSM_FAILURE\n");
410 return;
411
412 case BSM_SUCCESS:
413 break;
414
415 default:
365 panic("kaudit_to_bsm returned %d", ret);
416 panic("kaudit_to_bsm returned %d", error);
366 }
367
417 }
418
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 }
419 if (ar->k_ar_commit & AR_PRESELECT_TRAIL)
420 audit_record_write(audit_vp, audit_cred, audit_td, bsm->data,
421 bsm->len);
378
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);
422
423 if (ar->k_ar_commit & AR_PRESELECT_PIPE)
424 audit_pipe_submit(auid, event, class, sorf,
425 ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data,
426 bsm->len);
427
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

--- 145 unchanged lines hidden ---
428 kau_free(bsm);
429}
430
431/*
432 * The audit_worker thread is responsible for watching the event queue,
433 * dequeueing records, converting them to BSM format, and committing them to
434 * disk. In order to minimize lock thrashing, records are dequeued in sets
435 * to a thread-local work queue. In addition, the audit_work performs the

--- 145 unchanged lines hidden ---