audit_pipe.c revision 156883
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 156883 2006-03-19 15:38:03Z 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_ioctl.h> 52#include <security/audit/audit_private.h> 53 54/* 55 * Implementation of a clonable special device providing a live stream of BSM 56 * audit data. This is a "tee" of the data going to the file. It provides 57 * unreliable but timely access to audit events. Consumers of this interface 58 * should be very careful to avoid introducing event cycles. 59 */ 60 61/* 62 * Memory types. 63 */ 64static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 65static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 66 "Audit pipe entries and buffers"); 67 68/* 69 * Audit pipe buffer parameters. 70 */ 71#define AUDIT_PIPE_QLIMIT_DEFAULT (128) 72#define AUDIT_PIPE_QLIMIT_MIN (0) 73#define AUDIT_PIPE_QLIMIT_MAX (1024) 74 75/* 76 * Description of an entry in an audit_pipe. 77 */ 78struct audit_pipe_entry { 79 void *ape_record; 80 u_int ape_record_len; 81 TAILQ_ENTRY(audit_pipe_entry) ape_queue; 82}; 83 84/* 85 * Description of an individual audit_pipe. Consists largely of a bounded 86 * length queue. 87 */ 88#define AUDIT_PIPE_ASYNC 0x00000001 89#define AUDIT_PIPE_NBIO 0x00000002 90struct audit_pipe { 91 int ap_open; /* Device open? */ 92 u_int ap_flags; 93 94 struct selinfo ap_selinfo; 95 struct sigio *ap_sigio; 96 97 u_int ap_qlen; 98 u_int ap_qlimit; 99 100 u_int64_t ap_inserts; /* Records added. */ 101 u_int64_t ap_reads; /* Records read. */ 102 u_int64_t ap_drops; /* Records dropped. */ 103 u_int64_t ap_truncates; /* Records too long. */ 104 105 TAILQ_HEAD(, audit_pipe_entry) ap_queue; 106 107 TAILQ_ENTRY(audit_pipe) ap_list; 108}; 109 110/* 111 * Global list of audit pipes, mutex to protect it and the pipes. Finder 112 * grained locking may be desirable at some point. 113 */ 114static TAILQ_HEAD(, audit_pipe) audit_pipe_list; 115static struct mtx audit_pipe_mtx; 116 117/* 118 * This CV is used to wakeup on an audit record write. Eventually, it should 119 * probably be per-pipe. 120 */ 121static struct cv audit_pipe_cv; 122 123/* 124 * Cloning related variables and constants. 125 */ 126#define AUDIT_PIPE_NAME "auditpipe" 127static eventhandler_tag audit_pipe_eh_tag; 128static struct clonedevs *audit_pipe_clones; 129 130/* 131 * Special device methods and definition. 132 */ 133static d_open_t audit_pipe_open; 134static d_close_t audit_pipe_close; 135static d_read_t audit_pipe_read; 136static d_ioctl_t audit_pipe_ioctl; 137static d_poll_t audit_pipe_poll; 138 139static struct cdevsw audit_pipe_cdevsw = { 140 .d_version = D_VERSION, 141 .d_flags = D_PSEUDO, 142 .d_open = audit_pipe_open, 143 .d_close = audit_pipe_close, 144 .d_read = audit_pipe_read, 145 .d_ioctl = audit_pipe_ioctl, 146 .d_poll = audit_pipe_poll, 147 .d_name = AUDIT_PIPE_NAME, 148}; 149 150/* 151 * Some global statistics on audit pipes. 152 */ 153static int audit_pipe_count; /* Current number of pipes. */ 154static u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 155static u_int64_t audit_pipe_records; /* Records seen. */ 156static u_int64_t audit_pipe_drops; /* Global record drop count. */ 157 158/* 159 * Free an audit pipe entry. 160 */ 161static void 162audit_pipe_entry_free(struct audit_pipe_entry *ape) 163{ 164 165 free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 166 free(ape, M_AUDIT_PIPE_ENTRY); 167} 168 169/* 170 * Apparent individual record to a queue -- allocate queue-local buffer, and 171 * add to the queue. We try to drop from the head of the queue so that more 172 * recent events take precedence over older ones, but if allocation fails we 173 * do drop the new event. 174 */ 175static void 176audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 177{ 178 struct audit_pipe_entry *ape, *ape_remove; 179 180 mtx_assert(&audit_pipe_mtx, MA_OWNED); 181 182 ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 183 if (ape == NULL) { 184 ap->ap_drops++; 185 audit_pipe_drops++; 186 return; 187 } 188 189 ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 190 if (ape->ape_record == NULL) { 191 free(ape, M_AUDIT_PIPE_ENTRY); 192 ap->ap_drops++; 193 audit_pipe_drops++; 194 return; 195 } 196 197 bcopy(record, ape->ape_record, record_len); 198 ape->ape_record_len = record_len; 199 200 if (ap->ap_qlen >= ap->ap_qlimit) { 201 ape_remove = TAILQ_FIRST(&ap->ap_queue); 202 TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); 203 audit_pipe_entry_free(ape_remove); 204 ap->ap_qlen--; 205 ap->ap_drops++; 206 audit_pipe_drops++; 207 } 208 209 TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 210 ap->ap_inserts++; 211 ap->ap_qlen++; 212 selwakeuppri(&ap->ap_selinfo, PSOCK); 213 if (ap->ap_flags & AUDIT_PIPE_ASYNC) 214 pgsigio(&ap->ap_sigio, SIGIO, 0); 215} 216 217/* 218 * audit_pipe_submit(): audit_worker submits audit records via this 219 * interface, which arranges for them to be delivered to pipe queues. 220 */ 221void 222audit_pipe_submit(void *record, u_int record_len) 223{ 224 struct audit_pipe *ap; 225 226 /* 227 * Lockless read to avoid mutex overhead if pipes are not in use. 228 */ 229 if (TAILQ_FIRST(&audit_pipe_list) == NULL) 230 return; 231 232 mtx_lock(&audit_pipe_mtx); 233 TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) 234 audit_pipe_append(ap, record, record_len); 235 audit_pipe_records++; 236 mtx_unlock(&audit_pipe_mtx); 237 cv_signal(&audit_pipe_cv); 238} 239 240/* 241 * Read the next record off of an audit pipe. 242 */ 243static struct audit_pipe_entry * 244audit_pipe_pop(struct audit_pipe *ap) 245{ 246 struct audit_pipe_entry *ape; 247 248 mtx_assert(&audit_pipe_mtx, MA_OWNED); 249 250 ape = TAILQ_FIRST(&ap->ap_queue); 251 KASSERT((ape == NULL && ap->ap_qlen == 0) || 252 (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen")); 253 if (ape == NULL) 254 return (NULL); 255 TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 256 ap->ap_qlen--; 257 return (ape); 258} 259 260/* 261 * Allocate a new audit pipe. Connects the pipe, on success, to the global 262 * list and updates statistics. 263 */ 264static struct audit_pipe * 265audit_pipe_alloc(void) 266{ 267 struct audit_pipe *ap; 268 269 mtx_assert(&audit_pipe_mtx, MA_OWNED); 270 271 ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO); 272 if (ap == NULL) 273 return (NULL); 274 ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT; 275 TAILQ_INIT(&ap->ap_queue); 276 TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list); 277 audit_pipe_count++; 278 audit_pipe_ever++; 279 return (ap); 280} 281 282/* 283 * Free an audit pipe. Assumes mutex is held, audit_pipe is still on the 284 * global list. Frees any audit pipe entries in the queue. 285 */ 286static void 287audit_pipe_free(struct audit_pipe *ap) 288{ 289 struct audit_pipe_entry *ape; 290 291 mtx_assert(&audit_pipe_mtx, MA_OWNED); 292 293 TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); 294 while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) { 295 TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue); 296 audit_pipe_entry_free(ape); 297 ap->ap_qlen--; 298 } 299 KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen")); 300 free(ap, M_AUDIT_PIPE); 301 audit_pipe_count--; 302} 303 304/* 305 * Audit pipe clone routine -- provide specific requested audit pipe, or a 306 * fresh one if a specific one is not requested. 307 */ 308static void 309audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen, 310 struct cdev **dev) 311{ 312 int i, u; 313 314 if (*dev != NULL) 315 return; 316 317 if (strcmp(name, AUDIT_PIPE_NAME) == 0) 318 u = -1; 319 else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1) 320 return; 321 322 i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0); 323 if (i) { 324 *dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT, 325 GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u); 326 if (*dev != NULL) { 327 dev_ref(*dev); 328 (*dev)->si_flags |= SI_CHEAPCLONE; 329 } 330 } 331} 332 333/* 334 * Audit pipe open method. Explicit suser check isn't used as this allows 335 * file permissions on the special device to be used to grant audit review 336 * access. 337 */ 338static int 339audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 340{ 341 struct audit_pipe *ap; 342 343 mtx_lock(&audit_pipe_mtx); 344 ap = dev->si_drv1; 345 if (ap == NULL) { 346 ap = audit_pipe_alloc(); 347 if (ap == NULL) { 348 mtx_unlock(&audit_pipe_mtx); 349 return (ENOMEM); 350 } 351 dev->si_drv1 = ap; 352 } else { 353 KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open")); 354 mtx_unlock(&audit_pipe_mtx); 355 return (EBUSY); 356 } 357 ap->ap_open = 1; 358 mtx_unlock(&audit_pipe_mtx); 359 fsetown(td->td_proc->p_pid, &ap->ap_sigio); 360 return (0); 361} 362 363/* 364 * Close audit pipe, tear down all records, etc. 365 */ 366static int 367audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 368{ 369 struct audit_pipe *ap; 370 371 ap = dev->si_drv1; 372 KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL")); 373 KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open")); 374 funsetown(&ap->ap_sigio); 375 mtx_lock(&audit_pipe_mtx); 376 ap->ap_open = 0; 377 audit_pipe_free(ap); 378 dev->si_drv1 = NULL; 379 mtx_unlock(&audit_pipe_mtx); 380 return (0); 381} 382 383/* 384 * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer 385 * commands. 386 * 387 * Would be desirable to support filtering, although perhaps something simple 388 * like an event mask, as opposed to something complicated like BPF. 389 */ 390static int 391audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 392 struct thread *td) 393{ 394 struct audit_pipe *ap; 395 int error; 396 397 ap = dev->si_drv1; 398 KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL")); 399 switch (cmd) { 400 case FIONBIO: 401 mtx_lock(&audit_pipe_mtx); 402 if (*(int *)data) 403 ap->ap_flags |= AUDIT_PIPE_NBIO; 404 else 405 ap->ap_flags &= ~AUDIT_PIPE_NBIO; 406 mtx_unlock(&audit_pipe_mtx); 407 error = 0; 408 break; 409 410 case FIONREAD: 411 mtx_lock(&audit_pipe_mtx); 412 if (TAILQ_FIRST(&ap->ap_queue) != NULL) 413 *(int *)data = 414 TAILQ_FIRST(&ap->ap_queue)->ape_record_len; 415 else 416 *(int *)data = 0; 417 mtx_unlock(&audit_pipe_mtx); 418 error = 0; 419 break; 420 421 case FIOASYNC: 422 mtx_lock(&audit_pipe_mtx); 423 if (*(int *)data) 424 ap->ap_flags |= AUDIT_PIPE_ASYNC; 425 else 426 ap->ap_flags &= ~AUDIT_PIPE_ASYNC; 427 mtx_unlock(&audit_pipe_mtx); 428 error = 0; 429 break; 430 431 case FIOSETOWN: 432 error = fsetown(*(int *)data, &ap->ap_sigio); 433 break; 434 435 case FIOGETOWN: 436 *(int *)data = fgetown(&ap->ap_sigio); 437 error = 0; 438 break; 439 440 case AUDITPIPE_GET_QLEN: 441 *(u_int *)data = ap->ap_qlen; 442 error = 0; 443 break; 444 445 case AUDITPIPE_GET_QLIMIT: 446 *(u_int *)data = ap->ap_qlimit; 447 error = 0; 448 break; 449 450 case AUDITPIPE_SET_QLIMIT: 451 /* Lockless integer write. */ 452 if (*(u_int *)data >= AUDIT_PIPE_QLIMIT_MIN || 453 *(u_int *)data <= AUDIT_PIPE_QLIMIT_MAX) { 454 ap->ap_qlimit = *(u_int *)data; 455 error = 0; 456 } else 457 error = EINVAL; 458 break; 459 460 case AUDITPIPE_GET_INSERTS: 461 *(u_int *)data = ap->ap_inserts; 462 error = 0; 463 break; 464 465 case AUDITPIPE_GET_READS: 466 *(u_int *)data = ap->ap_reads; 467 error = 0; 468 break; 469 470 case AUDITPIPE_GET_DROPS: 471 *(u_int *)data = ap->ap_drops; 472 error = 0; 473 break; 474 475 case AUDITPIPE_GET_TRUNCATES: 476 *(u_int *)data = ap->ap_truncates; 477 error = 0; 478 break; 479 480 default: 481 error = ENOTTY; 482 } 483 return (error); 484} 485 486/* 487 * Audit pipe read. Pull one record off the queue and copy to user space. 488 * On error, the record is dropped. 489 */ 490static int 491audit_pipe_read(struct cdev *dev, struct uio *uio, int flag) 492{ 493 struct audit_pipe_entry *ape; 494 struct audit_pipe *ap; 495 int error; 496 497 ap = dev->si_drv1; 498 KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL")); 499 mtx_lock(&audit_pipe_mtx); 500 do { 501 /* 502 * Wait for a record that fits into the read buffer, dropping 503 * records that would be truncated if actually passed to the 504 * process. This helps maintain the discreet record read 505 * interface. 506 */ 507 while ((ape = audit_pipe_pop(ap)) == NULL) { 508 if (ap->ap_flags & AUDIT_PIPE_NBIO) { 509 mtx_unlock(&audit_pipe_mtx); 510 return (EAGAIN); 511 } 512 error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx); 513 if (error) { 514 mtx_unlock(&audit_pipe_mtx); 515 return (error); 516 } 517 } 518 if (ape->ape_record_len <= uio->uio_resid) 519 break; 520 audit_pipe_entry_free(ape); 521 ap->ap_truncates++; 522 } while (1); 523 mtx_unlock(&audit_pipe_mtx); 524 525 /* 526 * Now read record to user space memory. Even if the read is short, 527 * we abandon the remainder of the record, supporting only discreet 528 * record reads. 529 */ 530 error = uiomove(ape->ape_record, ape->ape_record_len, uio); 531 audit_pipe_entry_free(ape); 532 return (error); 533} 534 535/* 536 * Audit pipe poll. 537 */ 538static int 539audit_pipe_poll(struct cdev *dev, int events, struct thread *td) 540{ 541 struct audit_pipe *ap; 542 int revents; 543 544 revents = 0; 545 ap = dev->si_drv1; 546 KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL")); 547 if (events & (POLLIN | POLLRDNORM)) { 548 mtx_lock(&audit_pipe_mtx); 549 if (TAILQ_FIRST(&ap->ap_queue) != NULL) 550 revents |= events & (POLLIN | POLLRDNORM); 551 else 552 selrecord(td, &ap->ap_selinfo); 553 mtx_unlock(&audit_pipe_mtx); 554 } 555 return (revents); 556} 557 558/* 559 * Initialize the audit pipe system. 560 */ 561static void 562audit_pipe_init(void *unused) 563{ 564 565 TAILQ_INIT(&audit_pipe_list); 566 mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF); 567 cv_init(&audit_pipe_cv, "audit_pipe_cv"); 568 569 clone_setup(&audit_pipe_clones); 570 audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone, 571 audit_pipe_clone, 0, 1000); 572 if (audit_pipe_eh_tag == NULL) 573 panic("audit_pipe_init: EVENTHANDLER_REGISTER"); 574} 575 576SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init, 577 NULL); 578