audit_pipe.c revision 156884
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 156884 2006-03-19 15:39:03Z 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> 51156880Srwatson#include <security/audit/audit_ioctl.h> 52155408Srwatson#include <security/audit/audit_private.h> 53155408Srwatson 54155408Srwatson/* 55155408Srwatson * Implementation of a clonable special device providing a live stream of BSM 56155408Srwatson * audit data. This is a "tee" of the data going to the file. It provides 57155408Srwatson * unreliable but timely access to audit events. Consumers of this interface 58155408Srwatson * should be very careful to avoid introducing event cycles. 59155408Srwatson */ 60155408Srwatson 61155408Srwatson/* 62155408Srwatson * Memory types. 63155408Srwatson */ 64155408Srwatsonstatic MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 65155408Srwatsonstatic MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 66155408Srwatson "Audit pipe entries and buffers"); 67155408Srwatson 68155408Srwatson/* 69155408Srwatson * Audit pipe buffer parameters. 70155408Srwatson */ 71156883Srwatson#define AUDIT_PIPE_QLIMIT_DEFAULT (128) 72156880Srwatson#define AUDIT_PIPE_QLIMIT_MIN (0) 73155408Srwatson#define AUDIT_PIPE_QLIMIT_MAX (1024) 74155408Srwatson 75155408Srwatson/* 76155408Srwatson * Description of an entry in an audit_pipe. 77155408Srwatson */ 78155408Srwatsonstruct audit_pipe_entry { 79155408Srwatson void *ape_record; 80155408Srwatson u_int ape_record_len; 81155408Srwatson TAILQ_ENTRY(audit_pipe_entry) ape_queue; 82155408Srwatson}; 83155408Srwatson 84155408Srwatson/* 85155408Srwatson * Description of an individual audit_pipe. Consists largely of a bounded 86155408Srwatson * length queue. 87155408Srwatson */ 88155408Srwatson#define AUDIT_PIPE_ASYNC 0x00000001 89155408Srwatson#define AUDIT_PIPE_NBIO 0x00000002 90155408Srwatsonstruct audit_pipe { 91155408Srwatson int ap_open; /* Device open? */ 92155408Srwatson u_int ap_flags; 93155408Srwatson 94155408Srwatson struct selinfo ap_selinfo; 95155408Srwatson struct sigio *ap_sigio; 96155408Srwatson 97155408Srwatson u_int ap_qlen; 98155408Srwatson u_int ap_qlimit; 99155408Srwatson 100155408Srwatson u_int64_t ap_inserts; /* Records added. */ 101155408Srwatson u_int64_t ap_reads; /* Records read. */ 102155408Srwatson u_int64_t ap_drops; /* Records dropped. */ 103155408Srwatson u_int64_t ap_truncates; /* Records too long. */ 104155408Srwatson 105155408Srwatson TAILQ_HEAD(, audit_pipe_entry) ap_queue; 106155408Srwatson 107155408Srwatson TAILQ_ENTRY(audit_pipe) ap_list; 108155408Srwatson}; 109155408Srwatson 110155408Srwatson/* 111155408Srwatson * Global list of audit pipes, mutex to protect it and the pipes. Finder 112155408Srwatson * grained locking may be desirable at some point. 113155408Srwatson */ 114155408Srwatsonstatic TAILQ_HEAD(, audit_pipe) audit_pipe_list; 115155408Srwatsonstatic struct mtx audit_pipe_mtx; 116155408Srwatson 117155408Srwatson/* 118155408Srwatson * This CV is used to wakeup on an audit record write. Eventually, it should 119155408Srwatson * probably be per-pipe. 120155408Srwatson */ 121155408Srwatsonstatic struct cv audit_pipe_cv; 122155408Srwatson 123155408Srwatson/* 124155408Srwatson * Cloning related variables and constants. 125155408Srwatson */ 126155408Srwatson#define AUDIT_PIPE_NAME "auditpipe" 127155408Srwatsonstatic eventhandler_tag audit_pipe_eh_tag; 128155408Srwatsonstatic struct clonedevs *audit_pipe_clones; 129155408Srwatson 130155408Srwatson/* 131155408Srwatson * Special device methods and definition. 132155408Srwatson */ 133155408Srwatsonstatic d_open_t audit_pipe_open; 134155408Srwatsonstatic d_close_t audit_pipe_close; 135155408Srwatsonstatic d_read_t audit_pipe_read; 136155408Srwatsonstatic d_ioctl_t audit_pipe_ioctl; 137155408Srwatsonstatic d_poll_t audit_pipe_poll; 138155408Srwatson 139155408Srwatsonstatic struct cdevsw audit_pipe_cdevsw = { 140155408Srwatson .d_version = D_VERSION, 141155408Srwatson .d_flags = D_PSEUDO, 142155408Srwatson .d_open = audit_pipe_open, 143155408Srwatson .d_close = audit_pipe_close, 144155408Srwatson .d_read = audit_pipe_read, 145155408Srwatson .d_ioctl = audit_pipe_ioctl, 146155408Srwatson .d_poll = audit_pipe_poll, 147155408Srwatson .d_name = AUDIT_PIPE_NAME, 148155408Srwatson}; 149155408Srwatson 150155408Srwatson/* 151155408Srwatson * Some global statistics on audit pipes. 152155408Srwatson */ 153155408Srwatsonstatic int audit_pipe_count; /* Current number of pipes. */ 154155408Srwatsonstatic u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 155155408Srwatsonstatic u_int64_t audit_pipe_records; /* Records seen. */ 156155408Srwatsonstatic u_int64_t audit_pipe_drops; /* Global record drop count. */ 157155408Srwatson 158155408Srwatson/* 159155408Srwatson * Free an audit pipe entry. 160155408Srwatson */ 161155408Srwatsonstatic void 162155408Srwatsonaudit_pipe_entry_free(struct audit_pipe_entry *ape) 163155408Srwatson{ 164155408Srwatson 165155408Srwatson free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 166155408Srwatson free(ape, M_AUDIT_PIPE_ENTRY); 167155408Srwatson} 168155408Srwatson 169155408Srwatson/* 170155408Srwatson * Apparent individual record to a queue -- allocate queue-local buffer, and 171155408Srwatson * add to the queue. We try to drop from the head of the queue so that more 172155408Srwatson * recent events take precedence over older ones, but if allocation fails we 173155408Srwatson * do drop the new event. 174155408Srwatson */ 175155408Srwatsonstatic void 176155408Srwatsonaudit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 177155408Srwatson{ 178155408Srwatson struct audit_pipe_entry *ape, *ape_remove; 179155408Srwatson 180155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 181155408Srwatson 182155408Srwatson ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 183155408Srwatson if (ape == NULL) { 184155408Srwatson ap->ap_drops++; 185156292Srwatson audit_pipe_drops++; 186155408Srwatson return; 187155408Srwatson } 188155408Srwatson 189155408Srwatson ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 190155408Srwatson if (ape->ape_record == NULL) { 191155408Srwatson free(ape, M_AUDIT_PIPE_ENTRY); 192155408Srwatson ap->ap_drops++; 193155408Srwatson audit_pipe_drops++; 194155408Srwatson return; 195155408Srwatson } 196155408Srwatson 197155408Srwatson bcopy(record, ape->ape_record, record_len); 198155408Srwatson ape->ape_record_len = record_len; 199155408Srwatson 200155408Srwatson if (ap->ap_qlen >= ap->ap_qlimit) { 201155408Srwatson ape_remove = TAILQ_FIRST(&ap->ap_queue); 202155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); 203155408Srwatson audit_pipe_entry_free(ape_remove); 204155428Srwatson ap->ap_qlen--; 205155408Srwatson ap->ap_drops++; 206155408Srwatson audit_pipe_drops++; 207155408Srwatson } 208155408Srwatson 209155408Srwatson TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 210155408Srwatson ap->ap_inserts++; 211155408Srwatson ap->ap_qlen++; 212155408Srwatson selwakeuppri(&ap->ap_selinfo, PSOCK); 213155408Srwatson if (ap->ap_flags & AUDIT_PIPE_ASYNC) 214155408Srwatson pgsigio(&ap->ap_sigio, SIGIO, 0); 215155408Srwatson} 216155408Srwatson 217155408Srwatson/* 218155408Srwatson * audit_pipe_submit(): audit_worker submits audit records via this 219155408Srwatson * interface, which arranges for them to be delivered to pipe queues. 220155408Srwatson */ 221155408Srwatsonvoid 222155408Srwatsonaudit_pipe_submit(void *record, u_int record_len) 223155408Srwatson{ 224155408Srwatson struct audit_pipe *ap; 225155408Srwatson 226155408Srwatson /* 227155408Srwatson * Lockless read to avoid mutex overhead if pipes are not in use. 228155408Srwatson */ 229155408Srwatson if (TAILQ_FIRST(&audit_pipe_list) == NULL) 230155408Srwatson return; 231155408Srwatson 232155408Srwatson mtx_lock(&audit_pipe_mtx); 233155408Srwatson TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) 234155408Srwatson audit_pipe_append(ap, record, record_len); 235155408Srwatson audit_pipe_records++; 236155408Srwatson mtx_unlock(&audit_pipe_mtx); 237155408Srwatson cv_signal(&audit_pipe_cv); 238155408Srwatson} 239155408Srwatson 240155408Srwatson/* 241155408Srwatson * Read the next record off of an audit pipe. 242155408Srwatson */ 243155408Srwatsonstatic struct audit_pipe_entry * 244155408Srwatsonaudit_pipe_pop(struct audit_pipe *ap) 245155408Srwatson{ 246155408Srwatson struct audit_pipe_entry *ape; 247155408Srwatson 248155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 249155408Srwatson 250155408Srwatson ape = TAILQ_FIRST(&ap->ap_queue); 251155408Srwatson KASSERT((ape == NULL && ap->ap_qlen == 0) || 252155408Srwatson (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen")); 253155408Srwatson if (ape == NULL) 254155408Srwatson return (NULL); 255155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 256155408Srwatson ap->ap_qlen--; 257155408Srwatson return (ape); 258155408Srwatson} 259155408Srwatson 260155408Srwatson/* 261155408Srwatson * Allocate a new audit pipe. Connects the pipe, on success, to the global 262155408Srwatson * list and updates statistics. 263155408Srwatson */ 264155408Srwatsonstatic struct audit_pipe * 265155408Srwatsonaudit_pipe_alloc(void) 266155408Srwatson{ 267155408Srwatson struct audit_pipe *ap; 268155408Srwatson 269155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 270155408Srwatson 271155408Srwatson ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); 272155408Srwatson if (ap == NULL) 273155408Srwatson return (NULL); 274155408Srwatson ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; 275155408Srwatson TAILQ_INIT(&ap->ap_queue); 276155408Srwatson TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); 277155408Srwatson audit_pipe_count++; 278155408Srwatson audit_pipe_ever++; 279155408Srwatson return (ap); 280155408Srwatson} 281155408Srwatson 282155408Srwatson/* 283155408Srwatson * Free an audit pipe. Assumes mutex is held, audit_pipe is still on the 284155408Srwatson * global list. Frees any audit pipe entries in the queue. 285155408Srwatson */ 286155408Srwatsonstatic void 287155408Srwatsonaudit_pipe_free(struct audit_pipe *ap) 288155408Srwatson{ 289155408Srwatson struct audit_pipe_entry *ape; 290155408Srwatson 291155408Srwatson mtx_assert(&audit_pipe_mtx, MA_OWNED); 292155408Srwatson 293155408Srwatson TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); 294155408Srwatson while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { 295155408Srwatson TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 296155408Srwatson audit_pipe_entry_free(ape); 297155408Srwatson ap->ap_qlen--; 298155408Srwatson } 299155408Srwatson KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen")); 300155408Srwatson free(ap, M_AUDIT_PIPE); 301155408Srwatson audit_pipe_count--; 302155408Srwatson} 303155408Srwatson 304155408Srwatson/* 305155408Srwatson * Audit pipe clone routine -- provide specific requested audit pipe, or a 306155408Srwatson * fresh one if a specific one is not requested. 307155408Srwatson */ 308155408Srwatsonstatic void 309155408Srwatsonaudit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, 310155408Srwatson struct cdev **dev) 311155408Srwatson{ 312155408Srwatson int i, u; 313155408Srwatson 314155408Srwatson if (*dev != NULL) 315155408Srwatson return; 316155408Srwatson 317155408Srwatson if (strcmp(name, AUDIT_PIPE_NAME) == 0) 318155408Srwatson u = -1; 319155408Srwatson else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) 320155408Srwatson return; 321155408Srwatson 322155408Srwatson i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); 323155408Srwatson if (i) { 324155408Srwatson *dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT, 325155408Srwatson GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); 326155408Srwatson if (*dev != NULL) { 327155408Srwatson dev_ref(*dev); 328155408Srwatson (*dev)->si_flags |= SI_CHEAPCLONE; 329155408Srwatson } 330155408Srwatson } 331155408Srwatson} 332155408Srwatson 333155408Srwatson/* 334155408Srwatson * Audit pipe open method. Explicit suser check isn't used as this allows 335155408Srwatson * file permissions on the special device to be used to grant audit review 336155408Srwatson * access. 337155408Srwatson */ 338155408Srwatsonstatic int 339155408Srwatsonaudit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 340155408Srwatson{ 341155408Srwatson struct audit_pipe *ap; 342155408Srwatson 343155408Srwatson mtx_lock(&audit_pipe_mtx); 344155408Srwatson ap = dev->si_drv1; 345155408Srwatson if (ap == NULL) { 346155408Srwatson ap = audit_pipe_alloc(); 347155408Srwatson if (ap == NULL) { 348155408Srwatson mtx_unlock(&audit_pipe_mtx); 349155408Srwatson return (ENOMEM); 350155408Srwatson } 351155408Srwatson dev->si_drv1 = ap; 352155408Srwatson } else { 353155408Srwatson KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); 354155408Srwatson mtx_unlock(&audit_pipe_mtx); 355155408Srwatson return (EBUSY); 356155408Srwatson } 357155408Srwatson ap->ap_open = 1; 358155408Srwatson mtx_unlock(&audit_pipe_mtx); 359155408Srwatson fsetown(td->td_proc->p_pid, &ap->ap_sigio); 360155408Srwatson return (0); 361155408Srwatson} 362155408Srwatson 363155408Srwatson/* 364155408Srwatson * Close audit pipe, tear down all records, etc. 365155408Srwatson */ 366155408Srwatsonstatic int 367155408Srwatsonaudit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 368155408Srwatson{ 369155408Srwatson struct audit_pipe *ap; 370155408Srwatson 371155408Srwatson ap = dev->si_drv1; 372155408Srwatson KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); 373155408Srwatson KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); 374155408Srwatson funsetown(&ap->ap_sigio); 375155408Srwatson mtx_lock(&audit_pipe_mtx); 376155408Srwatson ap->ap_open = 0; 377155408Srwatson audit_pipe_free(ap); 378155408Srwatson dev->si_drv1 = NULL; 379155408Srwatson mtx_unlock(&audit_pipe_mtx); 380155408Srwatson return (0); 381155408Srwatson} 382155408Srwatson 383155408Srwatson/* 384156880Srwatson * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer 385156880Srwatson * commands. 386155408Srwatson * 387155408Srwatson * Would be desirable to support filtering, although perhaps something simple 388155408Srwatson * like an event mask, as opposed to something complicated like BPF. 389155408Srwatson */ 390155408Srwatsonstatic int 391155408Srwatsonaudit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 392155408Srwatson struct thread *td) 393155408Srwatson{ 394155408Srwatson struct audit_pipe *ap; 395155408Srwatson int error; 396155408Srwatson 397155408Srwatson ap = dev->si_drv1; 398155408Srwatson KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); 399155408Srwatson switch (cmd) { 400155408Srwatson case FIONBIO: 401155408Srwatson mtx_lock(&audit_pipe_mtx); 402155408Srwatson if (*(int *)data) 403155408Srwatson ap->ap_flags |= AUDIT_PIPE_NBIO; 404155408Srwatson else 405155408Srwatson ap->ap_flags &= ~AUDIT_PIPE_NBIO; 406155408Srwatson mtx_unlock(&audit_pipe_mtx); 407155408Srwatson error = 0; 408155408Srwatson break; 409155408Srwatson 410155408Srwatson case FIONREAD: 411155408Srwatson mtx_lock(&audit_pipe_mtx); 412155408Srwatson if (TAILQ_FIRST(&ap->ap_queue) != NULL) 413155408Srwatson *(int *)data = 414155408Srwatson TAILQ_FIRST(&ap->ap_queue)->ape_record_len; 415155408Srwatson else 416155408Srwatson *(int *)data = 0; 417155408Srwatson mtx_unlock(&audit_pipe_mtx); 418155408Srwatson error = 0; 419155408Srwatson break; 420155408Srwatson 421155408Srwatson case FIOASYNC: 422155408Srwatson mtx_lock(&audit_pipe_mtx); 423155408Srwatson if (*(int *)data) 424155408Srwatson ap->ap_flags |= AUDIT_PIPE_ASYNC; 425155408Srwatson else 426155408Srwatson ap->ap_flags &= ~AUDIT_PIPE_ASYNC; 427155408Srwatson mtx_unlock(&audit_pipe_mtx); 428155408Srwatson error = 0; 429155408Srwatson break; 430155408Srwatson 431155408Srwatson case FIOSETOWN: 432155408Srwatson error = fsetown(*(int *)data, &ap->ap_sigio); 433155408Srwatson break; 434155408Srwatson 435155408Srwatson case FIOGETOWN: 436155408Srwatson *(int *)data = fgetown(&ap->ap_sigio); 437155408Srwatson error = 0; 438156880Srwatson break; 439155408Srwatson 440156880Srwatson case AUDITPIPE_GET_QLEN: 441156880Srwatson *(u_int *)data = ap->ap_qlen; 442156880Srwatson error = 0; 443156880Srwatson break; 444156880Srwatson 445156880Srwatson case AUDITPIPE_GET_QLIMIT: 446156880Srwatson *(u_int *)data = ap->ap_qlimit; 447156880Srwatson error = 0; 448156880Srwatson break; 449156880Srwatson 450156880Srwatson case AUDITPIPE_SET_QLIMIT: 451156880Srwatson /* Lockless integer write. */ 452156880Srwatson if (*(u_int *)data >= AUDIT_PIPE_QLIMIT_MIN || 453156880Srwatson *(u_int *)data <= AUDIT_PIPE_QLIMIT_MAX) { 454156880Srwatson ap->ap_qlimit = *(u_int *)data; 455156880Srwatson error = 0; 456156880Srwatson } else 457156880Srwatson error = EINVAL; 458156880Srwatson break; 459156880Srwatson 460156884Srwatson case AUDITPIPE_GET_QLIMIT_MIN: 461156884Srwatson *(u_int *)data = AUDIT_PIPE_QLIMIT_MIN; 462156884Srwatson error = 0; 463156884Srwatson break; 464156884Srwatson 465156884Srwatson case AUDITPIPE_GET_QLIMIT_MAX: 466156884Srwatson *(u_int *)data = AUDIT_PIPE_QLIMIT_MAX; 467156884Srwatson error = 0; 468156884Srwatson break; 469156884Srwatson 470156880Srwatson case AUDITPIPE_GET_INSERTS: 471156880Srwatson *(u_int *)data = ap->ap_inserts; 472156880Srwatson error = 0; 473156880Srwatson break; 474156880Srwatson 475156880Srwatson case AUDITPIPE_GET_READS: 476156880Srwatson *(u_int *)data = ap->ap_reads; 477156880Srwatson error = 0; 478156880Srwatson break; 479156880Srwatson 480156880Srwatson case AUDITPIPE_GET_DROPS: 481156880Srwatson *(u_int *)data = ap->ap_drops; 482156880Srwatson error = 0; 483156880Srwatson break; 484156880Srwatson 485156880Srwatson case AUDITPIPE_GET_TRUNCATES: 486156880Srwatson *(u_int *)data = ap->ap_truncates; 487156880Srwatson error = 0; 488156880Srwatson break; 489156880Srwatson 490155408Srwatson default: 491155408Srwatson error = ENOTTY; 492155408Srwatson } 493155408Srwatson return (error); 494155408Srwatson} 495155408Srwatson 496155408Srwatson/* 497155408Srwatson * Audit pipe read. Pull one record off the queue and copy to user space. 498155408Srwatson * On error, the record is dropped. 499155408Srwatson */ 500155408Srwatsonstatic int 501155408Srwatsonaudit_pipe_read(struct cdev *dev, struct uio *uio, int flag) 502155408Srwatson{ 503155408Srwatson struct audit_pipe_entry *ape; 504155408Srwatson struct audit_pipe *ap; 505155408Srwatson int error; 506155408Srwatson 507155408Srwatson ap = dev->si_drv1; 508155408Srwatson KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); 509155408Srwatson mtx_lock(&audit_pipe_mtx); 510155408Srwatson do { 511155408Srwatson /* 512155408Srwatson * Wait for a record that fits into the read buffer, dropping 513155408Srwatson * records that would be truncated if actually passed to the 514155408Srwatson * process. This helps maintain the discreet record read 515155408Srwatson * interface. 516155408Srwatson */ 517155408Srwatson while ((ape = audit_pipe_pop(ap)) == NULL) { 518155408Srwatson if (ap->ap_flags & AUDIT_PIPE_NBIO) { 519155408Srwatson mtx_unlock(&audit_pipe_mtx); 520155408Srwatson return (EAGAIN); 521155408Srwatson } 522155408Srwatson error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); 523155408Srwatson if (error) { 524155408Srwatson mtx_unlock(&audit_pipe_mtx); 525155408Srwatson return (error); 526155408Srwatson } 527155408Srwatson } 528155408Srwatson if (ape->ape_record_len <= uio->uio_resid) 529155408Srwatson break; 530155408Srwatson audit_pipe_entry_free(ape); 531155408Srwatson ap->ap_truncates++; 532155408Srwatson } while (1); 533155408Srwatson mtx_unlock(&audit_pipe_mtx); 534155408Srwatson 535155408Srwatson /* 536155408Srwatson * Now read record to user space memory. Even if the read is short, 537155408Srwatson * we abandon the remainder of the record, supporting only discreet 538155408Srwatson * record reads. 539155408Srwatson */ 540155408Srwatson error = uiomove(ape->ape_record, ape->ape_record_len, uio); 541155408Srwatson audit_pipe_entry_free(ape); 542155408Srwatson return (error); 543155408Srwatson} 544155408Srwatson 545155408Srwatson/* 546155408Srwatson * Audit pipe poll. 547155408Srwatson */ 548155408Srwatsonstatic int 549155408Srwatsonaudit_pipe_poll(struct cdev *dev, int events, struct thread *td) 550155408Srwatson{ 551155408Srwatson struct audit_pipe *ap; 552155408Srwatson int revents; 553155408Srwatson 554155408Srwatson revents = 0; 555155408Srwatson ap = dev->si_drv1; 556155408Srwatson KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); 557155408Srwatson if (events & (POLLIN | POLLRDNORM)) { 558155408Srwatson mtx_lock(&audit_pipe_mtx); 559155408Srwatson if (TAILQ_FIRST(&ap->ap_queue) != NULL) 560155408Srwatson revents |= events & (POLLIN | POLLRDNORM); 561155408Srwatson else 562155408Srwatson selrecord(td, &ap->ap_selinfo); 563155408Srwatson mtx_unlock(&audit_pipe_mtx); 564155408Srwatson } 565155408Srwatson return (revents); 566155408Srwatson} 567155408Srwatson 568155408Srwatson/* 569155408Srwatson * Initialize the audit pipe system. 570155408Srwatson */ 571155408Srwatsonstatic void 572155408Srwatsonaudit_pipe_init(void *unused) 573155408Srwatson{ 574155408Srwatson 575155408Srwatson TAILQ_INIT(&audit_pipe_list); 576155408Srwatson mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF); 577155408Srwatson cv_init(&audit_pipe_cv, "audit_pipe_cv"); 578155408Srwatson 579155408Srwatson clone_setup(&audit_pipe_clones); 580155408Srwatson audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, 581155408Srwatson audit_pipe_clone, 0, 1000); 582155408Srwatson if (audit_pipe_eh_tag == NULL) 583155408Srwatson panic("audit_pipe_init: EVENTHANDLER_REGISTER"); 584155408Srwatson} 585155408Srwatson 586155408SrwatsonSYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, 587155408Srwatson NULL); 588