audit_pipe.c revision 155428
1/*- 2 * Copyright (c) 2006 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: head/sys/security/audit/audit_pipe.c 155428 2006-02-07 14:46:26Z rwatson $ 29 */ 30 31#include <sys/param.h> 32#include <sys/condvar.h> 33#include <sys/conf.h> 34#include <sys/eventhandler.h> 35#include <sys/filio.h> 36#include <sys/kernel.h> 37#include <sys/lock.h> 38#include <sys/malloc.h> 39#include <sys/mutex.h> 40#include <sys/poll.h> 41#include <sys/proc.h> 42#include <sys/queue.h> 43#include <sys/selinfo.h> 44#include <sys/sigio.h> 45#include <sys/signal.h> 46#include <sys/signalvar.h> 47#include <sys/systm.h> 48#include <sys/uio.h> 49 50#include <security/audit/audit.h> 51#include <security/audit/audit_private.h> 52 53/* 54 * Implementation of a clonable special device providing a live stream of BSM 55 * audit data. This is a "tee" of the data going to the file. It provides 56 * unreliable but timely access to audit events. Consumers of this interface 57 * should be very careful to avoid introducing event cycles. 58 */ 59 60/* 61 * Memory types. 62 */ 63static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 64static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 65 "Audit pipe entries and buffers"); 66 67/* 68 * Audit pipe buffer parameters. 69 */ 70#define AUDIT_PIPE_QLIMIT_DEFAULT (32) 71#define AUDIT_PIPE_QLIMIT_MAX (1024) 72 73/* 74 * Description of an entry in an audit_pipe. 75 */ 76struct audit_pipe_entry { 77 void *ape_record; 78 u_int ape_record_len; 79 TAILQ_ENTRY(audit_pipe_entry) ape_queue; 80}; 81 82/* 83 * Description of an individual audit_pipe. Consists largely of a bounded 84 * length queue. 85 */ 86#define AUDIT_PIPE_ASYNC 0x00000001 87#define AUDIT_PIPE_NBIO 0x00000002 88struct audit_pipe { 89 int ap_open; /* Device open? */ 90 u_int ap_flags; 91 92 struct selinfo ap_selinfo; 93 struct sigio *ap_sigio; 94 95 u_int ap_qlen; 96 u_int ap_qlimit; 97 98 u_int64_t ap_inserts; /* Records added. */ 99 u_int64_t ap_reads; /* Records read. */ 100 u_int64_t ap_drops; /* Records dropped. */ 101 u_int64_t ap_truncates; /* Records too long. */ 102 103 TAILQ_HEAD(, audit_pipe_entry) ap_queue; 104 105 TAILQ_ENTRY(audit_pipe) ap_list; 106}; 107 108/* 109 * Global list of audit pipes, mutex to protect it and the pipes. Finder 110 * grained locking may be desirable at some point. 111 */ 112static TAILQ_HEAD(, audit_pipe) audit_pipe_list; 113static struct mtx audit_pipe_mtx; 114 115/* 116 * This CV is used to wakeup on an audit record write. Eventually, it should 117 * probably be per-pipe. 118 */ 119static struct cv audit_pipe_cv; 120 121/* 122 * Cloning related variables and constants. 123 */ 124#define AUDIT_PIPE_NAME "auditpipe" 125static eventhandler_tag audit_pipe_eh_tag; 126static struct clonedevs *audit_pipe_clones; 127 128/* 129 * Special device methods and definition. 130 */ 131static d_open_t audit_pipe_open; 132static d_close_t audit_pipe_close; 133static d_read_t audit_pipe_read; 134static d_ioctl_t audit_pipe_ioctl; 135static d_poll_t audit_pipe_poll; 136 137static struct cdevsw audit_pipe_cdevsw = { 138 .d_version = D_VERSION, 139 .d_flags = D_PSEUDO, 140 .d_open = audit_pipe_open, 141 .d_close = audit_pipe_close, 142 .d_read = audit_pipe_read, 143 .d_ioctl = audit_pipe_ioctl, 144 .d_poll = audit_pipe_poll, 145 .d_name = AUDIT_PIPE_NAME, 146}; 147 148/* 149 * Some global statistics on audit pipes. 150 */ 151static int audit_pipe_count; /* Current number of pipes. */ 152static u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 153static u_int64_t audit_pipe_records; /* Records seen. */ 154static u_int64_t audit_pipe_drops; /* Global record drop count. */ 155 156/* 157 * Free an audit pipe entry. 158 */ 159static void 160audit_pipe_entry_free(struct audit_pipe_entry *ape) 161{ 162 163 free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 164 free(ape, M_AUDIT_PIPE_ENTRY); 165} 166 167/* 168 * Apparent individual record to a queue -- allocate queue-local buffer, and 169 * add to the queue. We try to drop from the head of the queue so that more 170 * recent events take precedence over older ones, but if allocation fails we 171 * do drop the new event. 172 */ 173static void 174audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 175{ 176 struct audit_pipe_entry *ape, *ape_remove; 177 178 mtx_assert(&audit_pipe_mtx, MA_OWNED); 179 180 ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 181 if (ape == NULL) { 182 ap->ap_drops++; 183 return; 184 } 185 186 ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 187 if (ape->ape_record == NULL) { 188 free(ape, M_AUDIT_PIPE_ENTRY); 189 ap->ap_drops++; 190 audit_pipe_drops++; 191 return; 192 } 193 194 bcopy(record, ape->ape_record, record_len); 195 ape->ape_record_len = record_len; 196 197 if (ap->ap_qlen >= ap->ap_qlimit) { 198 ape_remove = TAILQ_FIRST(&ap->ap_queue); 199 TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); 200 audit_pipe_entry_free(ape_remove); 201 ap->ap_qlen--; 202 ap->ap_drops++; 203 audit_pipe_drops++; 204 } 205 206 TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 207 ap->ap_inserts++; 208 ap->ap_qlen++; 209 selwakeuppri(&ap->ap_selinfo, PSOCK); 210 if (ap->ap_flags & AUDIT_PIPE_ASYNC) 211 pgsigio(&ap->ap_sigio, SIGIO, 0); 212} 213 214/* 215 * audit_pipe_submit(): audit_worker submits audit records via this 216 * interface, which arranges for them to be delivered to pipe queues. 217 */ 218void 219audit_pipe_submit(void *record, u_int record_len) 220{ 221 struct audit_pipe *ap; 222 223 /* 224 * Lockless read to avoid mutex overhead if pipes are not in use. 225 */ 226 if (TAILQ_FIRST(&audit_pipe_list) == NULL) 227 return; 228 229 mtx_lock(&audit_pipe_mtx); 230 TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) 231 audit_pipe_append(ap, record, record_len); 232 audit_pipe_records++; 233 mtx_unlock(&audit_pipe_mtx); 234 cv_signal(&audit_pipe_cv); 235} 236 237/* 238 * Read the next record off of an audit pipe. 239 */ 240static struct audit_pipe_entry * 241audit_pipe_pop(struct audit_pipe *ap) 242{ 243 struct audit_pipe_entry *ape; 244 245 mtx_assert(&audit_pipe_mtx, MA_OWNED); 246 247 ape = TAILQ_FIRST(&ap->ap_queue); 248 KASSERT((ape == NULL && ap->ap_qlen == 0) || 249 (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen")); 250 if (ape == NULL) 251 return (NULL); 252 TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 253 ap->ap_qlen--; 254 return (ape); 255} 256 257/* 258 * Allocate a new audit pipe. Connects the pipe, on success, to the global 259 * list and updates statistics. 260 */ 261static struct audit_pipe * 262audit_pipe_alloc(void) 263{ 264 struct audit_pipe *ap; 265 266 mtx_assert(&audit_pipe_mtx, MA_OWNED); 267 268 ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); 269 if (ap == NULL) 270 return (NULL); 271 ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; 272 TAILQ_INIT(&ap->ap_queue); 273 TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); 274 audit_pipe_count++; 275 audit_pipe_ever++; 276 return (ap); 277} 278 279/* 280 * Free an audit pipe. Assumes mutex is held, audit_pipe is still on the 281 * global list. Frees any audit pipe entries in the queue. 282 */ 283static void 284audit_pipe_free(struct audit_pipe *ap) 285{ 286 struct audit_pipe_entry *ape; 287 288 mtx_assert(&audit_pipe_mtx, MA_OWNED); 289 290 TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); 291 while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { 292 TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 293 audit_pipe_entry_free(ape); 294 ap->ap_qlen--; 295 } 296 KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen")); 297 free(ap, M_AUDIT_PIPE); 298 audit_pipe_count--; 299} 300 301/* 302 * Audit pipe clone routine -- provide specific requested audit pipe, or a 303 * fresh one if a specific one is not requested. 304 */ 305static void 306audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, 307 struct cdev **dev) 308{ 309 int i, u; 310 311 if (*dev != NULL) 312 return; 313 314 if (strcmp(name, AUDIT_PIPE_NAME) == 0) 315 u = -1; 316 else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) 317 return; 318 319 i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); 320 if (i) { 321 *dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT, 322 GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); 323 if (*dev != NULL) { 324 dev_ref(*dev); 325 (*dev)->si_flags |= SI_CHEAPCLONE; 326 } 327 } 328} 329 330/* 331 * Audit pipe open method. Explicit suser check isn't used as this allows 332 * file permissions on the special device to be used to grant audit review 333 * access. 334 */ 335static int 336audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 337{ 338 struct audit_pipe *ap; 339 340 mtx_lock(&audit_pipe_mtx); 341 ap = dev->si_drv1; 342 if (ap == NULL) { 343 ap = audit_pipe_alloc(); 344 if (ap == NULL) { 345 mtx_unlock(&audit_pipe_mtx); 346 return (ENOMEM); 347 } 348 dev->si_drv1 = ap; 349 } else { 350 KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); 351 mtx_unlock(&audit_pipe_mtx); 352 return (EBUSY); 353 } 354 ap->ap_open = 1; 355 mtx_unlock(&audit_pipe_mtx); 356 fsetown(td->td_proc->p_pid, &ap->ap_sigio); 357 return (0); 358} 359 360/* 361 * Close audit pipe, tear down all records, etc. 362 */ 363static int 364audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 365{ 366 struct audit_pipe *ap; 367 368 ap = dev->si_drv1; 369 KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); 370 KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); 371 funsetown(&ap->ap_sigio); 372 mtx_lock(&audit_pipe_mtx); 373 ap->ap_open = 0; 374 audit_pipe_free(ap); 375 dev->si_drv1 = NULL; 376 mtx_unlock(&audit_pipe_mtx); 377 return (0); 378} 379 380/* 381 * Audit pipe ioctl() routine. Nothing for now, but eventually will allow 382 * setting and retrieval of current queue depth, queue limit, flush, etc. 383 * 384 * Would be desirable to support filtering, although perhaps something simple 385 * like an event mask, as opposed to something complicated like BPF. 386 */ 387static int 388audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 389 struct thread *td) 390{ 391 struct audit_pipe *ap; 392 int error; 393 394 ap = dev->si_drv1; 395 KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); 396 switch (cmd) { 397 case FIONBIO: 398 mtx_lock(&audit_pipe_mtx); 399 if (*(int *)data) 400 ap->ap_flags |= AUDIT_PIPE_NBIO; 401 else 402 ap->ap_flags &= ~AUDIT_PIPE_NBIO; 403 mtx_unlock(&audit_pipe_mtx); 404 error = 0; 405 break; 406 407 case FIONREAD: 408 mtx_lock(&audit_pipe_mtx); 409 if (TAILQ_FIRST(&ap->ap_queue) != NULL) 410 *(int *)data = 411 TAILQ_FIRST(&ap->ap_queue)->ape_record_len; 412 else 413 *(int *)data = 0; 414 mtx_unlock(&audit_pipe_mtx); 415 error = 0; 416 break; 417 418 case FIOASYNC: 419 mtx_lock(&audit_pipe_mtx); 420 if (*(int *)data) 421 ap->ap_flags |= AUDIT_PIPE_ASYNC; 422 else 423 ap->ap_flags &= ~AUDIT_PIPE_ASYNC; 424 mtx_unlock(&audit_pipe_mtx); 425 error = 0; 426 break; 427 428 case FIOSETOWN: 429 error = fsetown(*(int *)data, &ap->ap_sigio); 430 break; 431 432 case FIOGETOWN: 433 *(int *)data = fgetown(&ap->ap_sigio); 434 error = 0; 435 436 default: 437 error = ENOTTY; 438 } 439 return (error); 440} 441 442/* 443 * Audit pipe read. Pull one record off the queue and copy to user space. 444 * On error, the record is dropped. 445 */ 446static int 447audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) 448{ 449 struct audit_pipe_entry *ape; 450 struct audit_pipe *ap; 451 int error; 452 453 ap = dev->si_drv1; 454 KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); 455 mtx_lock(&audit_pipe_mtx); 456 do { 457 /* 458 * Wait for a record that fits into the read buffer, dropping 459 * records that would be truncated if actually passed to the 460 * process. This helps maintain the discreet record read 461 * interface. 462 */ 463 while ((ape = audit_pipe_pop(ap)) == NULL) { 464 if (ap->ap_flags & AUDIT_PIPE_NBIO) { 465 mtx_unlock(&audit_pipe_mtx); 466 return (EAGAIN); 467 } 468 error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); 469 if (error) { 470 mtx_unlock(&audit_pipe_mtx); 471 return (error); 472 } 473 } 474 if (ape->ape_record_len <= uio->uio_resid) 475 break; 476 audit_pipe_entry_free(ape); 477 ap->ap_truncates++; 478 } while (1); 479 mtx_unlock(&audit_pipe_mtx); 480 481 /* 482 * Now read record to user space memory. Even if the read is short, 483 * we abandon the remainder of the record, supporting only discreet 484 * record reads. 485 */ 486 error = uiomove(ape->ape_record, ape->ape_record_len, uio); 487 audit_pipe_entry_free(ape); 488 return (error); 489} 490 491/* 492 * Audit pipe poll. 493 */ 494static int 495audit_pipe_poll(struct cdev *dev, int events, struct thread *td) 496{ 497 struct audit_pipe *ap; 498 int revents; 499 500 revents = 0; 501 ap = dev->si_drv1; 502 KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); 503 if (events & (POLLIN | POLLRDNORM)) { 504 mtx_lock(&audit_pipe_mtx); 505 if (TAILQ_FIRST(&ap->ap_queue) != NULL) 506 revents |= events & (POLLIN | POLLRDNORM); 507 else 508 selrecord(td, &ap->ap_selinfo); 509 mtx_unlock(&audit_pipe_mtx); 510 } 511 return (revents); 512} 513 514/* 515 * Initialize the audit pipe system. 516 */ 517static void 518audit_pipe_init(void *unused) 519{ 520 521 TAILQ_INIT(&audit_pipe_list); 522 mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF); 523 cv_init(&audit_pipe_cv, "audit_pipe_cv"); 524 525 clone_setup(&audit_pipe_clones); 526 audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, 527 audit_pipe_clone, 0, 1000); 528 if (audit_pipe_eh_tag == NULL) 529 panic("audit_pipe_init: EVENTHANDLER_REGISTER"); 530} 531 532SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, 533 NULL); 534