audit_pipe.c revision 155428
142660Smarkm/*- 2146515Sru * Copyright (c) 2006 Robert N. M. Watson 321495Sjmacd * All rights reserved. 442660Smarkm * 521495Sjmacd * This software was developed by Robert Watson for the TrustedBSD Project. 621495Sjmacd * 7146515Sru * Redistribution and use in source and binary forms, with or without 821495Sjmacd * modification, are permitted provided that the following conditions 921495Sjmacd * are met: 1021495Sjmacd * 1. Redistributions of source code must retain the above copyright 1121495Sjmacd * notice, this list of conditions and the following disclaimer. 1221495Sjmacd * 2. Redistributions in binary form must reproduce the above copyright 1321495Sjmacd * notice, this list of conditions and the following disclaimer in the 1421495Sjmacd * documentation and/or other materials provided with the distribution. 1521495Sjmacd * 1621495Sjmacd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1721495Sjmacd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1821495Sjmacd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1921495Sjmacd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2021495Sjmacd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2121495Sjmacd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2221495Sjmacd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2321495Sjmacd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2421495Sjmacd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2542660Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2642660Smarkm * SUCH DAMAGE. 2721495Sjmacd * 28146515Sru * $FreeBSD: head/sys/security/audit/audit_pipe.c 155428 2006-02-07 14:46:26Z rwatson $ 2921495Sjmacd */ 3021495Sjmacd 3121495Sjmacd#include <sys/param.h> 3221495Sjmacd#include <sys/condvar.h> 3321495Sjmacd#include <sys/conf.h> 3421495Sjmacd#include <sys/eventhandler.h> 3521495Sjmacd#include <sys/filio.h> 3621495Sjmacd#include <sys/kernel.h> 3721495Sjmacd#include <sys/lock.h> 3821495Sjmacd#include <sys/malloc.h> 3921495Sjmacd#include <sys/mutex.h> 4021495Sjmacd#include <sys/poll.h> 4121495Sjmacd#include <sys/proc.h> 4221495Sjmacd#include <sys/queue.h> 4321495Sjmacd#include <sys/selinfo.h> 4421495Sjmacd#include <sys/sigio.h> 4521495Sjmacd#include <sys/signal.h> 4621495Sjmacd#include <sys/signalvar.h> 4721495Sjmacd#include <sys/systm.h> 4842660Smarkm#include <sys/uio.h> 4942660Smarkm 5042660Smarkm#include <security/audit/audit.h> 5121495Sjmacd#include <security/audit/audit_private.h> 5221495Sjmacd 5321495Sjmacd/* 5421495Sjmacd * Implementation of a clonable special device providing a live stream of BSM 5521495Sjmacd * audit data. This is a "tee" of the data going to the file. It provides 5621495Sjmacd * unreliable but timely access to audit events. Consumers of this interface 5721495Sjmacd * should be very careful to avoid introducing event cycles. 5842660Smarkm */ 5942660Smarkm 6042660Smarkm/* 6142660Smarkm * Memory types. 6242660Smarkm */ 6342660Smarkmstatic MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes"); 6442660Smarkmstatic MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent", 6542660Smarkm "Audit pipe entries and buffers"); 6642660Smarkm 6742660Smarkm/* 6842660Smarkm * Audit pipe buffer parameters. 6942660Smarkm */ 7042660Smarkm#define AUDIT_PIPE_QLIMIT_DEFAULT (32) 7142660Smarkm#define AUDIT_PIPE_QLIMIT_MAX (1024) 7221495Sjmacd 7321495Sjmacd/* 7421495Sjmacd * Description of an entry in an audit_pipe. 7542660Smarkm */ 7621495Sjmacdstruct audit_pipe_entry { 7721495Sjmacd void *ape_record; 78146515Sru u_int ape_record_len; 79146515Sru TAILQ_ENTRY(audit_pipe_entry) ape_queue; 80146515Sru}; 81146515Sru 82146515Sru/* 83146515Sru * Description of an individual audit_pipe. Consists largely of a bounded 84146515Sru * length queue. 85146515Sru */ 8642660Smarkm#define AUDIT_PIPE_ASYNC 0x00000001 8742660Smarkm#define AUDIT_PIPE_NBIO 0x00000002 8842660Smarkmstruct audit_pipe { 8942660Smarkm int ap_open; /* Device open? */ 9042660Smarkm u_int ap_flags; 9142660Smarkm 9242660Smarkm struct selinfo ap_selinfo; 9321495Sjmacd struct sigio *ap_sigio; 9442660Smarkm 9542660Smarkm u_int ap_qlen; 9642660Smarkm u_int ap_qlimit; 9742660Smarkm 9821495Sjmacd u_int64_t ap_inserts; /* Records added. */ 9921495Sjmacd u_int64_t ap_reads; /* Records read. */ 10021495Sjmacd u_int64_t ap_drops; /* Records dropped. */ 10121495Sjmacd u_int64_t ap_truncates; /* Records too long. */ 10221495Sjmacd 10321495Sjmacd TAILQ_HEAD(, audit_pipe_entry) ap_queue; 10421495Sjmacd 10521495Sjmacd TAILQ_ENTRY(audit_pipe) ap_list; 106146515Sru}; 10721495Sjmacd 10821495Sjmacd/* 10921495Sjmacd * Global list of audit pipes, mutex to protect it and the pipes. Finder 11021495Sjmacd * grained locking may be desirable at some point. 111146515Sru */ 11221495Sjmacdstatic TAILQ_HEAD(, audit_pipe) audit_pipe_list; 11321495Sjmacdstatic struct mtx audit_pipe_mtx; 11421495Sjmacd 11521495Sjmacd/* 11621495Sjmacd * This CV is used to wakeup on an audit record write. Eventually, it should 11721495Sjmacd * probably be per-pipe. 118146515Sru */ 11921495Sjmacdstatic struct cv audit_pipe_cv; 12021495Sjmacd 12121495Sjmacd/* 12221495Sjmacd * Cloning related variables and constants. 123146515Sru */ 12421495Sjmacd#define AUDIT_PIPE_NAME "auditpipe" 12521495Sjmacdstatic eventhandler_tag audit_pipe_eh_tag; 12621495Sjmacdstatic struct clonedevs *audit_pipe_clones; 12721495Sjmacd 12821495Sjmacd/* 12921495Sjmacd * Special device methods and definition. 13021495Sjmacd */ 13121495Sjmacdstatic d_open_t audit_pipe_open; 132146515Srustatic d_close_t audit_pipe_close; 13321495Sjmacdstatic d_read_t audit_pipe_read; 13421495Sjmacdstatic d_ioctl_t audit_pipe_ioctl; 13521495Sjmacdstatic d_poll_t audit_pipe_poll; 13621495Sjmacd 13721495Sjmacdstatic struct cdevsw audit_pipe_cdevsw = { 138146515Sru .d_version = D_VERSION, 13921495Sjmacd .d_flags = D_PSEUDO, 14021495Sjmacd .d_open = audit_pipe_open, 14121495Sjmacd .d_close = audit_pipe_close, 14221495Sjmacd .d_read = audit_pipe_read, 143146515Sru .d_ioctl = audit_pipe_ioctl, 14421495Sjmacd .d_poll = audit_pipe_poll, 14521495Sjmacd .d_name = AUDIT_PIPE_NAME, 146146515Sru}; 14721495Sjmacd 14821495Sjmacd/* 14921495Sjmacd * Some global statistics on audit pipes. 15021495Sjmacd */ 15121495Sjmacdstatic int audit_pipe_count; /* Current number of pipes. */ 15221495Sjmacdstatic u_int64_t audit_pipe_ever; /* Pipes ever allocated. */ 153146515Srustatic u_int64_t audit_pipe_records; /* Records seen. */ 15421495Sjmacdstatic u_int64_t audit_pipe_drops; /* Global record drop count. */ 15521495Sjmacd 15621495Sjmacd/* 157146515Sru * Free an audit pipe entry. 15821495Sjmacd */ 15921495Sjmacdstatic void 160146515Sruaudit_pipe_entry_free(struct audit_pipe_entry *ape) 16121495Sjmacd{ 16221495Sjmacd 163146515Sru free(ape->ape_record, M_AUDIT_PIPE_ENTRY); 16421495Sjmacd free(ape, M_AUDIT_PIPE_ENTRY); 16521495Sjmacd} 166146515Sru 16721495Sjmacd/* 16821495Sjmacd * Apparent individual record to a queue -- allocate queue-local buffer, and 16921495Sjmacd * add to the queue. We try to drop from the head of the queue so that more 170146515Sru * recent events take precedence over older ones, but if allocation fails we 17121495Sjmacd * do drop the new event. 17221495Sjmacd */ 173146515Srustatic void 17421495Sjmacdaudit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len) 17521495Sjmacd{ 176146515Sru struct audit_pipe_entry *ape, *ape_remove; 177146515Sru 17821495Sjmacd mtx_assert(&audit_pipe_mtx, MA_OWNED); 17921495Sjmacd 180146515Sru ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO); 18121495Sjmacd if (ape == NULL) { 18221495Sjmacd ap->ap_drops++; 183146515Sru return; 18421495Sjmacd } 18521495Sjmacd 186146515Sru ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT); 18721495Sjmacd if (ape->ape_record == NULL) { 18821495Sjmacd free(ape, M_AUDIT_PIPE_ENTRY); 18921495Sjmacd ap->ap_drops++; 19021495Sjmacd audit_pipe_drops++; 19121495Sjmacd return; 192146515Sru } 19321495Sjmacd 19421495Sjmacd bcopy(record, ape->ape_record, record_len); 19521495Sjmacd ape->ape_record_len = record_len; 19621495Sjmacd 19721495Sjmacd if (ap->ap_qlen >= ap->ap_qlimit) { 198146515Sru ape_remove = TAILQ_FIRST(&ap->ap_queue); 199146515Sru TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue); 20021495Sjmacd audit_pipe_entry_free(ape_remove); 20121495Sjmacd ap->ap_qlen--; 20221495Sjmacd ap->ap_drops++; 203146515Sru audit_pipe_drops++; 20421495Sjmacd } 20521495Sjmacd 20621495Sjmacd TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue); 207146515Sru ap->ap_inserts++; 20821495Sjmacd ap->ap_qlen++; 20921495Sjmacd selwakeuppri(&ap->ap_selinfo, PSOCK); 21021495Sjmacd if (ap->ap_flags & AUDIT_PIPE_ASYNC) 211146515Sru pgsigio(&ap->ap_sigio, SIGIO, 0); 21221495Sjmacd} 21321495Sjmacd 214146515Sru/* 21521495Sjmacd * audit_pipe_submit(): audit_worker submits audit records via this 21621495Sjmacd * interface, which arranges for them to be delivered to pipe queues. 21721495Sjmacd */ 218146515Sruvoid 21921495Sjmacdaudit_pipe_submit(void *record, u_int record_len) 22021495Sjmacd{ 22121495Sjmacd struct audit_pipe *ap; 222146515Sru 22321495Sjmacd /* 22421495Sjmacd * Lockless read to avoid mutex overhead if pipes are not in use. 225146515Sru */ 22621495Sjmacd if (TAILQ_FIRST(&audit_pipe_list) == NULL) 22721495Sjmacd return; 228146515Sru 22921495Sjmacd mtx_lock(&audit_pipe_mtx); 23021495Sjmacd TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) 231146515Sru audit_pipe_append(ap, record, record_len); 23221495Sjmacd audit_pipe_records++; 23321495Sjmacd mtx_unlock(&audit_pipe_mtx); 234146515Sru cv_signal(&audit_pipe_cv); 235146515Sru} 23621495Sjmacd 23721495Sjmacd/* 23821495Sjmacd * Read the next record off of an audit pipe. 239146515Sru */ 24021495Sjmacdstatic struct audit_pipe_entry * 24142660Smarkmaudit_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