audit_pipe.c revision 156292
1155408Srwatson/*- 2155408Srwatson * Copyright (c) 2006 Robert N. M. Watson 3155408Srwatson * All rights reserved. 4155408Srwatson * 5155408Srwatson * This software was developed by Robert Watson for the TrustedBSD Project. 6155408Srwatson * 7155408Srwatson * Redistribution and use in source and binary forms, with or without 8155408Srwatson * modification, are permitted provided that the following conditions 9155408Srwatson * are met: 10155408Srwatson * 1. Redistributions of source code must retain the above copyright 11155408Srwatson * notice, this list of conditions and the following disclaimer. 12155408Srwatson * 2. Redistributions in binary form must reproduce the above copyright 13155408Srwatson * notice, this list of conditions and the following disclaimer in the 14155408Srwatson * documentation and/or other materials provided with the distribution. 15155408Srwatson * 16155408Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17155408Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18155408Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19155408Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20155408Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21155408Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22155408Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23155408Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24155408Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25155408Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26155408Srwatson * SUCH DAMAGE. 27155408Srwatson * 28155408Srwatson * $FreeBSD: head/sys/security/audit/audit_pipe.c 156292 2006-03-04 17:09:17Z rwatson $ 29155408Srwatson */ 30155408Srwatson 31155408Srwatson#include <sys/param.h> 32155408Srwatson#include <sys/condvar.h> 33155408Srwatson#include <sys/conf.h> 34155408Srwatson#include <sys/eventhandler.h> 35155408Srwatson#include <sys/filio.h> 36155408Srwatson#include <sys/kernel.h> 37155408Srwatson#include <sys/lock.h> 38155408Srwatson#include <sys/malloc.h> 39155408Srwatson#include <sys/mutex.h> 40155408Srwatson#include <sys/poll.h> 41155408Srwatson#include <sys/proc.h> 42155408Srwatson#include <sys/queue.h> 43155408Srwatson#include <sys/selinfo.h> 44155408Srwatson#include <sys/sigio.h> 45155408Srwatson#include <sys/signal.h> 46155408Srwatson#include <sys/signalvar.h> 47155408Srwatson#include <sys/systm.h> 48155408Srwatson#include <sys/uio.h> 49155408Srwatson 50155408Srwatson#include <security/audit/audit.h> 51155408Srwatson#include <security/audit/audit_private.h> 52155408Srwatson 53155408Srwatson/* 54155408Srwatson * Implementation of a clonable special device providing a live stream of BSM 55155408Srwatson * audit data. This is a "tee" of the data going to the file. It provides 56155408Srwatson * unreliable but timely access to audit events. Consumers of this interface 57155408Srwatson * should be very careful to avoid introducing event cycles. 58155408Srwatson */ 59155408Srwatson 60155408Srwatson/* 61155408Srwatson * Memory types. 62155408Srwatson */ 63155408Srwatsonstatic MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 64155408Srwatsonstatic MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 65155408Srwatson "Audit pipe entries and buffers"); 66155408Srwatson 67155408Srwatson/* 68155408Srwatson * Audit pipe buffer parameters. 69155408Srwatson */ 70155408Srwatson#define AUDIT_PIPE_QLIMIT_DEFAULT (32) 71155408Srwatson#define AUDIT_PIPE_QLIMIT_MAX (1024) 72155408Srwatson 73155408Srwatson/* 74155408Srwatson * Description of an entry in an audit_pipe. 75155408Srwatson */ 76155408Srwatsonstruct audit_pipe_entry { 77155408Srwatson void *ape_record; 78155408Srwatson u_int ape_record_len; 79155408Srwatson TAILQ_ENTRY(audit_pipe_entry) ape_queue; 80155408Srwatson}; 81155408Srwatson 82155408Srwatson/* 83155408Srwatson * Description of an individual audit_pipe. Consists largely of a bounded 84155408Srwatson * length queue. 85155408Srwatson */ 86155408Srwatson#define AUDIT_PIPE_ASYNC 0x00000001 87155408Srwatson#define AUDIT_PIPE_NBIO 0x00000002 88155408Srwatsonstruct audit_pipe { 89155408Srwatson int ap_open; /* Device open? */ 90155408Srwatson u_int ap_flags; 91155408Srwatson 92155408Srwatson struct selinfo ap_selinfo; 93155408Srwatson struct sigio *ap_sigio; 94155408Srwatson 95155408Srwatson u_int ap_qlen; 96155408Srwatson u_int ap_qlimit; 97155408Srwatson 98155408Srwatson u_int64_t ap_inserts; /* Records added. */ 99155408Srwatson u_int64_t ap_reads; /* Records read. */ 100155408Srwatson u_int64_t ap_drops; /* Records dropped. */ 101155408Srwatson u_int64_t ap_truncates; /* Records too long. */ 102155408Srwatson 103155408Srwatson TAILQ_HEAD(, audit_pipe_entry) ap_queue; 104155408Srwatson 105155408Srwatson TAILQ_ENTRY(audit_pipe) ap_list; 106155408Srwatson}; 107155408Srwatson 108155408Srwatson/* 109155408Srwatson * Global list of audit pipes, mutex to protect it and the pipes. Finder 110155408Srwatson * grained locking may be desirable at some point. 111155408Srwatson */ 112155408Srwatsonstatic TAILQ_HEAD(, audit_pipe) audit_pipe_list; 113155408Srwatsonstatic struct mtx audit_pipe_mtx; 114155408Srwatson 115155408Srwatson/* 116155408Srwatson * This CV is used to wakeup on an audit record write. Eventually, it should 117155408Srwatson * probably be per-pipe. 118155408Srwatson */ 119155408Srwatsonstatic struct cv audit_pipe_cv; 120155408Srwatson 121155408Srwatson/* 122155408Srwatson * Cloning related variables and constants. 123155408Srwatson */ 124155408Srwatson#define AUDIT_PIPE_NAME "auditpipe" 125155408Srwatsonstatic eventhandler_tag audit_pipe_eh_tag; 126155408Srwatsonstatic struct clonedevs *audit_pipe_clones; 127155408Srwatson 128155408Srwatson/* 129155408Srwatson * Special device methods and definition. 130155408Srwatson */ 131155408Srwatsonstatic d_open_t audit_pipe_open; 132155408Srwatsonstatic d_close_t audit_pipe_close; 133155408Srwatsonstatic d_read_t audit_pipe_read; 134155408Srwatsonstatic d_ioctl_t audit_pipe_ioctl; 135155408Srwatsonstatic d_poll_t audit_pipe_poll; 136155408Srwatson 137155408Srwatsonstatic struct cdevsw audit_pipe_cdevsw = { 138155408Srwatson .d_version = D_VERSION, 139155408Srwatson .d_flags = D_PSEUDO, 140155408Srwatson .d_open = audit_pipe_open, 141155408Srwatson .d_close = audit_pipe_close, 142155408Srwatson .d_read = audit_pipe_read, 143155408Srwatson .d_ioctl = audit_pipe_ioctl, 144155408Srwatson .d_poll = audit_pipe_poll, 145155408Srwatson .d_name = AUDIT_PIPE_NAME, 146155408Srwatson}; 147155408Srwatson 148155408Srwatson/* 149155408Srwatson * Some global statistics on audit pipes. 150155408Srwatson */ 151155408Srwatsonstatic int audit_pipe_count; /* Current number of pipes. */ 152155408Srwatsonstatic u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 153155408Srwatsonstatic u_int64_t audit_pipe_records; /* Records seen. */ 154155408Srwatsonstatic u_int64_t audit_pipe_drops; /* Global record drop count. */ 155155408Srwatson 156155408Srwatson/* 157155408Srwatson * Free an audit pipe entry. 158155408Srwatson */ 159155408Srwatsonstatic void 160155408Srwatsonaudit_pipe_entry_free(struct audit_pipe_entry *ape) 161155408Srwatson{ 162155408Srwatson 163155408Srwatson free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 164155408Srwatson free(ape, M_AUDIT_PIPE_ENTRY); 165155408Srwatson} 166155408Srwatson 167155408Srwatson/* 168155408Srwatson * Apparent individual record to a queue -- allocate queue-local buffer, and 169155408Srwatson * add to the queue. We try to drop from the head of the queue so that more 170155408Srwatson * recent events take precedence over older ones, but if allocation fails we 171155408Srwatson * do drop the new event. 172155408Srwatson */ 173155408Srwatsonstatic void 174155408Srwatsonaudit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 175155408Srwatson{ 176155408Srwatson struct audit_pipe_entry *ape, *ape_remove; 177155408Srwatson 178155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 179155408Srwatson 180155408Srwatson ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 181155408Srwatson if (ape == NULL) { 182155408Srwatson ap->ap_drops++; 183156292Srwatson audit_pipe_drops++; 184155408Srwatson return; 185155408Srwatson } 186155408Srwatson 187155408Srwatson ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 188155408Srwatson if (ape->ape_record == NULL) { 189155408Srwatson free(ape, M_AUDIT_PIPE_ENTRY); 190155408Srwatson ap->ap_drops++; 191155408Srwatson audit_pipe_drops++; 192155408Srwatson return; 193155408Srwatson } 194155408Srwatson 195155408Srwatson bcopy(record, ape->ape_record, record_len); 196155408Srwatson ape->ape_record_len = record_len; 197155408Srwatson 198155408Srwatson if (ap->ap_qlen >= ap->ap_qlimit) { 199155408Srwatson ape_remove = TAILQ_FIRST(&ap->ap_queue); 200155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); 201155408Srwatson audit_pipe_entry_free(ape_remove); 202155428Srwatson ap->ap_qlen--; 203155408Srwatson ap->ap_drops++; 204155408Srwatson audit_pipe_drops++; 205155408Srwatson } 206155408Srwatson 207155408Srwatson TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 208155408Srwatson ap->ap_inserts++; 209155408Srwatson ap->ap_qlen++; 210155408Srwatson selwakeuppri(&ap->ap_selinfo, PSOCK); 211155408Srwatson if (ap->ap_flags & AUDIT_PIPE_ASYNC) 212155408Srwatson pgsigio(&ap->ap_sigio, SIGIO, 0); 213155408Srwatson} 214155408Srwatson 215155408Srwatson/* 216155408Srwatson * audit_pipe_submit(): audit_worker submits audit records via this 217155408Srwatson * interface, which arranges for them to be delivered to pipe queues. 218155408Srwatson */ 219155408Srwatsonvoid 220155408Srwatsonaudit_pipe_submit(void *record, u_int record_len) 221155408Srwatson{ 222155408Srwatson struct audit_pipe *ap; 223155408Srwatson 224155408Srwatson /* 225155408Srwatson * Lockless read to avoid mutex overhead if pipes are not in use. 226155408Srwatson */ 227155408Srwatson if (TAILQ_FIRST(&audit_pipe_list) == NULL) 228155408Srwatson return; 229155408Srwatson 230155408Srwatson mtx_lock(&audit_pipe_mtx); 231155408Srwatson TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) 232155408Srwatson audit_pipe_append(ap, record, record_len); 233155408Srwatson audit_pipe_records++; 234155408Srwatson mtx_unlock(&audit_pipe_mtx); 235155408Srwatson cv_signal(&audit_pipe_cv); 236155408Srwatson} 237155408Srwatson 238155408Srwatson/* 239155408Srwatson * Read the next record off of an audit pipe. 240155408Srwatson */ 241155408Srwatsonstatic struct audit_pipe_entry * 242155408Srwatsonaudit_pipe_pop(struct audit_pipe *ap) 243155408Srwatson{ 244155408Srwatson struct audit_pipe_entry *ape; 245155408Srwatson 246155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 247155408Srwatson 248155408Srwatson ape = TAILQ_FIRST(&ap->ap_queue); 249155408Srwatson KASSERT((ape == NULL && ap->ap_qlen == 0) || 250155408Srwatson (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen")); 251155408Srwatson if (ape == NULL) 252155408Srwatson return (NULL); 253155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 254155408Srwatson ap->ap_qlen--; 255155408Srwatson return (ape); 256155408Srwatson} 257155408Srwatson 258155408Srwatson/* 259155408Srwatson * Allocate a new audit pipe. Connects the pipe, on success, to the global 260155408Srwatson * list and updates statistics. 261155408Srwatson */ 262155408Srwatsonstatic struct audit_pipe * 263155408Srwatsonaudit_pipe_alloc(void) 264155408Srwatson{ 265155408Srwatson struct audit_pipe *ap; 266155408Srwatson 267155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 268155408Srwatson 269155408Srwatson ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); 270155408Srwatson if (ap == NULL) 271155408Srwatson return (NULL); 272155408Srwatson ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; 273155408Srwatson TAILQ_INIT(&ap->ap_queue); 274155408Srwatson TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); 275155408Srwatson audit_pipe_count++; 276155408Srwatson audit_pipe_ever++; 277155408Srwatson return (ap); 278155408Srwatson} 279155408Srwatson 280155408Srwatson/* 281155408Srwatson * Free an audit pipe. Assumes mutex is held, audit_pipe is still on the 282155408Srwatson * global list. Frees any audit pipe entries in the queue. 283155408Srwatson */ 284155408Srwatsonstatic void 285155408Srwatsonaudit_pipe_free(struct audit_pipe *ap) 286155408Srwatson{ 287155408Srwatson struct audit_pipe_entry *ape; 288155408Srwatson 289155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 290155408Srwatson 291155408Srwatson TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); 292155408Srwatson while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { 293155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 294155408Srwatson audit_pipe_entry_free(ape); 295155408Srwatson ap->ap_qlen--; 296155408Srwatson } 297155408Srwatson KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen")); 298155408Srwatson free(ap, M_AUDIT_PIPE); 299155408Srwatson audit_pipe_count--; 300155408Srwatson} 301155408Srwatson 302155408Srwatson/* 303155408Srwatson * Audit pipe clone routine -- provide specific requested audit pipe, or a 304155408Srwatson * fresh one if a specific one is not requested. 305155408Srwatson */ 306155408Srwatsonstatic void 307155408Srwatsonaudit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, 308155408Srwatson struct cdev **dev) 309155408Srwatson{ 310155408Srwatson int i, u; 311155408Srwatson 312155408Srwatson if (*dev != NULL) 313155408Srwatson return; 314155408Srwatson 315155408Srwatson if (strcmp(name, AUDIT_PIPE_NAME) == 0) 316155408Srwatson u = -1; 317155408Srwatson else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) 318155408Srwatson return; 319155408Srwatson 320155408Srwatson i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); 321155408Srwatson if (i) { 322155408Srwatson *dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT, 323155408Srwatson GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); 324155408Srwatson if (*dev != NULL) { 325155408Srwatson dev_ref(*dev); 326155408Srwatson (*dev)->si_flags |= SI_CHEAPCLONE; 327155408Srwatson } 328155408Srwatson } 329155408Srwatson} 330155408Srwatson 331155408Srwatson/* 332155408Srwatson * Audit pipe open method. Explicit suser check isn't used as this allows 333155408Srwatson * file permissions on the special device to be used to grant audit review 334155408Srwatson * access. 335155408Srwatson */ 336155408Srwatsonstatic int 337155408Srwatsonaudit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 338155408Srwatson{ 339155408Srwatson struct audit_pipe *ap; 340155408Srwatson 341155408Srwatson mtx_lock(&audit_pipe_mtx); 342155408Srwatson ap = dev->si_drv1; 343155408Srwatson if (ap == NULL) { 344155408Srwatson ap = audit_pipe_alloc(); 345155408Srwatson if (ap == NULL) { 346155408Srwatson mtx_unlock(&audit_pipe_mtx); 347155408Srwatson return (ENOMEM); 348155408Srwatson } 349155408Srwatson dev->si_drv1 = ap; 350155408Srwatson } else { 351155408Srwatson KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); 352155408Srwatson mtx_unlock(&audit_pipe_mtx); 353155408Srwatson return (EBUSY); 354155408Srwatson } 355155408Srwatson ap->ap_open = 1; 356155408Srwatson mtx_unlock(&audit_pipe_mtx); 357155408Srwatson fsetown(td->td_proc->p_pid, &ap->ap_sigio); 358155408Srwatson return (0); 359155408Srwatson} 360155408Srwatson 361155408Srwatson/* 362155408Srwatson * Close audit pipe, tear down all records, etc. 363155408Srwatson */ 364155408Srwatsonstatic int 365155408Srwatsonaudit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 366155408Srwatson{ 367155408Srwatson struct audit_pipe *ap; 368155408Srwatson 369155408Srwatson ap = dev->si_drv1; 370155408Srwatson KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); 371155408Srwatson KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); 372155408Srwatson funsetown(&ap->ap_sigio); 373155408Srwatson mtx_lock(&audit_pipe_mtx); 374155408Srwatson ap->ap_open = 0; 375155408Srwatson audit_pipe_free(ap); 376155408Srwatson dev->si_drv1 = NULL; 377155408Srwatson mtx_unlock(&audit_pipe_mtx); 378155408Srwatson return (0); 379155408Srwatson} 380155408Srwatson 381155408Srwatson/* 382155408Srwatson * Audit pipe ioctl() routine. Nothing for now, but eventually will allow 383155408Srwatson * setting and retrieval of current queue depth, queue limit, flush, etc. 384155408Srwatson * 385155408Srwatson * Would be desirable to support filtering, although perhaps something simple 386155408Srwatson * like an event mask, as opposed to something complicated like BPF. 387155408Srwatson */ 388155408Srwatsonstatic int 389155408Srwatsonaudit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 390155408Srwatson struct thread *td) 391155408Srwatson{ 392155408Srwatson struct audit_pipe *ap; 393155408Srwatson int error; 394155408Srwatson 395155408Srwatson ap = dev->si_drv1; 396155408Srwatson KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); 397155408Srwatson switch (cmd) { 398155408Srwatson case FIONBIO: 399155408Srwatson mtx_lock(&audit_pipe_mtx); 400155408Srwatson if (*(int *)data) 401155408Srwatson ap->ap_flags |= AUDIT_PIPE_NBIO; 402155408Srwatson else 403155408Srwatson ap->ap_flags &= ~AUDIT_PIPE_NBIO; 404155408Srwatson mtx_unlock(&audit_pipe_mtx); 405155408Srwatson error = 0; 406155408Srwatson break; 407155408Srwatson 408155408Srwatson case FIONREAD: 409155408Srwatson mtx_lock(&audit_pipe_mtx); 410155408Srwatson if (TAILQ_FIRST(&ap->ap_queue) != NULL) 411155408Srwatson *(int *)data = 412155408Srwatson TAILQ_FIRST(&ap->ap_queue)->ape_record_len; 413155408Srwatson else 414155408Srwatson *(int *)data = 0; 415155408Srwatson mtx_unlock(&audit_pipe_mtx); 416155408Srwatson error = 0; 417155408Srwatson break; 418155408Srwatson 419155408Srwatson case FIOASYNC: 420155408Srwatson mtx_lock(&audit_pipe_mtx); 421155408Srwatson if (*(int *)data) 422155408Srwatson ap->ap_flags |= AUDIT_PIPE_ASYNC; 423155408Srwatson else 424155408Srwatson ap->ap_flags &= ~AUDIT_PIPE_ASYNC; 425155408Srwatson mtx_unlock(&audit_pipe_mtx); 426155408Srwatson error = 0; 427155408Srwatson break; 428155408Srwatson 429155408Srwatson case FIOSETOWN: 430155408Srwatson error = fsetown(*(int *)data, &ap->ap_sigio); 431155408Srwatson break; 432155408Srwatson 433155408Srwatson case FIOGETOWN: 434155408Srwatson *(int *)data = fgetown(&ap->ap_sigio); 435155408Srwatson error = 0; 436155408Srwatson 437155408Srwatson default: 438155408Srwatson error = ENOTTY; 439155408Srwatson } 440155408Srwatson return (error); 441155408Srwatson} 442155408Srwatson 443155408Srwatson/* 444155408Srwatson * Audit pipe read. Pull one record off the queue and copy to user space. 445155408Srwatson * On error, the record is dropped. 446155408Srwatson */ 447155408Srwatsonstatic int 448155408Srwatsonaudit_pipe_read(struct cdev *dev, struct uio *uio, int flag) 449155408Srwatson{ 450155408Srwatson struct audit_pipe_entry *ape; 451155408Srwatson struct audit_pipe *ap; 452155408Srwatson int error; 453155408Srwatson 454155408Srwatson ap = dev->si_drv1; 455155408Srwatson KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); 456155408Srwatson mtx_lock(&audit_pipe_mtx); 457155408Srwatson do { 458155408Srwatson /* 459155408Srwatson * Wait for a record that fits into the read buffer, dropping 460155408Srwatson * records that would be truncated if actually passed to the 461155408Srwatson * process. This helps maintain the discreet record read 462155408Srwatson * interface. 463155408Srwatson */ 464155408Srwatson while ((ape = audit_pipe_pop(ap)) == NULL) { 465155408Srwatson if (ap->ap_flags & AUDIT_PIPE_NBIO) { 466155408Srwatson mtx_unlock(&audit_pipe_mtx); 467155408Srwatson return (EAGAIN); 468155408Srwatson } 469155408Srwatson error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); 470155408Srwatson if (error) { 471155408Srwatson mtx_unlock(&audit_pipe_mtx); 472155408Srwatson return (error); 473155408Srwatson } 474155408Srwatson } 475155408Srwatson if (ape->ape_record_len <= uio->uio_resid) 476155408Srwatson break; 477155408Srwatson audit_pipe_entry_free(ape); 478155408Srwatson ap->ap_truncates++; 479155408Srwatson } while (1); 480155408Srwatson mtx_unlock(&audit_pipe_mtx); 481155408Srwatson 482155408Srwatson /* 483155408Srwatson * Now read record to user space memory. Even if the read is short, 484155408Srwatson * we abandon the remainder of the record, supporting only discreet 485155408Srwatson * record reads. 486155408Srwatson */ 487155408Srwatson error = uiomove(ape->ape_record, ape->ape_record_len, uio); 488155408Srwatson audit_pipe_entry_free(ape); 489155408Srwatson return (error); 490155408Srwatson} 491155408Srwatson 492155408Srwatson/* 493155408Srwatson * Audit pipe poll. 494155408Srwatson */ 495155408Srwatsonstatic int 496155408Srwatsonaudit_pipe_poll(struct cdev *dev, int events, struct thread *td) 497155408Srwatson{ 498155408Srwatson struct audit_pipe *ap; 499155408Srwatson int revents; 500155408Srwatson 501155408Srwatson revents = 0; 502155408Srwatson ap = dev->si_drv1; 503155408Srwatson KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); 504155408Srwatson if (events & (POLLIN | POLLRDNORM)) { 505155408Srwatson mtx_lock(&audit_pipe_mtx); 506155408Srwatson if (TAILQ_FIRST(&ap->ap_queue) != NULL) 507155408Srwatson revents |= events & (POLLIN | POLLRDNORM); 508155408Srwatson else 509155408Srwatson selrecord(td, &ap->ap_selinfo); 510155408Srwatson mtx_unlock(&audit_pipe_mtx); 511155408Srwatson } 512155408Srwatson return (revents); 513155408Srwatson} 514155408Srwatson 515155408Srwatson/* 516155408Srwatson * Initialize the audit pipe system. 517155408Srwatson */ 518155408Srwatsonstatic void 519155408Srwatsonaudit_pipe_init(void *unused) 520155408Srwatson{ 521155408Srwatson 522155408Srwatson TAILQ_INIT(&audit_pipe_list); 523155408Srwatson mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF); 524155408Srwatson cv_init(&audit_pipe_cv, "audit_pipe_cv"); 525155408Srwatson 526155408Srwatson clone_setup(&audit_pipe_clones); 527155408Srwatson audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, 528155408Srwatson audit_pipe_clone, 0, 1000); 529155408Srwatson if (audit_pipe_eh_tag == NULL) 530155408Srwatson panic("audit_pipe_init: EVENTHANDLER_REGISTER"); 531155408Srwatson} 532155408Srwatson 533155408SrwatsonSYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, 534155408Srwatson NULL); 535