audit.c revision 155558
1155192Srwatson/* 2155192Srwatson * Copyright (c) 1999-2005 Apple Computer, Inc. 3155406Srwatson * Copyright (c) 2006 Robert N. M. Watson 4155192Srwatson * All rights reserved. 5155192Srwatson * 6155192Srwatson * Redistribution and use in source and binary forms, with or without 7155192Srwatson * modification, are permitted provided that the following conditions 8155192Srwatson * are met: 9155192Srwatson * 1. Redistributions of source code must retain the above copyright 10155192Srwatson * notice, this list of conditions and the following disclaimer. 11155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright 12155192Srwatson * notice, this list of conditions and the following disclaimer in the 13155192Srwatson * documentation and/or other materials provided with the distribution. 14155192Srwatson * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15155192Srwatson * its contributors may be used to endorse or promote products derived 16155192Srwatson * from this software without specific prior written permission. 17155192Srwatson * 18155192Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21155192Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22155192Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26155192Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27155192Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28155192Srwatson * POSSIBILITY OF SUCH DAMAGE. 29155192Srwatson * 30155192Srwatson * $FreeBSD: head/sys/security/audit/audit.c 155558 2006-02-11 23:53:00Z rwatson $ 31155192Srwatson */ 32155192Srwatson 33155192Srwatson#include <sys/param.h> 34155192Srwatson#include <sys/condvar.h> 35155192Srwatson#include <sys/conf.h> 36155192Srwatson#include <sys/file.h> 37155192Srwatson#include <sys/filedesc.h> 38155192Srwatson#include <sys/fcntl.h> 39155192Srwatson#include <sys/ipc.h> 40155192Srwatson#include <sys/kernel.h> 41155192Srwatson#include <sys/kthread.h> 42155192Srwatson#include <sys/malloc.h> 43155192Srwatson#include <sys/mount.h> 44155192Srwatson#include <sys/namei.h> 45155192Srwatson#include <sys/proc.h> 46155192Srwatson#include <sys/queue.h> 47155192Srwatson#include <sys/socket.h> 48155192Srwatson#include <sys/socketvar.h> 49155192Srwatson#include <sys/protosw.h> 50155192Srwatson#include <sys/domain.h> 51155192Srwatson#include <sys/sysproto.h> 52155192Srwatson#include <sys/sysent.h> 53155192Srwatson#include <sys/systm.h> 54155192Srwatson#include <sys/ucred.h> 55155192Srwatson#include <sys/uio.h> 56155192Srwatson#include <sys/un.h> 57155192Srwatson#include <sys/unistd.h> 58155192Srwatson#include <sys/vnode.h> 59155192Srwatson 60155406Srwatson#include <bsm/audit.h> 61155406Srwatson#include <bsm/audit_kevents.h> 62155406Srwatson 63155192Srwatson#include <netinet/in.h> 64155192Srwatson#include <netinet/in_pcb.h> 65155192Srwatson 66155192Srwatson#include <security/audit/audit.h> 67155192Srwatson#include <security/audit/audit_private.h> 68155192Srwatson 69155406Srwatson#include <vm/uma.h> 70155406Srwatson 71155192Srwatson/* 72155192Srwatson * The AUDIT_EXCESSIVELY_VERBOSE define enables a number of 73155192Srwatson * gratuitously noisy printf's to the console. Due to the 74155192Srwatson * volume, it should be left off unless you want your system 75155192Srwatson * to churn a lot whenever the audit record flow gets high. 76155192Srwatson */ 77155192Srwatson//#define AUDIT_EXCESSIVELY_VERBOSE 78155192Srwatson#ifdef AUDIT_EXCESSIVELY_VERBOSE 79155192Srwatson#define AUDIT_PRINTF(x) printf x 80155192Srwatson#else 81155192Srwatson#define AUDIT_PRINTF(X) 82155192Srwatson#endif 83155192Srwatson 84155406Srwatsonstatic uma_zone_t audit_record_zone; 85155192Srwatsonstatic MALLOC_DEFINE(M_AUDITPROC, "audit_proc", "Audit process storage"); 86155192SrwatsonMALLOC_DEFINE(M_AUDITDATA, "audit_data", "Audit data storage"); 87155192SrwatsonMALLOC_DEFINE(M_AUDITPATH, "audit_path", "Audit path storage"); 88155192SrwatsonMALLOC_DEFINE(M_AUDITTEXT, "audit_text", "Audit text storage"); 89155192Srwatson 90155192Srwatson/* 91155192Srwatson * Audit control settings that are set/read by system calls and are 92155192Srwatson * hence non-static. 93155192Srwatson */ 94155192Srwatson/* 95155192Srwatson * Define the audit control flags. 96155192Srwatson */ 97155192Srwatsonint audit_enabled; 98155192Srwatsonint audit_suspended; 99155192Srwatson 100155192Srwatson/* 101155192Srwatson * Flags controlling behavior in low storage situations. 102155192Srwatson * Should we panic if a write fails? Should we fail stop 103155192Srwatson * if we're out of disk space? 104155192Srwatson */ 105155192Srwatsonint audit_panic_on_write_fail; 106155192Srwatsonint audit_fail_stop; 107155192Srwatson 108155192Srwatson/* 109155192Srwatson * Are we currently "failing stop" due to out of disk space? 110155192Srwatson */ 111155192Srwatsonstatic int audit_in_failure; 112155192Srwatson 113155192Srwatson/* 114155192Srwatson * Global audit statistiscs. 115155192Srwatson */ 116155192Srwatsonstruct audit_fstat audit_fstat; 117155192Srwatson 118155192Srwatson/* 119155192Srwatson * Preselection mask for non-attributable events. 120155192Srwatson */ 121155192Srwatsonstruct au_mask audit_nae_mask; 122155192Srwatson 123155192Srwatson/* 124155192Srwatson * Mutex to protect global variables shared between various threads and 125155192Srwatson * processes. 126155192Srwatson */ 127155192Srwatsonstatic struct mtx audit_mtx; 128155192Srwatson 129155192Srwatson/* 130155192Srwatson * Queue of audit records ready for delivery to disk. We insert new 131155192Srwatson * records at the tail, and remove records from the head. Also, 132155192Srwatson * a count of the number of records used for checking queue depth. 133155192Srwatson * In addition, a counter of records that we have allocated but are 134155192Srwatson * not yet in the queue, which is needed to estimate the total 135155192Srwatson * size of the combined set of records outstanding in the system. 136155192Srwatson */ 137155192Srwatsonstatic TAILQ_HEAD(, kaudit_record) audit_q; 138155192Srwatsonstatic int audit_q_len; 139155192Srwatsonstatic int audit_pre_q_len; 140155192Srwatson 141155192Srwatson/* 142155192Srwatson * Audit queue control settings (minimum free, low/high water marks, etc.) 143155192Srwatson */ 144155192Srwatsonstruct au_qctrl audit_qctrl; 145155192Srwatson 146155192Srwatson/* 147155192Srwatson * Condition variable to signal to the worker that it has work to do: 148155192Srwatson * either new records are in the queue, or a log replacement is taking 149155192Srwatson * place. 150155192Srwatson */ 151155192Srwatsonstatic struct cv audit_cv; 152155192Srwatson 153155192Srwatson/* 154155192Srwatson * Worker thread that will schedule disk I/O, etc. 155155192Srwatson */ 156155192Srwatsonstatic struct proc *audit_thread; 157155192Srwatson 158155192Srwatson/* 159155192Srwatson * When an audit log is rotated, the actual rotation must be performed 160155192Srwatson * by the audit worker thread, as it may have outstanding writes on the 161155192Srwatson * current audit log. audit_replacement_vp holds the vnode replacing 162155192Srwatson * the current vnode. We can't let more than one replacement occur 163155192Srwatson * at a time, so if more than one thread requests a replacement, only 164155192Srwatson * one can have the replacement "in progress" at any given moment. If 165155192Srwatson * a thread tries to replace the audit vnode and discovers a replacement 166155192Srwatson * is already in progress (i.e., audit_replacement_flag != 0), then it 167155192Srwatson * will sleep on audit_replacement_cv waiting its turn to perform a 168155192Srwatson * replacement. When a replacement is completed, this cv is signalled 169155192Srwatson * by the worker thread so a waiting thread can start another replacement. 170155192Srwatson * We also store a credential to perform audit log write operations with. 171155192Srwatson * 172155192Srwatson * The current credential and vnode are thread-local to audit_worker. 173155192Srwatson */ 174155192Srwatsonstatic struct cv audit_replacement_cv; 175155192Srwatson 176155192Srwatsonstatic int audit_replacement_flag; 177155192Srwatsonstatic struct vnode *audit_replacement_vp; 178155192Srwatsonstatic struct ucred *audit_replacement_cred; 179155192Srwatson 180155192Srwatson/* 181155192Srwatson * Condition variable to signal to the worker that it has work to do: 182155192Srwatson * either new records are in the queue, or a log replacement is taking 183155192Srwatson * place. 184155192Srwatson */ 185155192Srwatsonstatic struct cv audit_commit_cv; 186155192Srwatson 187155192Srwatson/* 188155192Srwatson * Condition variable for auditing threads wait on when in fail-stop mode. 189155192Srwatson * Threads wait on this CV forever (and ever), never seeing the light of 190155192Srwatson * day again. 191155192Srwatson */ 192155192Srwatsonstatic struct cv audit_fail_cv; 193155192Srwatson 194155192Srwatson/* 195155192Srwatson * Flags related to Kernel->user-space communication. 196155192Srwatson */ 197155192Srwatsonstatic int audit_file_rotate_wait; 198155192Srwatson 199155192Srwatson/* 200155406Srwatson * Construct an audit record for the passed thread. 201155192Srwatson */ 202155406Srwatsonstatic int 203155406Srwatsonaudit_record_ctor(void *mem, int size, void *arg, int flags) 204155406Srwatson{ 205155406Srwatson struct kaudit_record *ar; 206155406Srwatson struct thread *td; 207155406Srwatson 208155406Srwatson KASSERT(sizeof(*ar) == size, ("audit_record_ctor: wrong size")); 209155406Srwatson 210155406Srwatson td = arg; 211155406Srwatson ar = mem; 212155406Srwatson bzero(ar, sizeof(*ar)); 213155406Srwatson ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; 214155406Srwatson nanotime(&ar->k_ar.ar_starttime); 215155406Srwatson 216155406Srwatson /* 217155406Srwatson * Export the subject credential. 218155406Srwatson * 219155406Srwatson * XXXAUDIT: td_ucred access is OK without proc lock, but some other 220155406Srwatson * fields here may require the proc lock. 221155406Srwatson */ 222155406Srwatson cru2x(td->td_ucred, &ar->k_ar.ar_subj_cred); 223155406Srwatson ar->k_ar.ar_subj_ruid = td->td_ucred->cr_ruid; 224155406Srwatson ar->k_ar.ar_subj_rgid = td->td_ucred->cr_rgid; 225155406Srwatson ar->k_ar.ar_subj_egid = td->td_ucred->cr_groups[0]; 226155406Srwatson ar->k_ar.ar_subj_auid = td->td_proc->p_au->ai_auid; 227155406Srwatson ar->k_ar.ar_subj_asid = td->td_proc->p_au->ai_asid; 228155406Srwatson ar->k_ar.ar_subj_pid = td->td_proc->p_pid; 229155406Srwatson ar->k_ar.ar_subj_amask = td->td_proc->p_au->ai_mask; 230155406Srwatson ar->k_ar.ar_subj_term = td->td_proc->p_au->ai_termid; 231155406Srwatson bcopy(td->td_proc->p_comm, ar->k_ar.ar_subj_comm, MAXCOMLEN); 232155406Srwatson 233155406Srwatson return (0); 234155406Srwatson} 235155406Srwatson 236155192Srwatsonstatic void 237155406Srwatsonaudit_record_dtor(void *mem, int size, void *arg) 238155192Srwatson{ 239155406Srwatson struct kaudit_record *ar; 240155192Srwatson 241155406Srwatson KASSERT(sizeof(*ar) == size, ("audit_record_dtor: wrong size")); 242155406Srwatson 243155406Srwatson ar = mem; 244155406Srwatson if (ar->k_ar.ar_arg_upath1 != NULL) 245155192Srwatson free(ar->k_ar.ar_arg_upath1, M_AUDITPATH); 246155406Srwatson if (ar->k_ar.ar_arg_upath2 != NULL) 247155192Srwatson free(ar->k_ar.ar_arg_upath2, M_AUDITPATH); 248155406Srwatson if (ar->k_ar.ar_arg_text != NULL) 249155192Srwatson free(ar->k_ar.ar_arg_text, M_AUDITTEXT); 250155406Srwatson if (ar->k_udata != NULL) 251155192Srwatson free(ar->k_udata, M_AUDITDATA); 252155192Srwatson} 253155192Srwatson 254155192Srwatson/* 255155192Srwatson * XXXAUDIT: Should adjust comments below to make it clear that we get to 256155192Srwatson * this point only if we believe we have storage, so not having space here 257155192Srwatson * is a violation of invariants derived from administrative procedures. 258155192Srwatson * I.e., someone else has written to the audit partition, leaving less space 259155192Srwatson * than we accounted for. 260155192Srwatson */ 261155192Srwatsonstatic int 262155192Srwatsonaudit_record_write(struct vnode *vp, struct kaudit_record *ar, 263155192Srwatson struct ucred *cred, struct thread *td) 264155192Srwatson{ 265155192Srwatson int ret; 266155192Srwatson long temp; 267155192Srwatson struct au_record *bsm; 268155192Srwatson struct vattr vattr; 269155192Srwatson struct statfs *mnt_stat = &vp->v_mount->mnt_stat; 270155192Srwatson int vfslocked; 271155192Srwatson 272155192Srwatson vfslocked = VFS_LOCK_GIANT(vp->v_mount); 273155192Srwatson 274155192Srwatson /* 275155192Srwatson * First, gather statistics on the audit log file and file system 276155192Srwatson * so that we know how we're doing on space. In both cases, 277155192Srwatson * if we're unable to perform the operation, we drop the record 278155192Srwatson * and return. However, this is arguably an assertion failure. 279155192Srwatson * XXX Need a FreeBSD equivalent. 280155192Srwatson */ 281155192Srwatson ret = VFS_STATFS(vp->v_mount, mnt_stat, td); 282155192Srwatson if (ret) 283155192Srwatson goto out; 284155192Srwatson 285155448Srwatson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 286155192Srwatson ret = VOP_GETATTR(vp, &vattr, cred, td); 287155448Srwatson VOP_UNLOCK(vp, 0, td); 288155192Srwatson if (ret) 289155192Srwatson goto out; 290155192Srwatson 291155192Srwatson /* update the global stats struct */ 292155192Srwatson audit_fstat.af_currsz = vattr.va_size; 293155192Srwatson 294155192Srwatson /* 295155192Srwatson * XXX Need to decide what to do if the trigger to the audit daemon 296155192Srwatson * fails. 297155192Srwatson */ 298155192Srwatson 299155192Srwatson /* 300155192Srwatson * If we fall below minimum free blocks (hard limit), tell the audit 301155192Srwatson * daemon to force a rotation off of the file system. We also stop 302155192Srwatson * writing, which means this audit record is probably lost. 303155192Srwatson * If we fall below the minimum percent free blocks (soft limit), 304155192Srwatson * then kindly suggest to the audit daemon to do something. 305155192Srwatson */ 306155192Srwatson if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) { 307155192Srwatson send_trigger(AUDIT_TRIGGER_NO_SPACE); 308155192Srwatson /* Hopefully userspace did something about all the previous 309155192Srwatson * triggers that were sent prior to this critical condition. 310155192Srwatson * If fail-stop is set, then we're done; goodnight Gracie. 311155192Srwatson */ 312155192Srwatson if (audit_fail_stop) 313155192Srwatson panic("Audit log space exhausted and fail-stop set."); 314155192Srwatson else { 315155192Srwatson audit_suspended = 1; 316155192Srwatson ret = ENOSPC; 317155192Srwatson goto out; 318155192Srwatson } 319155192Srwatson } else 320155192Srwatson /* 321155192Srwatson * Send a message to the audit daemon that disk space 322155192Srwatson * is getting low. 323155192Srwatson * 324155192Srwatson * XXXAUDIT: Check math and block size calculation here. 325155192Srwatson */ 326155192Srwatson if (audit_qctrl.aq_minfree != 0) { 327155192Srwatson temp = mnt_stat->f_blocks / (100 / 328155192Srwatson audit_qctrl.aq_minfree); 329155192Srwatson if (mnt_stat->f_bfree < temp) 330155192Srwatson send_trigger(AUDIT_TRIGGER_LOW_SPACE); 331155192Srwatson } 332155192Srwatson 333155192Srwatson /* Check if the current log file is full; if so, call for 334155192Srwatson * a log rotate. This is not an exact comparison; we may 335155192Srwatson * write some records over the limit. If that's not 336155192Srwatson * acceptable, then add a fudge factor here. 337155192Srwatson */ 338155192Srwatson if ((audit_fstat.af_filesz != 0) && 339155192Srwatson (audit_file_rotate_wait == 0) && 340155192Srwatson (vattr.va_size >= audit_fstat.af_filesz)) { 341155192Srwatson audit_file_rotate_wait = 1; 342155192Srwatson send_trigger(AUDIT_TRIGGER_OPEN_NEW); 343155192Srwatson } 344155192Srwatson 345155192Srwatson /* 346155192Srwatson * If the estimated amount of audit data in the audit event queue 347155192Srwatson * (plus records allocated but not yet queued) has reached the 348155192Srwatson * amount of free space on the disk, then we need to go into an 349155192Srwatson * audit fail stop state, in which we do not permit the 350155192Srwatson * allocation/committing of any new audit records. We continue to 351155192Srwatson * process packets but don't allow any activities that might 352155192Srwatson * generate new records. In the future, we might want to detect 353155192Srwatson * when space is available again and allow operation to continue, 354155192Srwatson * but this behavior is sufficient to meet fail stop requirements 355155192Srwatson * in CAPP. 356155192Srwatson */ 357155192Srwatson if (audit_fail_stop && 358155192Srwatson (unsigned long) 359155192Srwatson ((audit_q_len + audit_pre_q_len + 1) * MAX_AUDIT_RECORD_SIZE) / 360155192Srwatson mnt_stat->f_bsize >= (unsigned long)(mnt_stat->f_bfree)) { 361155192Srwatson printf( 362155192Srwatson "audit_worker: free space below size of audit queue, failing stop\n"); 363155192Srwatson audit_in_failure = 1; 364155192Srwatson } 365155192Srwatson 366155192Srwatson /* 367155192Srwatson * If there is a user audit record attached to the kernel record, 368155192Srwatson * then write the user record. 369155192Srwatson */ 370155192Srwatson /* XXX Need to decide a few things here: IF the user audit 371155192Srwatson * record is written, but the write of the kernel record fails, 372155192Srwatson * what to do? Should the kernel record come before or after the 373155192Srwatson * user record? For now, we write the user record first, and 374155192Srwatson * we ignore errors. 375155192Srwatson */ 376155192Srwatson if (ar->k_ar_commit & AR_COMMIT_USER) { 377155408Srwatson /* 378155408Srwatson * Try submitting the record to any active audit pipes. 379155408Srwatson */ 380155408Srwatson audit_pipe_submit((void *)ar->k_udata, ar->k_ulen); 381155408Srwatson 382155408Srwatson /* 383155408Srwatson * And to disk. 384155408Srwatson */ 385155192Srwatson ret = vn_rdwr(UIO_WRITE, vp, (void *)ar->k_udata, ar->k_ulen, 386155192Srwatson (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, cred, NULL, 387155192Srwatson NULL, td); 388155192Srwatson if (ret) 389155192Srwatson goto out; 390155192Srwatson } 391155192Srwatson 392155192Srwatson /* 393155192Srwatson * Convert the internal kernel record to BSM format and write it 394155192Srwatson * out if everything's OK. 395155192Srwatson */ 396155192Srwatson if (!(ar->k_ar_commit & AR_COMMIT_KERNEL)) { 397155192Srwatson ret = 0; 398155192Srwatson goto out; 399155192Srwatson } 400155192Srwatson 401155192Srwatson /* 402155192Srwatson * XXXAUDIT: Should we actually allow this conversion to fail? With 403155192Srwatson * sleeping memory allocation and invariants checks, perhaps not. 404155192Srwatson */ 405155192Srwatson ret = kaudit_to_bsm(ar, &bsm); 406155192Srwatson if (ret == BSM_NOAUDIT) { 407155192Srwatson ret = 0; 408155192Srwatson goto out; 409155192Srwatson } 410155192Srwatson 411155192Srwatson /* 412155192Srwatson * XXX: We drop the record on BSM conversion failure, but really 413155192Srwatson * this is an assertion failure. 414155192Srwatson */ 415155192Srwatson if (ret == BSM_FAILURE) { 416155192Srwatson AUDIT_PRINTF(("BSM conversion failure\n")); 417155192Srwatson ret = EINVAL; 418155192Srwatson goto out; 419155192Srwatson } 420155408Srwatson 421155408Srwatson /* 422155408Srwatson * Try submitting the record to any active audit pipes. 423155408Srwatson */ 424155408Srwatson audit_pipe_submit((void *)bsm->data, bsm->len); 425155192Srwatson 426155192Srwatson /* 427155192Srwatson * XXX 428155192Srwatson * We should break the write functionality away from the BSM record 429155192Srwatson * generation and have the BSM generation done before this function 430155192Srwatson * is called. This function will then take the BSM record as a 431155192Srwatson * parameter. 432155192Srwatson */ 433155192Srwatson ret = (vn_rdwr(UIO_WRITE, vp, (void *)bsm->data, bsm->len, 434155192Srwatson (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, cred, NULL, NULL, td)); 435155192Srwatson 436155192Srwatson kau_free(bsm); 437155192Srwatson 438155192Srwatsonout: 439155192Srwatson /* 440155192Srwatson * When we're done processing the current record, we have to 441155192Srwatson * check to see if we're in a failure mode, and if so, whether 442155192Srwatson * this was the last record left to be drained. If we're done 443155192Srwatson * draining, then we fsync the vnode and panic. 444155192Srwatson */ 445155192Srwatson if (audit_in_failure && 446155192Srwatson audit_q_len == 0 && audit_pre_q_len == 0) { 447155192Srwatson VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td); 448155192Srwatson (void)VOP_FSYNC(vp, MNT_WAIT, td); 449155192Srwatson VOP_UNLOCK(vp, 0, td); 450155192Srwatson panic("Audit store overflow; record queue drained."); 451155192Srwatson } 452155192Srwatson 453155192Srwatson VFS_UNLOCK_GIANT(vfslocked); 454155192Srwatson 455155192Srwatson return (ret); 456155192Srwatson} 457155192Srwatson 458155192Srwatson/* 459155192Srwatson * The audit_worker thread is responsible for watching the event queue, 460155192Srwatson * dequeueing records, converting them to BSM format, and committing them to 461155192Srwatson * disk. In order to minimize lock thrashing, records are dequeued in sets 462155192Srwatson * to a thread-local work queue. In addition, the audit_work performs the 463155192Srwatson * actual exchange of audit log vnode pointer, as audit_vp is a thread-local 464155192Srwatson * variable. 465155192Srwatson */ 466155192Srwatsonstatic void 467155192Srwatsonaudit_worker(void *arg) 468155192Srwatson{ 469155192Srwatson int do_replacement_signal, error; 470155192Srwatson TAILQ_HEAD(, kaudit_record) ar_worklist; 471155192Srwatson struct kaudit_record *ar; 472155192Srwatson struct vnode *audit_vp, *old_vp; 473155192Srwatson int vfslocked; 474155192Srwatson 475155192Srwatson struct ucred *audit_cred, *old_cred; 476155192Srwatson struct thread *audit_td; 477155192Srwatson 478155192Srwatson AUDIT_PRINTF(("audit_worker starting\n")); 479155192Srwatson 480155192Srwatson /* 481155192Srwatson * These are thread-local variables requiring no synchronization. 482155192Srwatson */ 483155192Srwatson TAILQ_INIT(&ar_worklist); 484155192Srwatson audit_cred = NULL; 485155192Srwatson audit_td = curthread; 486155192Srwatson audit_vp = NULL; 487155192Srwatson 488155192Srwatson mtx_lock(&audit_mtx); 489155192Srwatson while (1) { 490155192Srwatson /* 491155192Srwatson * First priority: replace the audit log target if requested. 492155192Srwatson * Accessing the vnode here requires dropping the audit_mtx; 493155192Srwatson * in case another replacement was scheduled while the mutex 494155192Srwatson * was released, we loop. 495155192Srwatson * 496155192Srwatson * XXX It could well be we should drain existing records 497155192Srwatson * first to ensure that the timestamps and ordering 498155192Srwatson * are right. 499155192Srwatson */ 500155192Srwatson do_replacement_signal = 0; 501155192Srwatson while (audit_replacement_flag != 0) { 502155192Srwatson old_cred = audit_cred; 503155192Srwatson old_vp = audit_vp; 504155192Srwatson audit_cred = audit_replacement_cred; 505155192Srwatson audit_vp = audit_replacement_vp; 506155192Srwatson audit_replacement_cred = NULL; 507155192Srwatson audit_replacement_vp = NULL; 508155192Srwatson audit_replacement_flag = 0; 509155192Srwatson 510155192Srwatson audit_enabled = (audit_vp != NULL); 511155192Srwatson 512155192Srwatson /* 513155192Srwatson * XXX: What to do about write failures here? 514155192Srwatson */ 515155192Srwatson if (old_vp != NULL) { 516155192Srwatson AUDIT_PRINTF(("Closing old audit file\n")); 517155192Srwatson mtx_unlock(&audit_mtx); 518155192Srwatson vfslocked = VFS_LOCK_GIANT(old_vp->v_mount); 519155192Srwatson vn_close(old_vp, AUDIT_CLOSE_FLAGS, old_cred, 520155192Srwatson audit_td); 521155192Srwatson VFS_UNLOCK_GIANT(vfslocked); 522155192Srwatson crfree(old_cred); 523155192Srwatson mtx_lock(&audit_mtx); 524155192Srwatson old_cred = NULL; 525155192Srwatson old_vp = NULL; 526155192Srwatson AUDIT_PRINTF(("Audit file closed\n")); 527155192Srwatson } 528155192Srwatson if (audit_vp != NULL) { 529155192Srwatson AUDIT_PRINTF(("Opening new audit file\n")); 530155192Srwatson } 531155192Srwatson do_replacement_signal = 1; 532155192Srwatson } 533155192Srwatson /* 534155192Srwatson * Signal that replacement have occurred to wake up and 535155192Srwatson * start any other replacements started in parallel. We can 536155192Srwatson * continue about our business in the mean time. We 537155192Srwatson * broadcast so that both new replacements can be inserted, 538155192Srwatson * but also so that the source(s) of replacement can return 539155192Srwatson * successfully. 540155192Srwatson */ 541155192Srwatson if (do_replacement_signal) 542155192Srwatson cv_broadcast(&audit_replacement_cv); 543155192Srwatson 544155192Srwatson /* 545155192Srwatson * Next, check to see if we have any records to drain into 546155192Srwatson * the vnode. If not, go back to waiting for an event. 547155192Srwatson */ 548155192Srwatson if (TAILQ_EMPTY(&audit_q)) { 549155192Srwatson AUDIT_PRINTF(("audit_worker waiting\n")); 550155192Srwatson cv_wait(&audit_cv, &audit_mtx); 551155192Srwatson AUDIT_PRINTF(("audit_worker woken up\n")); 552155192Srwatson AUDIT_PRINTF(("audit_worker: new vp = %p; value of flag %d\n", 553155192Srwatson audit_replacement_vp, audit_replacement_flag)); 554155192Srwatson continue; 555155192Srwatson } 556155192Srwatson 557155192Srwatson /* 558155406Srwatson * If we have records, but there's no active vnode to write 559155406Srwatson * to, drain the record queue. Generally, we prevent the 560155406Srwatson * unnecessary allocation of records elsewhere, but we need 561155406Srwatson * to allow for races between conditional allocation and 562155406Srwatson * queueing. Go back to waiting when we're done. 563155192Srwatson */ 564155192Srwatson if (audit_vp == NULL) { 565155192Srwatson while ((ar = TAILQ_FIRST(&audit_q))) { 566155192Srwatson TAILQ_REMOVE(&audit_q, ar, k_q); 567155406Srwatson uma_zfree(audit_record_zone, ar); 568155192Srwatson audit_q_len--; 569155406Srwatson /* 570155406Srwatson * XXXRW: Why broadcast if we hold the 571155406Srwatson * mutex and know that audit_vp is NULL? 572155406Srwatson */ 573155192Srwatson if (audit_q_len <= audit_qctrl.aq_lowater) 574155192Srwatson cv_broadcast(&audit_commit_cv); 575155192Srwatson } 576155192Srwatson continue; 577155192Srwatson } 578155192Srwatson 579155192Srwatson /* 580155406Srwatson * We have both records to write and an active vnode to write 581155406Srwatson * to. Dequeue a record, and start the write. Eventually, 582155406Srwatson * it might make sense to dequeue several records and perform 583155406Srwatson * our own clustering, if the lower layers aren't doing it 584155406Srwatson * automatically enough. 585155192Srwatson */ 586155192Srwatson while ((ar = TAILQ_FIRST(&audit_q))) { 587155192Srwatson TAILQ_REMOVE(&audit_q, ar, k_q); 588155192Srwatson audit_q_len--; 589155192Srwatson if (audit_q_len <= audit_qctrl.aq_lowater) 590155192Srwatson cv_broadcast(&audit_commit_cv); 591155192Srwatson TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q); 592155192Srwatson } 593155192Srwatson 594155192Srwatson mtx_unlock(&audit_mtx); 595155192Srwatson while ((ar = TAILQ_FIRST(&ar_worklist))) { 596155192Srwatson TAILQ_REMOVE(&ar_worklist, ar, k_q); 597155192Srwatson if (audit_vp != NULL) { 598155192Srwatson error = audit_record_write(audit_vp, ar, 599155192Srwatson audit_cred, audit_td); 600155192Srwatson if (error && audit_panic_on_write_fail) 601155192Srwatson panic("audit_worker: write error %d\n", 602155192Srwatson error); 603155192Srwatson else if (error) 604155192Srwatson printf("audit_worker: write error %d\n", 605155192Srwatson error); 606155192Srwatson } 607155406Srwatson uma_zfree(audit_record_zone, ar); 608155192Srwatson } 609155192Srwatson mtx_lock(&audit_mtx); 610155192Srwatson } 611155192Srwatson} 612155192Srwatson 613155192Srwatson/* 614155192Srwatson * Initialize the Audit subsystem: configuration state, work queue, 615155192Srwatson * synchronization primitives, worker thread, and trigger device node. Also 616155192Srwatson * call into the BSM assembly code to initialize it. 617155192Srwatson */ 618155192Srwatsonstatic void 619155192Srwatsonaudit_init(void) 620155192Srwatson{ 621155192Srwatson int error; 622155192Srwatson 623155192Srwatson printf("Security auditing service present\n"); 624155192Srwatson audit_enabled = 0; 625155192Srwatson audit_suspended = 0; 626155192Srwatson audit_panic_on_write_fail = 0; 627155192Srwatson audit_fail_stop = 0; 628155192Srwatson audit_in_failure = 0; 629155192Srwatson 630155192Srwatson audit_replacement_vp = NULL; 631155192Srwatson audit_replacement_cred = NULL; 632155192Srwatson audit_replacement_flag = 0; 633155192Srwatson 634155192Srwatson audit_fstat.af_filesz = 0; /* '0' means unset, unbounded */ 635155192Srwatson audit_fstat.af_currsz = 0; 636155192Srwatson audit_nae_mask.am_success = AU_NULL; 637155192Srwatson audit_nae_mask.am_failure = AU_NULL; 638155192Srwatson 639155192Srwatson TAILQ_INIT(&audit_q); 640155192Srwatson audit_q_len = 0; 641155192Srwatson audit_pre_q_len = 0; 642155192Srwatson audit_qctrl.aq_hiwater = AQ_HIWATER; 643155192Srwatson audit_qctrl.aq_lowater = AQ_LOWATER; 644155192Srwatson audit_qctrl.aq_bufsz = AQ_BUFSZ; 645155192Srwatson audit_qctrl.aq_minfree = AU_FS_MINFREE; 646155192Srwatson 647155192Srwatson mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF); 648155192Srwatson cv_init(&audit_cv, "audit_cv"); 649155192Srwatson cv_init(&audit_replacement_cv, "audit_replacement_cv"); 650155192Srwatson cv_init(&audit_commit_cv, "audit_commit_cv"); 651155192Srwatson cv_init(&audit_fail_cv, "audit_fail_cv"); 652155192Srwatson 653155406Srwatson audit_record_zone = uma_zcreate("audit_record_zone", 654155406Srwatson sizeof(struct kaudit_record), audit_record_ctor, 655155406Srwatson audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); 656155406Srwatson 657155192Srwatson /* Initialize the BSM audit subsystem. */ 658155192Srwatson kau_init(); 659155192Srwatson 660155192Srwatson audit_file_rotate_wait = 0; 661155192Srwatson audit_trigger_init(); 662155192Srwatson 663155192Srwatson /* Register shutdown handler. */ 664155192Srwatson EVENTHANDLER_REGISTER(shutdown_pre_sync, audit_shutdown, NULL, 665155192Srwatson SHUTDOWN_PRI_FIRST); 666155192Srwatson 667155192Srwatson error = kthread_create(audit_worker, NULL, &audit_thread, RFHIGHPID, 668155192Srwatson 0, "audit_worker"); 669155192Srwatson if (error != 0) 670155192Srwatson panic("audit_init: kthread_create returned %d", error); 671155192Srwatson} 672155192Srwatson 673155192SrwatsonSYSINIT(audit_init, SI_SUB_AUDIT, SI_ORDER_FIRST, audit_init, NULL) 674155192Srwatson 675155192Srwatson/* 676155192Srwatson * audit_rotate_vnode() is called by a user or kernel thread to configure or 677155192Srwatson * de-configure auditing on a vnode. The arguments are the replacement 678155192Srwatson * credential and vnode to substitute for the current credential and vnode, 679155192Srwatson * if any. If either is set to NULL, both should be NULL, and this is used 680155192Srwatson * to indicate that audit is being disabled. The real work is done in the 681155192Srwatson * audit_worker thread, but audit_rotate_vnode() waits synchronously for that 682155192Srwatson * to complete. 683155192Srwatson * 684155192Srwatson * The vnode should be referenced and opened by the caller. The credential 685155192Srwatson * should be referenced. audit_rotate_vnode() will own both references as of 686155192Srwatson * this call, so the caller should not release either. 687155192Srwatson * 688155192Srwatson * XXXAUDIT: Review synchronize communication logic. Really, this is a 689155192Srwatson * message queue of depth 1. 690155192Srwatson * 691155192Srwatson * XXXAUDIT: Enhance the comments below to indicate that we are basically 692155192Srwatson * acquiring ownership of the communications queue, inserting our message, 693155192Srwatson * and waiting for an acknowledgement. 694155192Srwatson */ 695155192Srwatsonvoid 696155192Srwatsonaudit_rotate_vnode(struct ucred *cred, struct vnode *vp) 697155192Srwatson{ 698155192Srwatson 699155192Srwatson /* 700155192Srwatson * If other parallel log replacements have been requested, we wait 701155192Srwatson * until they've finished before continuing. 702155192Srwatson */ 703155192Srwatson mtx_lock(&audit_mtx); 704155192Srwatson while (audit_replacement_flag != 0) { 705155192Srwatson AUDIT_PRINTF(("audit_rotate_vnode: sleeping to wait for " 706155192Srwatson "flag\n")); 707155192Srwatson cv_wait(&audit_replacement_cv, &audit_mtx); 708155192Srwatson AUDIT_PRINTF(("audit_rotate_vnode: woken up (flag %d)\n", 709155192Srwatson audit_replacement_flag)); 710155192Srwatson } 711155192Srwatson audit_replacement_cred = cred; 712155192Srwatson audit_replacement_flag = 1; 713155192Srwatson audit_replacement_vp = vp; 714155192Srwatson 715155192Srwatson /* 716155192Srwatson * Wake up the audit worker to perform the exchange once we 717155192Srwatson * release the mutex. 718155192Srwatson */ 719155192Srwatson cv_signal(&audit_cv); 720155192Srwatson 721155192Srwatson /* 722155192Srwatson * Wait for the audit_worker to broadcast that a replacement has 723155192Srwatson * taken place; we know that once this has happened, our vnode 724155192Srwatson * has been replaced in, so we can return successfully. 725155192Srwatson */ 726155192Srwatson AUDIT_PRINTF(("audit_rotate_vnode: waiting for news of " 727155192Srwatson "replacement\n")); 728155192Srwatson cv_wait(&audit_replacement_cv, &audit_mtx); 729155192Srwatson AUDIT_PRINTF(("audit_rotate_vnode: change acknowledged by " 730155192Srwatson "audit_worker (flag " "now %d)\n", audit_replacement_flag)); 731155192Srwatson mtx_unlock(&audit_mtx); 732155192Srwatson 733155192Srwatson audit_file_rotate_wait = 0; /* We can now request another rotation */ 734155192Srwatson} 735155192Srwatson 736155192Srwatson/* 737155192Srwatson * Drain the audit queue and close the log at shutdown. Note that this can 738155192Srwatson * be called both from the system shutdown path and also from audit 739155192Srwatson * configuration syscalls, so 'arg' and 'howto' are ignored. 740155192Srwatson */ 741155192Srwatsonvoid 742155192Srwatsonaudit_shutdown(void *arg, int howto) 743155192Srwatson{ 744155192Srwatson 745155192Srwatson audit_rotate_vnode(NULL, NULL); 746155192Srwatson} 747155192Srwatson 748155192Srwatson/* 749155192Srwatson * Return the current thread's audit record, if any. 750155192Srwatson */ 751155192Srwatson__inline__ struct kaudit_record * 752155192Srwatsoncurrecord(void) 753155192Srwatson{ 754155192Srwatson 755155192Srwatson return (curthread->td_ar); 756155192Srwatson} 757155192Srwatson 758155192Srwatson/* 759155192Srwatson * MPSAFE 760155192Srwatson * 761155192Srwatson * XXXAUDIT: There are a number of races present in the code below due to 762155192Srwatson * release and re-grab of the mutex. The code should be revised to become 763155192Srwatson * slightly less racy. 764155192Srwatson * 765155192Srwatson * XXXAUDIT: Shouldn't there be logic here to sleep waiting on available 766155192Srwatson * pre_q space, suspending the system call until there is room? 767155192Srwatson */ 768155192Srwatsonstruct kaudit_record * 769155192Srwatsonaudit_new(int event, struct thread *td) 770155192Srwatson{ 771155192Srwatson struct kaudit_record *ar; 772155192Srwatson int no_record; 773155192Srwatson 774155406Srwatson mtx_lock(&audit_mtx); 775155406Srwatson no_record = (audit_suspended || !audit_enabled); 776155406Srwatson mtx_unlock(&audit_mtx); 777155406Srwatson if (no_record) 778155406Srwatson return (NULL); 779155192Srwatson 780155192Srwatson /* 781155192Srwatson * XXX: The number of outstanding uncommitted audit records is 782155406Srwatson * limited to the number of concurrent threads servicing system 783155192Srwatson * calls in the kernel. 784155192Srwatson */ 785155406Srwatson ar = uma_zalloc_arg(audit_record_zone, td, M_WAITOK); 786155406Srwatson ar->k_ar.ar_event = event; 787155192Srwatson 788155192Srwatson mtx_lock(&audit_mtx); 789155192Srwatson audit_pre_q_len++; 790155192Srwatson mtx_unlock(&audit_mtx); 791155192Srwatson 792155192Srwatson return (ar); 793155192Srwatson} 794155192Srwatson 795155192Srwatson/* 796155192Srwatson * MPSAFE 797155192Srwatson */ 798155192Srwatsonvoid 799155192Srwatsonaudit_commit(struct kaudit_record *ar, int error, int retval) 800155192Srwatson{ 801155192Srwatson int sorf; 802155192Srwatson struct au_mask *aumask; 803155192Srwatson 804155192Srwatson if (ar == NULL) 805155192Srwatson return; 806155192Srwatson 807155192Srwatson /* 808155192Srwatson * Decide whether to commit the audit record by checking the 809155192Srwatson * error value from the system call and using the appropriate 810155192Srwatson * audit mask. 811155192Srwatson * 812155192Srwatson * XXXAUDIT: Synchronize access to audit_nae_mask? 813155192Srwatson */ 814155192Srwatson if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID) 815155192Srwatson aumask = &audit_nae_mask; 816155192Srwatson else 817155192Srwatson aumask = &ar->k_ar.ar_subj_amask; 818155192Srwatson 819155192Srwatson if (error) 820155192Srwatson sorf = AU_PRS_FAILURE; 821155192Srwatson else 822155192Srwatson sorf = AU_PRS_SUCCESS; 823155192Srwatson 824155192Srwatson switch(ar->k_ar.ar_event) { 825155192Srwatson 826155192Srwatson case AUE_OPEN_RWTC: 827155192Srwatson /* The open syscall always writes a AUE_OPEN_RWTC event; change 828155192Srwatson * it to the proper type of event based on the flags and the 829155192Srwatson * error value. 830155192Srwatson */ 831155192Srwatson ar->k_ar.ar_event = flags_and_error_to_openevent( 832155192Srwatson ar->k_ar.ar_arg_fflags, error); 833155192Srwatson break; 834155192Srwatson 835155192Srwatson case AUE_SYSCTL: 836155192Srwatson ar->k_ar.ar_event = ctlname_to_sysctlevent( 837155192Srwatson ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg); 838155192Srwatson break; 839155192Srwatson 840155192Srwatson case AUE_AUDITON: 841155192Srwatson /* Convert the auditon() command to an event */ 842155192Srwatson ar->k_ar.ar_event = auditon_command_event(ar->k_ar.ar_arg_cmd); 843155192Srwatson break; 844155192Srwatson } 845155192Srwatson 846155192Srwatson if (au_preselect(ar->k_ar.ar_event, aumask, sorf) != 0) 847155192Srwatson ar->k_ar_commit |= AR_COMMIT_KERNEL; 848155192Srwatson 849155406Srwatson /* 850155406Srwatson * XXXRW: Why is this necessary? Should we ever accept a record that 851155406Srwatson * we're not willing to commit? 852155406Srwatson */ 853155192Srwatson if ((ar->k_ar_commit & (AR_COMMIT_USER | AR_COMMIT_KERNEL)) == 0) { 854155192Srwatson mtx_lock(&audit_mtx); 855155192Srwatson audit_pre_q_len--; 856155192Srwatson mtx_unlock(&audit_mtx); 857155406Srwatson uma_zfree(audit_record_zone, ar); 858155192Srwatson return; 859155192Srwatson } 860155192Srwatson 861155192Srwatson ar->k_ar.ar_errno = error; 862155192Srwatson ar->k_ar.ar_retval = retval; 863155192Srwatson 864155192Srwatson /* 865155192Srwatson * We might want to do some system-wide post-filtering 866155192Srwatson * here at some point. 867155192Srwatson */ 868155192Srwatson 869155192Srwatson /* 870155192Srwatson * Timestamp system call end. 871155192Srwatson */ 872155192Srwatson nanotime(&ar->k_ar.ar_endtime); 873155192Srwatson 874155192Srwatson mtx_lock(&audit_mtx); 875155192Srwatson 876155192Srwatson /* 877155192Srwatson * Note: it could be that some records initiated while audit was 878155192Srwatson * enabled should still be committed? 879155192Srwatson */ 880155192Srwatson if (audit_suspended || !audit_enabled) { 881155192Srwatson audit_pre_q_len--; 882155192Srwatson mtx_unlock(&audit_mtx); 883155406Srwatson uma_zfree(audit_record_zone, ar); 884155192Srwatson return; 885155192Srwatson } 886155192Srwatson 887155192Srwatson /* 888155192Srwatson * Constrain the number of committed audit records based on 889155192Srwatson * the configurable parameter. 890155192Srwatson */ 891155192Srwatson while (audit_q_len >= audit_qctrl.aq_hiwater) { 892155192Srwatson AUDIT_PRINTF(("audit_commit: sleeping to wait for " 893155192Srwatson "audit queue to drain below high water mark\n")); 894155192Srwatson cv_wait(&audit_commit_cv, &audit_mtx); 895155192Srwatson AUDIT_PRINTF(("audit_commit: woke up waiting for " 896155192Srwatson "audit queue draining\n")); 897155192Srwatson } 898155192Srwatson 899155192Srwatson TAILQ_INSERT_TAIL(&audit_q, ar, k_q); 900155192Srwatson audit_q_len++; 901155192Srwatson audit_pre_q_len--; 902155192Srwatson cv_signal(&audit_cv); 903155192Srwatson mtx_unlock(&audit_mtx); 904155192Srwatson} 905155192Srwatson 906155192Srwatson/* 907155192Srwatson * audit_syscall_enter() is called on entry to each system call. It is 908155192Srwatson * responsible for deciding whether or not to audit the call (preselection), 909155192Srwatson * and if so, allocating a per-thread audit record. audit_new() will fill in 910155192Srwatson * basic thread/credential properties. 911155192Srwatson */ 912155192Srwatsonvoid 913155192Srwatsonaudit_syscall_enter(unsigned short code, struct thread *td) 914155192Srwatson{ 915155192Srwatson int audit_event; 916155192Srwatson struct au_mask *aumask; 917155192Srwatson 918155192Srwatson KASSERT(td->td_ar == NULL, ("audit_syscall_enter: td->td_ar != NULL")); 919155192Srwatson 920155192Srwatson /* 921155192Srwatson * In FreeBSD, each ABI has its own system call table, and hence 922155192Srwatson * mapping of system call codes to audit events. Convert the code to 923155192Srwatson * an audit event identifier using the process system call table 924155192Srwatson * reference. In Darwin, there's only one, so we use the global 925155192Srwatson * symbol for the system call table. 926155192Srwatson * 927155192Srwatson * XXXAUDIT: Should we audit that a bad system call was made, and if 928155192Srwatson * so, how? 929155192Srwatson */ 930155192Srwatson if (code >= td->td_proc->p_sysent->sv_size) 931155192Srwatson return; 932155192Srwatson 933155192Srwatson audit_event = td->td_proc->p_sysent->sv_table[code].sy_auevent; 934155192Srwatson if (audit_event == AUE_NULL) 935155192Srwatson return; 936155192Srwatson 937155192Srwatson /* 938155192Srwatson * Check which audit mask to use; either the kernel non-attributable 939155192Srwatson * event mask or the process audit mask. 940155192Srwatson */ 941155192Srwatson if (td->td_proc->p_au->ai_auid == AU_DEFAUDITID) 942155192Srwatson aumask = &audit_nae_mask; 943155192Srwatson else 944155192Srwatson aumask = &td->td_proc->p_au->ai_mask; 945155192Srwatson 946155192Srwatson /* 947155192Srwatson * Allocate an audit record, if preselection allows it, and store 948155192Srwatson * in the thread for later use. 949155192Srwatson */ 950155192Srwatson if (au_preselect(audit_event, aumask, 951155192Srwatson AU_PRS_FAILURE | AU_PRS_SUCCESS)) { 952155192Srwatson /* 953155192Srwatson * If we're out of space and need to suspend unprivileged 954155192Srwatson * processes, do that here rather than trying to allocate 955155192Srwatson * another audit record. 956155192Srwatson * 957155192Srwatson * XXXRW: We might wish to be able to continue here in the 958155192Srwatson * future, if the system recovers. That should be possible 959155192Srwatson * by means of checking the condition in a loop around 960155192Srwatson * cv_wait(). It might be desirable to reevaluate whether an 961155192Srwatson * audit record is still required for this event by 962155192Srwatson * re-calling au_preselect(). 963155192Srwatson */ 964155192Srwatson if (audit_in_failure && suser(td) != 0) { 965155192Srwatson cv_wait(&audit_fail_cv, &audit_mtx); 966155192Srwatson panic("audit_failing_stop: thread continued"); 967155192Srwatson } 968155192Srwatson td->td_ar = audit_new(audit_event, td); 969155192Srwatson } else 970155192Srwatson td->td_ar = NULL; 971155192Srwatson} 972155192Srwatson 973155192Srwatson/* 974155192Srwatson * audit_syscall_exit() is called from the return of every system call, or in 975155192Srwatson * the event of exit1(), during the execution of exit1(). It is responsible 976155192Srwatson * for committing the audit record, if any, along with return condition. 977155192Srwatson */ 978155192Srwatsonvoid 979155192Srwatsonaudit_syscall_exit(int error, struct thread *td) 980155192Srwatson{ 981155192Srwatson int retval; 982155192Srwatson 983155192Srwatson /* 984155192Srwatson * Commit the audit record as desired; once we pass the record 985155192Srwatson * into audit_commit(), the memory is owned by the audit 986155192Srwatson * subsystem. 987155192Srwatson * The return value from the system call is stored on the user 988155192Srwatson * thread. If there was an error, the return value is set to -1, 989155192Srwatson * imitating the behavior of the cerror routine. 990155192Srwatson */ 991155192Srwatson if (error) 992155192Srwatson retval = -1; 993155192Srwatson else 994155192Srwatson retval = td->td_retval[0]; 995155192Srwatson 996155192Srwatson audit_commit(td->td_ar, error, retval); 997155192Srwatson if (td->td_ar != NULL) 998155192Srwatson AUDIT_PRINTF(("audit record committed by pid %d\n", 999155192Srwatson td->td_proc->p_pid)); 1000155192Srwatson td->td_ar = NULL; 1001155192Srwatson 1002155192Srwatson} 1003155192Srwatson 1004155192Srwatson/* 1005155192Srwatson * Allocate storage for a new process (init, or otherwise). 1006155192Srwatson */ 1007155192Srwatsonvoid 1008155192Srwatsonaudit_proc_alloc(struct proc *p) 1009155192Srwatson{ 1010155192Srwatson 1011155192Srwatson KASSERT(p->p_au == NULL, ("audit_proc_alloc: p->p_au != NULL (%d)", 1012155192Srwatson p->p_pid)); 1013155192Srwatson p->p_au = malloc(sizeof(*(p->p_au)), M_AUDITPROC, M_WAITOK); 1014155192Srwatson /* XXXAUDIT: Zero? Slab allocate? */ 1015155192Srwatson //printf("audit_proc_alloc: pid %d p_au %p\n", p->p_pid, p->p_au); 1016155192Srwatson} 1017155192Srwatson 1018155195Srwatson/* 1019155195Srwatson * Allocate storage for a new thread. 1020155195Srwatson */ 1021155195Srwatsonvoid 1022155195Srwatsonaudit_thread_alloc(struct thread *td) 1023155195Srwatson{ 1024155195Srwatson 1025155195Srwatson td->td_ar = NULL; 1026155195Srwatson} 1027155195Srwatson 1028155353Srwatson/* 1029155353Srwatson * Thread destruction. 1030155353Srwatson */ 1031155353Srwatsonvoid 1032155353Srwatsonaudit_thread_free(struct thread *td) 1033155353Srwatson{ 1034155353Srwatson 1035155353Srwatson KASSERT(td->td_ar == NULL, ("audit_thread_free: td_ar != NULL")); 1036155353Srwatson} 1037155353Srwatson 1038155192Srwatson/* 1039155192Srwatson * Initialize the audit information for the a process, presumably the first 1040155192Srwatson * process in the system. 1041155192Srwatson * XXX It is not clear what the initial values should be for audit ID, 1042155192Srwatson * session ID, etc. 1043155192Srwatson */ 1044155192Srwatsonvoid 1045155192Srwatsonaudit_proc_kproc0(struct proc *p) 1046155192Srwatson{ 1047155192Srwatson 1048155192Srwatson KASSERT(p->p_au != NULL, ("audit_proc_kproc0: p->p_au == NULL (%d)", 1049155192Srwatson p->p_pid)); 1050155192Srwatson //printf("audit_proc_kproc0: pid %d p_au %p\n", p->p_pid, p->p_au); 1051155192Srwatson bzero(p->p_au, sizeof(*(p)->p_au)); 1052155192Srwatson} 1053155192Srwatson 1054155192Srwatsonvoid 1055155192Srwatsonaudit_proc_init(struct proc *p) 1056155192Srwatson{ 1057155192Srwatson 1058155192Srwatson KASSERT(p->p_au != NULL, ("audit_proc_init: p->p_au == NULL (%d)", 1059155192Srwatson p->p_pid)); 1060155192Srwatson //printf("audit_proc_init: pid %d p_au %p\n", p->p_pid, p->p_au); 1061155192Srwatson bzero(p->p_au, sizeof(*(p)->p_au)); 1062155558Srwatson p->p_au->ai_auid = AU_DEFAUDITID; 1063155192Srwatson} 1064155192Srwatson 1065155192Srwatson/* 1066155192Srwatson * Copy the audit info from the parent process to the child process when 1067155192Srwatson * a fork takes place. 1068155192Srwatson */ 1069155192Srwatsonvoid 1070155192Srwatsonaudit_proc_fork(struct proc *parent, struct proc *child) 1071155192Srwatson{ 1072155192Srwatson 1073155192Srwatson PROC_LOCK_ASSERT(parent, MA_OWNED); 1074155192Srwatson PROC_LOCK_ASSERT(child, MA_OWNED); 1075155192Srwatson KASSERT(parent->p_au != NULL, 1076155192Srwatson ("audit_proc_fork: parent->p_au == NULL (%d)", parent->p_pid)); 1077155192Srwatson KASSERT(child->p_au != NULL, 1078155192Srwatson ("audit_proc_fork: child->p_au == NULL (%d)", child->p_pid)); 1079155192Srwatson //printf("audit_proc_fork: parent pid %d p_au %p\n", parent->p_pid, 1080155192Srwatson // parent->p_au); 1081155192Srwatson //printf("audit_proc_fork: child pid %d p_au %p\n", child->p_pid, 1082155192Srwatson // child->p_au); 1083155192Srwatson bcopy(parent->p_au, child->p_au, sizeof(*child->p_au)); 1084155192Srwatson /* 1085155192Srwatson * XXXAUDIT: Zero pointers to external memory, or assert they are 1086155192Srwatson * zero? 1087155192Srwatson */ 1088155192Srwatson} 1089155192Srwatson 1090155192Srwatson/* 1091155192Srwatson * Free the auditing structure for the process. 1092155192Srwatson */ 1093155192Srwatsonvoid 1094155192Srwatsonaudit_proc_free(struct proc *p) 1095155192Srwatson{ 1096155192Srwatson 1097155192Srwatson KASSERT(p->p_au != NULL, ("p->p_au == NULL (%d)", p->p_pid)); 1098155192Srwatson //printf("audit_proc_free: pid %d p_au %p\n", p->p_pid, p->p_au); 1099155192Srwatson /* 1100155192Srwatson * XXXAUDIT: Assert that external memory pointers are NULL? 1101155192Srwatson */ 1102155192Srwatson free(p->p_au, M_AUDITPROC); 1103155192Srwatson p->p_au = NULL; 1104155192Srwatson} 1105