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 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/* |
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. |
111 */ |
112static void |
113audit_record_write(struct vnode *vp, struct ucred *cred, struct thread *td, 114 void *data, size_t len) 115{ |
116 static struct timeval last_lowspace_trigger; 117 static struct timeval last_fail; 118 static int cur_lowspace_trigger; |
119 struct statfs *mnt_stat; |
120 int error, vfslocked; 121 static int cur_fail; 122 struct vattr vattr; 123 long temp; |
124 125 if (vp == NULL) |
126 return; |
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 |
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. |
135 */ |
136 error = VFS_STATFS(vp->v_mount, mnt_stat, td); 137 if (error) 138 goto fail; |
139 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); |
140 error = VOP_GETATTR(vp, &vattr, cred, td); |
141 VOP_UNLOCK(vp, 0, td); |
142 if (error) 143 goto fail; |
144 audit_fstat.af_currsz = vattr.va_size; 145 146 /* |
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. |
171 */ |
172 if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) { 173 error = ENOSPC; 174 goto fail_enospc; 175 } |
176 177 /* |
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. |
181 */ |
182 if (audit_qctrl.aq_minfree != 0) { |
183 /* |
184 * XXXAUDIT: Check math and block size calculations here. |
185 */ |
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)) { |
190 (void)send_trigger(AUDIT_TRIGGER_LOW_SPACE); |
191 printf("Warning: audit space low\n"); 192 } |
193 } |
194 } |
195 196 /* |
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. |
200 */ |
201 if ((audit_fstat.af_filesz != 0) && (audit_file_rotate_wait == 0) && |
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 |
212 * any new audit records. We continue to process records but don't |
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 */ |
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 } |
234 } 235 |
236 error = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE, |
237 IO_APPEND|IO_UNIT, cred, NULL, NULL, td); |
238 if (error == ENOSPC) 239 goto fail_enospc; 240 else if (error) 241 goto fail; |
242 |
243 /* |
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. |
251 */ |
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) { |
271 VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td); 272 (void)VOP_FSYNC(vp, MNT_WAIT, td); 273 VOP_UNLOCK(vp, 0, td); |
274 panic("Audit log space exhausted and fail-stop set."); |
275 } |
276 (void)send_trigger(AUDIT_TRIGGER_NO_SPACE); 277 audit_suspended = 1; |
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); |
292 VFS_UNLOCK_GIANT(vfslocked); |
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; |
374 au_id_t auid; |
375 int error, sorf; |
376 |
377 /* 378 * First, handle the user record, if any: commit to the system trail 379 * and audit pipes as selected. 380 */ |
381 if ((ar->k_ar_commit & AR_COMMIT_USER) && |
382 (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) 383 audit_record_write(audit_vp, audit_cred, audit_td, |
384 ar->k_udata, ar->k_ulen); |
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 |
403 error = kaudit_to_bsm(ar, &bsm); 404 switch (error) { |
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: |
416 panic("kaudit_to_bsm returned %d", error); |
417 } 418 |
419 if (ar->k_ar_commit & AR_PRESELECT_TRAIL) 420 audit_record_write(audit_vp, audit_cred, audit_td, bsm->data, 421 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 |
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 --- |