1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Threads: 27 * 28 * auditd is thread 0 and does signal handling 29 * 30 * input() is a door server that receives binary audit records and 31 * queues them for handling by an instance of process() for conversion to syslog 32 * message(s). There is one process thread per plugin. 33 * 34 * Queues: 35 * 36 * Each plugin has a buffer pool and and queue for feeding the 37 * the process threads. The input thread moves buffers from the pool 38 * to the queue and the process thread puts them back. 39 * 40 * Another pool, b_pool, contains buffers referenced by each of the 41 * process queues; this is to minimize the number of buffer copies 42 * 43 */ 44 45 #include <arpa/inet.h> 46 #include <assert.h> 47 #include <bsm/adt.h> 48 #include <dlfcn.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <libintl.h> 52 #include <pthread.h> 53 #include <secdb.h> 54 #include <security/auditd.h> 55 #include <signal.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <syslog.h> 60 #include <sys/socket.h> 61 #include <sys/types.h> 62 #include <sys/stat.h> 63 #include <unistd.h> 64 #include <audit_plugin.h> /* libbsm */ 65 #include "plugin.h" 66 #include <bsm/audit_door_infc.h> 67 #include "queue.h" 68 69 #define DEBUG 0 70 71 /* gettext() obfuscation routine for lint */ 72 #ifdef __lint 73 #define gettext(x) x 74 #endif 75 76 #if DEBUG 77 static FILE *dbfp; 78 #define DUMP(w, x, y, z) dump_state(w, x, y, z) 79 #define DPRINT(x) { (void) fprintf x; } 80 #else 81 #define DUMP(w, x, y, z) 82 #define DPRINT(x) 83 #endif 84 85 #define FATAL_MESSAGE_LEN 256 86 87 #define MIN_RECORD_SIZE (size_t)25 88 89 #define INPUT_MIN 2 90 #define THRESHOLD_PCT 75 91 #define DEFAULT_BUF_SZ (size_t)250 92 #define BASE_PRIORITY 10 /* 0 - 20 valid for user, time share */ 93 #define HIGH_PRIORITY BASE_PRIORITY - 1 94 95 static thr_data_t in_thr; /* input thread locks and data */ 96 static int doorfd = -1; 97 98 static int largest_queue = INPUT_MIN; 99 static au_queue_t b_pool; 100 static int b_allocated = 0; 101 static pthread_mutex_t b_alloc_lock; 102 static pthread_mutex_t b_refcnt_lock; 103 104 static void input(void *, void *, int, door_desc_t *, int); 105 static void *process(void *); 106 107 static audit_q_t *qpool_withdraw(plugin_t *); 108 static void qpool_init(plugin_t *, int); 109 static void qpool_return(plugin_t *, audit_q_t *); 110 static void qpool_close(plugin_t *); 111 112 static audit_rec_t *bpool_withdraw(char *, size_t, size_t); 113 static void bpool_init(); 114 static void bpool_return(audit_rec_t *); 115 116 /* 117 * warn_or_fatal() -- log daemon error and (optionally) exit 118 */ 119 static void 120 warn_or_fatal(int fatal, char *parting_shot) 121 { 122 char *severity; 123 char message[512]; 124 125 if (fatal) 126 severity = gettext("fatal error"); 127 else 128 severity = gettext("warning"); 129 130 (void) snprintf(message, 512, "%s: %s", severity, parting_shot); 131 132 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 133 LOG_DAEMON, LOG_ALERT, message); 134 135 DPRINT((dbfp, "auditd warn_or_fatal %s: %s\n", severity, parting_shot)); 136 if (fatal) 137 auditd_exit(1); 138 } 139 140 /* Internal to doorway.c errors... */ 141 #define INTERNAL_LOAD_ERROR -1 142 #define INTERNAL_SYS_ERROR -2 143 #define INTERNAL_CONFIG_ERROR -3 144 145 /* 146 * report_error -- handle errors returned by plugin 147 * 148 * rc is plugin's return code if it is a non-negative value, 149 * otherwise it is a doorway.c code about a plugin. 150 */ 151 static void 152 report_error(int rc, char *error_text, char *plugin_path) 153 { 154 int warn = 0; 155 char rcbuf[100]; /* short error name string */ 156 char message[FATAL_MESSAGE_LEN]; 157 int bad_count = 0; 158 char *name; 159 char empty[] = ".."; 160 161 static int no_plug = 0; 162 static int no_load = 0; 163 static int no_thread; 164 static int no_memory = 0; 165 static int invalid = 0; 166 static int retry = 0; 167 static int fail = 0; 168 169 name = plugin_path; 170 if (error_text == NULL) 171 error_text = empty; 172 if (name == NULL) 173 name = empty; 174 175 switch (rc) { 176 case INTERNAL_LOAD_ERROR: 177 warn = 1; 178 bad_count = ++no_load; 179 (void) strcpy(rcbuf, "load_error"); 180 break; 181 case INTERNAL_SYS_ERROR: 182 warn = 1; 183 bad_count = ++no_thread; 184 (void) strcpy(rcbuf, "sys_error"); 185 break; 186 case INTERNAL_CONFIG_ERROR: 187 warn = 1; 188 bad_count = ++no_plug; 189 (void) strcpy(rcbuf, "config_error"); 190 name = strdup("--"); 191 break; 192 case AUDITD_SUCCESS: 193 break; 194 case AUDITD_NO_MEMORY: /* no_memory */ 195 warn = 1; 196 bad_count = ++no_memory; 197 (void) strcpy(rcbuf, "no_memory"); 198 break; 199 case AUDITD_INVALID: /* invalid */ 200 warn = 1; 201 bad_count = ++invalid; 202 (void) strcpy(rcbuf, "invalid"); 203 break; 204 case AUDITD_RETRY: 205 warn = 1; 206 bad_count = ++retry; 207 (void) strcpy(rcbuf, "retry"); 208 break; 209 case AUDITD_COMM_FAIL: /* comm_fail */ 210 (void) strcpy(rcbuf, "comm_fail"); 211 break; 212 case AUDITD_FATAL: /* failure */ 213 warn = 1; 214 bad_count = ++fail; 215 (void) strcpy(rcbuf, "failure"); 216 break; 217 default: 218 (void) strcpy(rcbuf, "error"); 219 break; 220 } 221 DPRINT((dbfp, "report_error(%d - %s): %s\n\t%s\n", 222 bad_count, name, rcbuf, error_text)); 223 if (warn) 224 __audit_dowarn2("plugin", name, rcbuf, error_text, bad_count); 225 else { 226 (void) snprintf(message, FATAL_MESSAGE_LEN, 227 gettext("audit plugin %s reported error = \"%s\": %s\n"), 228 name, rcbuf, error_text); 229 warn_or_fatal(0, message); 230 } 231 } 232 233 static size_t 234 getlen(char *buf) 235 { 236 adr_t adr; 237 char tokenid; 238 uint32_t len; 239 240 adr.adr_now = buf; 241 adr.adr_stream = buf; 242 243 adrm_char(&adr, &tokenid, 1); 244 if ((tokenid == AUT_OHEADER) || (tokenid == AUT_HEADER32) || 245 (tokenid == AUT_HEADER32_EX) || (tokenid == AUT_HEADER64) || 246 (tokenid == AUT_HEADER64_EX)) { 247 adrm_u_int32(&adr, &len, 1); 248 249 return (len); 250 } 251 DPRINT((dbfp, "getlen() is not looking at a header token\n")); 252 253 return (0); 254 } 255 256 /* 257 * load_function - call dlsym() to resolve the function address 258 */ 259 static int 260 load_function(plugin_t *p, char *name, auditd_rc_t (**func)()) 261 { 262 *func = (auditd_rc_t (*)())dlsym(p->plg_dlptr, name); 263 if (*func == NULL) { 264 char message[FATAL_MESSAGE_LEN]; 265 char *errmsg = dlerror(); 266 267 (void) snprintf(message, FATAL_MESSAGE_LEN, 268 gettext("dlsym failed %s: error %s"), 269 name, errmsg != NULL ? errmsg : gettext("Unknown error\n")); 270 271 warn_or_fatal(0, message); 272 return (-1); 273 } 274 return (0); 275 } 276 277 /* 278 * load the auditd plug in 279 */ 280 static int 281 load_plugin(plugin_t *p) 282 { 283 struct stat64 stat; 284 int fd; 285 int fail = 0; 286 287 /* 288 * Stat the file so we can check modes and ownerships 289 */ 290 if ((fd = open(p->plg_path, O_NONBLOCK | O_RDONLY)) != -1) { 291 if ((fstat64(fd, &stat) == -1) || (!S_ISREG(stat.st_mode))) 292 fail = 1; 293 } else 294 fail = 1; 295 if (fail) { 296 char message[FATAL_MESSAGE_LEN]; 297 298 (void) snprintf(message, FATAL_MESSAGE_LEN, 299 gettext("auditd plugin: stat(%s) failed: %s\n"), 300 p->plg_path, strerror(errno)); 301 302 warn_or_fatal(0, message); 303 return (-1); 304 } 305 /* 306 * Check the ownership of the file 307 */ 308 if (stat.st_uid != (uid_t)0) { 309 char message[FATAL_MESSAGE_LEN]; 310 311 (void) snprintf(message, FATAL_MESSAGE_LEN, 312 gettext( 313 "auditd plugin: Owner of the module %s is not root\n"), 314 p->plg_path); 315 316 warn_or_fatal(0, message); 317 return (-1); 318 } 319 /* 320 * Check the modes on the file 321 */ 322 if (stat.st_mode&S_IWGRP) { 323 char message[FATAL_MESSAGE_LEN]; 324 325 (void) snprintf(message, FATAL_MESSAGE_LEN, 326 gettext("auditd plugin: module %s writable by group\n"), 327 p->plg_path); 328 329 warn_or_fatal(0, message); 330 return (-1); 331 } 332 if (stat.st_mode&S_IWOTH) { 333 char message[FATAL_MESSAGE_LEN]; 334 335 (void) snprintf(message, FATAL_MESSAGE_LEN, 336 gettext("auditd plugin: module %s writable by world\n"), 337 p->plg_path); 338 339 warn_or_fatal(0, message); 340 return (-1); 341 } 342 /* 343 * Open the plugin 344 */ 345 p->plg_dlptr = dlopen(p->plg_path, RTLD_LAZY); 346 347 if (p->plg_dlptr == NULL) { 348 char message[FATAL_MESSAGE_LEN]; 349 char *errmsg = dlerror(); 350 351 (void) snprintf(message, FATAL_MESSAGE_LEN, 352 gettext("plugin load %s failed: %s\n"), 353 p->plg_path, errmsg != NULL ? errmsg : 354 gettext("Unknown error\n")); 355 356 warn_or_fatal(0, message); 357 return (-1); 358 } 359 if (load_function(p, "auditd_plugin", &(p->plg_fplugin))) 360 return (-1); 361 362 if (load_function(p, "auditd_plugin_open", &(p->plg_fplugin_open))) 363 return (-1); 364 365 if (load_function(p, "auditd_plugin_close", &(p->plg_fplugin_close))) 366 return (-1); 367 368 return (0); 369 } 370 371 /* 372 * unload_plugin() unlinks and frees the plugin_t structure after 373 * freeing buffers and structures that hang off it. It also dlcloses 374 * the referenced plugin. The return is the next entry, which may be NULL 375 * 376 * hold plugin_mutex for this call 377 */ 378 static plugin_t * 379 unload_plugin(plugin_t *p) 380 { 381 plugin_t *q, **r; 382 383 assert(pthread_mutex_trylock(&plugin_mutex) != 0); 384 385 DPRINT((dbfp, "unload_plugin: removing %s\n", p->plg_path)); 386 387 _kva_free(p->plg_kvlist); /* _kva_free accepts NULL */ 388 qpool_close(p); /* qpool_close accepts NULL pool, queue */ 389 DPRINT((dbfp, "unload_plugin: %s structure removed\n", p->plg_path)); 390 391 (void) dlclose(p->plg_dlptr); 392 393 DPRINT((dbfp, "unload_plugin: %s dlclosed\n", p->plg_path)); 394 free(p->plg_path); 395 396 (void) pthread_mutex_destroy(&(p->plg_mutex)); 397 (void) pthread_cond_destroy(&(p->plg_cv)); 398 399 q = plugin_head; 400 r = &plugin_head; 401 while (q != NULL) { 402 if (q == p) { 403 *r = p->plg_next; 404 free(p); 405 break; 406 } 407 r = &(q->plg_next); 408 q = q->plg_next; 409 } 410 return (*r); 411 } 412 413 /* 414 * process return values from plugin_open 415 * 416 * presently no attribute is defined. 417 */ 418 /* ARGSUSED */ 419 static void 420 open_return(plugin_t *p, char *attrval) 421 { 422 } 423 424 /* 425 * auditd_thread_init 426 * - create threads 427 * - load plugins 428 * 429 * auditd_thread_init is called at auditd startup with an initial list 430 * of plugins and again each time audit catches a SIGHUP or SIGUSR1. 431 */ 432 int 433 auditd_thread_init() 434 { 435 int threshold; 436 auditd_rc_t rc; 437 plugin_t *p; 438 char *open_params; 439 char *error_string; 440 int plugin_count = 0; 441 static int threads_ready = 0; 442 443 if (!threads_ready) { 444 struct sched_param param; 445 #if DEBUG 446 dbfp = __auditd_debug_file_open(); 447 #endif 448 doorfd = door_create((void(*)())input, 0, 449 DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 450 if (doorfd < 0) 451 return (1); /* can't create door -> fatal */ 452 453 param.sched_priority = BASE_PRIORITY; 454 (void) pthread_setschedparam(pthread_self(), SCHED_OTHER, 455 ¶m); 456 457 /* input door server */ 458 (void) pthread_mutex_init(&(in_thr.thd_mutex), NULL); 459 (void) pthread_cond_init(&(in_thr.thd_cv), NULL); 460 in_thr.thd_waiting = 0; 461 462 bpool_init(); 463 } 464 p = plugin_head; 465 while (p != NULL) { 466 if (p->plg_removed) { 467 DPRINT((dbfp, "start removing %s\n", p->plg_path)); 468 /* tell process(p) to exit and dlclose */ 469 (void) pthread_cond_signal(&(p->plg_cv)); 470 } else if (!p->plg_initialized) { 471 DPRINT((dbfp, "start initial load of %s\n", 472 p->plg_path)); 473 if (load_plugin(p)) { 474 report_error(INTERNAL_LOAD_ERROR, 475 gettext("dynamic load failed"), 476 p->plg_path); 477 p = unload_plugin(p); 478 continue; 479 } 480 open_params = NULL; 481 error_string = NULL; 482 if ((rc = p->plg_fplugin_open( 483 p->plg_kvlist, 484 &open_params, &error_string)) != AUDITD_SUCCESS) { 485 report_error(rc, error_string, p->plg_path); 486 free(error_string); 487 p = unload_plugin(p); 488 continue; 489 } 490 open_return(p, open_params); 491 p->plg_reopen = 0; 492 493 threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100; 494 p->plg_qmin = INPUT_MIN; 495 496 DPRINT((dbfp, 497 "calling qpool_init for %s with qmax=%d\n", 498 p->plg_path, p->plg_qmax)); 499 500 qpool_init(p, threshold); 501 audit_queue_init(&(p->plg_queue)); 502 p->plg_initialized = 1; 503 504 (void) pthread_mutex_init(&(p->plg_mutex), NULL); 505 (void) pthread_cond_init(&(p->plg_cv), NULL); 506 p->plg_waiting = 0; 507 508 if (pthread_create(&(p->plg_tid), NULL, process, p)) { 509 report_error(INTERNAL_SYS_ERROR, 510 gettext("thread creation failed"), 511 p->plg_path); 512 p = unload_plugin(p); 513 continue; 514 } 515 } else if (p->plg_reopen) { 516 DPRINT((dbfp, "reopen %s\n", p->plg_path)); 517 error_string = NULL; 518 if ((rc = p->plg_fplugin_open(p->plg_kvlist, 519 &open_params, &error_string)) != AUDITD_SUCCESS) { 520 report_error(rc, error_string, p->plg_path); 521 free(error_string); 522 p = unload_plugin(p); 523 continue; 524 } 525 open_return(p, open_params); 526 p->plg_reopen = 0; 527 528 DPRINT((dbfp, "%s qmax=%d\n", 529 p->plg_path, p->plg_qmax)); 530 531 } 532 p->plg_q_threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100; 533 534 p = p->plg_next; 535 plugin_count++; 536 } 537 if (plugin_count == 0) { 538 report_error(INTERNAL_CONFIG_ERROR, 539 gettext("No plugins are configured"), NULL); 540 return (-1); 541 } 542 if (!threads_ready) { 543 /* unleash the kernel */ 544 rc = auditdoor(doorfd); 545 546 DPRINT((dbfp, "%d returned from auditdoor.\n", 547 rc)); 548 if (rc != 0) 549 return (1); /* fatal */ 550 551 threads_ready = 1; 552 } 553 return (0); 554 } 555 556 /* 557 * Door invocations that are in progress during a 558 * door_revoke() invocation are allowed to complete normally. 559 * -- man page for door_revoke() 560 */ 561 void 562 auditd_thread_close() 563 { 564 if (doorfd == -1) 565 return; 566 (void) door_revoke(doorfd); 567 doorfd = -1; 568 } 569 570 /* 571 * qpool_init() sets up pool for queue entries (audit_q_t) 572 * 573 */ 574 static void 575 qpool_init(plugin_t *p, int threshold) 576 { 577 int i; 578 audit_q_t *node; 579 580 audit_queue_init(&(p->plg_pool)); 581 582 DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n", 583 p->plg_tid, p->plg_qmax, p->plg_qmin, threshold)); 584 585 if (p->plg_qmax > largest_queue) 586 largest_queue = p->plg_qmax; 587 588 p->plg_q_threshold = threshold; 589 590 for (i = 0; i < p->plg_qmin; i++) { 591 node = malloc(sizeof (audit_q_t)); 592 if (node == NULL) 593 warn_or_fatal(1, gettext("no memory\n")); 594 /* doesn't return */ 595 596 audit_enqueue(&p->plg_pool, node); 597 } 598 } 599 600 /* 601 * bpool_init() sets up pool and queue for record entries (audit_rec_t) 602 * 603 */ 604 static void 605 bpool_init() 606 { 607 int i; 608 audit_rec_t *node; 609 610 audit_queue_init(&b_pool); 611 (void) pthread_mutex_init(&b_alloc_lock, NULL); 612 (void) pthread_mutex_init(&b_refcnt_lock, NULL); 613 614 for (i = 0; i < INPUT_MIN; i++) { 615 node = malloc(AUDIT_REC_HEADER + DEFAULT_BUF_SZ); 616 if (node == NULL) 617 warn_or_fatal(1, gettext("no memory\n")); 618 /* doesn't return */ 619 620 node->abq_buf_len = DEFAULT_BUF_SZ; 621 622 node->abq_data_len = 0; 623 audit_enqueue(&b_pool, node); 624 (void) pthread_mutex_lock(&b_alloc_lock); 625 b_allocated++; 626 (void) pthread_mutex_unlock(&b_alloc_lock); 627 } 628 } 629 630 /* 631 * qpool_close() discard queue and pool for a discontinued plugin 632 * 633 * there is no corresponding bpool_close() since it would only 634 * be called as auditd is going down. 635 */ 636 static void 637 qpool_close(plugin_t *p) 638 { 639 audit_q_t *q_node; 640 audit_rec_t *b_node; 641 642 if (!p->plg_initialized) 643 return; 644 645 while (audit_dequeue(&(p->plg_pool), (void *)&q_node) == 0) { 646 free(q_node); 647 } 648 audit_queue_destroy(&(p->plg_pool)); 649 650 while (audit_dequeue(&(p->plg_queue), (void *)&q_node) == 0) { 651 b_node = audit_release(&b_refcnt_lock, q_node->aqq_data); 652 if (b_node != NULL) 653 audit_enqueue(&b_pool, b_node); 654 free(q_node); 655 } 656 audit_queue_destroy(&(p->plg_queue)); 657 } 658 659 /* 660 * qpool_withdraw 661 */ 662 static audit_q_t * 663 qpool_withdraw(plugin_t *p) 664 { 665 audit_q_t *node; 666 int rc; 667 668 /* get a buffer from the pool, if any */ 669 rc = audit_dequeue(&(p->plg_pool), (void *)&node); 670 if (rc == 0) 671 return (node); 672 673 /* 674 * the pool is empty: allocate a new element 675 */ 676 node = malloc(sizeof (audit_q_t)); 677 678 if (node == NULL) 679 warn_or_fatal(1, gettext("no memory\n")); 680 /* doesn't return */ 681 682 return (node); 683 } 684 685 /* 686 * bpool_withdraw -- gets a buffer and fills it 687 * 688 */ 689 static audit_rec_t * 690 bpool_withdraw(char *buffer, size_t buff_size, size_t request_size) 691 { 692 audit_rec_t *node; 693 int rc; 694 size_t new_length; 695 696 new_length = (request_size > DEFAULT_BUF_SZ) ? 697 request_size : DEFAULT_BUF_SZ; 698 699 /* get a buffer from the pool, if any */ 700 rc = audit_dequeue(&b_pool, (void *)&node); 701 702 DPRINT((dbfp, "bpool_withdraw buf length=%d," 703 " requested size=%d, dequeue rc=%d\n", 704 new_length, request_size, rc)); 705 706 if (rc == 0) { 707 DPRINT((dbfp, "bpool_withdraw node=%p (pool=%d)\n", 708 (void *)node, audit_queue_size(&b_pool))); 709 710 if (new_length > node->abq_buf_len) { 711 node = realloc(node, AUDIT_REC_HEADER + new_length); 712 if (node == NULL) 713 warn_or_fatal(1, gettext("no memory\n")); 714 /* no return */ 715 } 716 } else { 717 /* 718 * the pool is empty: allocate a new element 719 */ 720 (void) pthread_mutex_lock(&b_alloc_lock); 721 if (b_allocated >= largest_queue) { 722 (void) pthread_mutex_unlock(&b_alloc_lock); 723 DPRINT((dbfp, "bpool_withdraw is over max (pool=%d)\n", 724 audit_queue_size(&b_pool))); 725 return (NULL); 726 } 727 (void) pthread_mutex_unlock(&b_alloc_lock); 728 729 node = malloc(AUDIT_REC_HEADER + new_length); 730 731 if (node == NULL) 732 warn_or_fatal(1, gettext("no memory\n")); 733 /* no return */ 734 735 (void) pthread_mutex_lock(&b_alloc_lock); 736 b_allocated++; 737 (void) pthread_mutex_unlock(&b_alloc_lock); 738 DPRINT((dbfp, "bpool_withdraw node=%p (alloc=%d, pool=%d)\n", 739 (void *)node, b_allocated, audit_queue_size(&b_pool))); 740 } 741 assert(request_size <= new_length); 742 743 (void) memcpy(node->abq_buffer, buffer, buff_size); 744 node->abq_data_len = buff_size; 745 node->abq_buf_len = new_length; 746 node->abq_ref_count = 0; 747 748 return (node); 749 } 750 751 /* 752 * qpool_return() moves queue nodes back to the pool queue. 753 * 754 * if the pool is over max, the node is discarded instead. 755 */ 756 static void 757 qpool_return(plugin_t *p, audit_q_t *node) 758 { 759 int qpool_size; 760 int q_size; 761 762 #if DEBUG 763 uint64_t sequence = node->aqq_sequence; 764 #endif 765 qpool_size = audit_queue_size(&(p->plg_pool)); 766 q_size = audit_queue_size(&(p->plg_queue)); 767 768 if (qpool_size + q_size > p->plg_qmax) 769 free(node); 770 else 771 audit_enqueue(&(p->plg_pool), node); 772 773 DPRINT((dbfp, 774 "qpool_return(%d): seq=%llu, q size=%d," 775 " pool size=%d (total alloc=%d), threshhold=%d\n", 776 p->plg_tid, sequence, q_size, qpool_size, 777 q_size + qpool_size, p->plg_q_threshold)); 778 } 779 780 /* 781 * bpool_return() moves queue nodes back to the pool queue. 782 */ 783 static void 784 bpool_return(audit_rec_t *node) 785 { 786 #if DEBUG 787 audit_rec_t *copy = node; 788 #endif 789 node = audit_release(&b_refcnt_lock, node); /* decrement ref cnt */ 790 791 if (node != NULL) { /* NULL if ref cnt is not zero */ 792 audit_enqueue(&b_pool, node); 793 DPRINT((dbfp, 794 "bpool_return: requeue %p (allocated=%d," 795 " pool size=%d)\n", (void *)node, b_allocated, 796 audit_queue_size(&b_pool))); 797 } 798 #if DEBUG 799 else { 800 DPRINT((dbfp, 801 "bpool_return: decrement count for %p (allocated=%d," 802 " pool size=%d)\n", (void *)copy, b_allocated, 803 audit_queue_size(&b_pool))); 804 } 805 #endif 806 } 807 808 #if DEBUG 809 static void 810 dump_state(char *src, plugin_t *p, uint64_t count, char *msg) 811 { 812 struct sched_param param; 813 int policy; 814 /* 815 * count is message sequence 816 */ 817 (void) pthread_getschedparam(p->plg_tid, &policy, ¶m); 818 (void) fprintf(dbfp, "%7s(%d/%llu) %11s:" 819 " input_in_wait=%d" 820 " priority=%d" 821 " queue size=%d pool size=%d" 822 "\n\t" 823 "process wait=%d" 824 " tossed=%d" 825 " queued=%d" 826 " written=%d" 827 "\n", 828 src, p->plg_tid, count, msg, 829 in_thr.thd_waiting, param.sched_priority, 830 audit_queue_size(&(p->plg_queue)), 831 audit_queue_size(&(p->plg_pool)), 832 p->plg_waiting, p->plg_tossed, 833 p->plg_queued, p->plg_output); 834 835 (void) fflush(dbfp); 836 } 837 #endif 838 839 /* 840 * policy_is_block: return 1 if the continue policy is off for any active 841 * plugin, else 0 842 */ 843 static int 844 policy_is_block() 845 { 846 plugin_t *p; 847 848 (void) pthread_mutex_lock(&plugin_mutex); 849 p = plugin_head; 850 851 while (p != NULL) { 852 if (p->plg_cnt == 0) { 853 (void) pthread_mutex_unlock(&plugin_mutex); 854 DPRINT((dbfp, 855 "policy_is_block: policy is to block\n")); 856 return (1); 857 } 858 p = p->plg_next; 859 } 860 (void) pthread_mutex_unlock(&plugin_mutex); 861 DPRINT((dbfp, "policy_is_block: policy is to continue\n")); 862 return (0); 863 } 864 865 /* 866 * policy_update() -- the kernel has received a policy change. 867 * Presently, the only policy auditd cares about is AUDIT_CNT 868 */ 869 static void 870 policy_update(uint32_t newpolicy) 871 { 872 plugin_t *p; 873 874 DPRINT((dbfp, "policy change: %X\n", newpolicy)); 875 (void) pthread_mutex_lock(&plugin_mutex); 876 p = plugin_head; 877 while (p != NULL) { 878 p->plg_cnt = (newpolicy & AUDIT_CNT) ? 1 : 0; 879 (void) pthread_cond_signal(&(p->plg_cv)); 880 881 DPRINT((dbfp, "policy changed for thread %d\n", p->plg_tid)); 882 p = p->plg_next; 883 } 884 (void) pthread_mutex_unlock(&plugin_mutex); 885 } 886 887 /* 888 * queue_buffer() inputs a buffer and queues for each active plugin if 889 * it represents a complete audit record. Otherwise it builds a 890 * larger buffer to hold the record and take successive buffers from 891 * c2audit to build a complete record; then queues it for each plugin. 892 * 893 * return 0 if data is queued (or damaged and tossed). If resources 894 * are not available, return 0 if all active plugins have the cnt 895 * policy set, else 1. 0 is also returned if the input is a control 896 * message. (aub_buf is aligned on a 64 bit boundary, so casting 897 * it to an integer works just fine.) 898 */ 899 static int 900 queue_buffer(au_dbuf_t *kl) 901 { 902 plugin_t *p; 903 audit_rec_t *b_copy; 904 audit_q_t *q_copy; 905 boolean_t referenced = 0; 906 static char *invalid_msg = "invalid audit record discarded"; 907 static char *invalid_control = "invalid audit control discarded"; 908 909 static audit_rec_t *alt_b_copy = NULL; 910 static size_t alt_length; 911 static size_t alt_offset; 912 913 /* 914 * the buffer may be a kernel -> auditd message. (only 915 * the policy change message exists so far.) 916 */ 917 918 if ((kl->aub_type & AU_DBUF_NOTIFY) != 0) { 919 uint32_t control; 920 921 control = kl->aub_type & ~AU_DBUF_NOTIFY; 922 switch (control) { 923 case AU_DBUF_POLICY: 924 /* LINTED */ 925 policy_update(*(uint32_t *)kl->aub_buf); 926 break; 927 case AU_DBUF_SHUTDOWN: 928 (void) kill(getpid(), SIGTERM); 929 DPRINT((dbfp, "AU_DBUF_SHUTDOWN message\n")); 930 break; 931 default: 932 warn_or_fatal(0, gettext(invalid_control)); 933 break; 934 } 935 return (0); 936 } 937 /* 938 * The test for valid continuation/completion may fail. Need to 939 * assume the failure was earlier and that this buffer may 940 * be a valid first or complete buffer after discarding the 941 * incomplete record 942 */ 943 944 if (alt_b_copy != NULL) { 945 if ((kl->aub_type == AU_DBUF_FIRST) || 946 (kl->aub_type == AU_DBUF_COMPLETE)) { 947 DPRINT((dbfp, "copy is not null, partial is %d\n", 948 kl->aub_type)); 949 bpool_return(alt_b_copy); 950 warn_or_fatal(0, gettext(invalid_msg)); 951 alt_b_copy = NULL; 952 } 953 } 954 if (alt_b_copy != NULL) { /* continue collecting a long record */ 955 if (kl->aub_size + alt_offset > alt_length) { 956 bpool_return(alt_b_copy); 957 alt_b_copy = NULL; 958 warn_or_fatal(0, gettext(invalid_msg)); 959 return (0); 960 } 961 (void) memcpy(alt_b_copy->abq_buffer + alt_offset, kl->aub_buf, 962 kl->aub_size); 963 alt_offset += kl->aub_size; 964 if (kl->aub_type == AU_DBUF_MIDDLE) 965 return (0); 966 b_copy = alt_b_copy; 967 alt_b_copy = NULL; 968 b_copy->abq_data_len = alt_length; 969 } else if (kl->aub_type == AU_DBUF_FIRST) { 970 /* first buffer of a multiple buffer record */ 971 alt_length = getlen(kl->aub_buf); 972 if ((alt_length < MIN_RECORD_SIZE) || 973 (alt_length <= kl->aub_size)) { 974 warn_or_fatal(0, gettext(invalid_msg)); 975 return (0); 976 } 977 alt_b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 978 alt_length); 979 980 if (alt_b_copy == NULL) 981 return (policy_is_block()); 982 983 alt_offset = kl->aub_size; 984 return (0); 985 } else { /* one buffer, one record -- the basic case */ 986 if (kl->aub_type != AU_DBUF_COMPLETE) { 987 DPRINT((dbfp, "copy is null, partial is %d\n", 988 kl->aub_type)); 989 warn_or_fatal(0, gettext(invalid_msg)); 990 return (0); /* tossed */ 991 } 992 b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 993 kl->aub_size); 994 995 if (b_copy == NULL) 996 return (policy_is_block()); 997 } 998 999 (void) pthread_mutex_lock(&plugin_mutex); 1000 p = plugin_head; 1001 while (p != NULL) { 1002 if (!p->plg_removed) { 1003 /* 1004 * Link the record buffer to the input queues. 1005 * To avoid a race, it is necessary to wait 1006 * until all reference count increments 1007 * are complete before queueing q_copy. 1008 */ 1009 audit_incr_ref(&b_refcnt_lock, b_copy); 1010 1011 q_copy = qpool_withdraw(p); 1012 q_copy->aqq_sequence = p->plg_sequence++; 1013 q_copy->aqq_data = b_copy; 1014 1015 p->plg_save_q_copy = q_copy; /* enqueue below */ 1016 referenced = 1; 1017 } else 1018 p->plg_save_q_copy = NULL; 1019 p = p->plg_next; 1020 } 1021 /* 1022 * now that the reference count is updated, queue it. 1023 */ 1024 if (referenced) { 1025 p = plugin_head; 1026 while ((p != NULL) && (p->plg_save_q_copy != NULL)) { 1027 audit_enqueue(&(p->plg_queue), p->plg_save_q_copy); 1028 (void) pthread_cond_signal(&(p->plg_cv)); 1029 p->plg_queued++; 1030 p = p->plg_next; 1031 } 1032 } else 1033 bpool_return(b_copy); 1034 1035 (void) pthread_mutex_unlock(&plugin_mutex); 1036 1037 return (0); 1038 } 1039 1040 /* 1041 * wait_a_while() -- timed wait in the door server to allow output 1042 * time to catch up. 1043 */ 1044 static void 1045 wait_a_while() 1046 { 1047 struct timespec delay = {0, 500000000}; /* 1/2 second */; 1048 1049 (void) pthread_mutex_lock(&(in_thr.thd_mutex)); 1050 in_thr.thd_waiting = 1; 1051 (void) pthread_cond_reltimedwait_np(&(in_thr.thd_cv), 1052 &(in_thr.thd_mutex), &delay); 1053 in_thr.thd_waiting = 0; 1054 (void) pthread_mutex_unlock(&(in_thr.thd_mutex)); 1055 } 1056 1057 /* 1058 * adjust_priority() -- check queue and pools and adjust the priority 1059 * for process() accordingly. If we're way ahead of output, do a 1060 * timed wait as well. 1061 */ 1062 static void 1063 adjust_priority() 1064 { 1065 int queue_near_full; 1066 plugin_t *p; 1067 int queue_size; 1068 struct sched_param param; 1069 1070 queue_near_full = 0; 1071 (void) pthread_mutex_lock(&plugin_mutex); 1072 p = plugin_head; 1073 while (p != NULL) { 1074 queue_size = audit_queue_size(&(p->plg_queue)); 1075 if (queue_size > p->plg_q_threshold) { 1076 if (p->plg_priority != HIGH_PRIORITY) { 1077 p->plg_priority = 1078 param.sched_priority = 1079 HIGH_PRIORITY; 1080 (void) pthread_setschedparam(p->plg_tid, 1081 SCHED_OTHER, ¶m); 1082 } 1083 if (queue_size > p->plg_qmax - p->plg_qmin) { 1084 queue_near_full = 1; 1085 break; 1086 } 1087 } 1088 p = p->plg_next; 1089 } 1090 (void) pthread_mutex_unlock(&plugin_mutex); 1091 1092 if (queue_near_full) { 1093 DPRINT((dbfp, 1094 "adjust_priority: input taking a short break\n")); 1095 wait_a_while(); 1096 DPRINT((dbfp, 1097 "adjust_priority: input back from my break\n")); 1098 } 1099 } 1100 1101 /* 1102 * input() is a door server; it blocks if any plugins have full queues 1103 * with the continue policy off. (auditconfig -setpolicy -cnt) 1104 * 1105 * input() is called synchronously from c2audit and is NOT 1106 * reentrant due to the (unprotected) static variables in 1107 * queue_buffer(). If multiple clients are created, a context 1108 * structure will be required for queue_buffer. 1109 * 1110 * timedwait is used when input() gets too far ahead of process(); 1111 * the wait terminates either when the set time expires or when 1112 * process() signals that it has nearly caught up. 1113 */ 1114 /* ARGSUSED */ 1115 static void 1116 input(void *cookie, void *argp, int arg_size, door_desc_t *dp, 1117 int n_descriptors) 1118 { 1119 int is_blocked; 1120 plugin_t *p; 1121 #if DEBUG 1122 int loop_count = 0; 1123 static int call_counter = 0; 1124 #endif 1125 if (argp == NULL) { 1126 warn_or_fatal(0, 1127 gettext("invalid data received from c2audit\n")); 1128 goto input_exit; 1129 } 1130 DPRINT((dbfp, "%d input new buffer: length=%u, " 1131 "partial=%u, arg_size=%d\n", 1132 ++call_counter, ((au_dbuf_t *)argp)->aub_size, 1133 ((au_dbuf_t *)argp)->aub_type, arg_size)); 1134 1135 if (((au_dbuf_t *)argp)->aub_size < 1) { 1136 warn_or_fatal(0, 1137 gettext("invalid data length received from c2audit\n")); 1138 goto input_exit; 1139 } 1140 /* 1141 * is_blocked is true only if one or more plugins have "no 1142 * continue" (-cnt) set and one of those has a full queue. 1143 * All plugins block until success is met. 1144 */ 1145 for (;;) { 1146 DPRINT((dbfp, "%d input is calling queue_buffer\n", 1147 call_counter)); 1148 1149 is_blocked = queue_buffer((au_dbuf_t *)argp); 1150 1151 if (!is_blocked) { 1152 adjust_priority(); 1153 break; 1154 } else { 1155 DPRINT((dbfp, 1156 "%d input blocked (loop=%d)\n", 1157 call_counter, loop_count)); 1158 1159 wait_a_while(); 1160 1161 DPRINT((dbfp, "%d input unblocked (loop=%d)\n", 1162 call_counter, loop_count)); 1163 } 1164 #if DEBUG 1165 loop_count++; 1166 #endif 1167 } 1168 input_exit: 1169 p = plugin_head; 1170 while (p != NULL) { 1171 (void) pthread_cond_signal(&(p->plg_cv)); 1172 p = p->plg_next; 1173 } 1174 ((au_dbuf_t *)argp)->aub_size = 0; /* return code */ 1175 (void) door_return(argp, sizeof (uint64_t), NULL, 0); 1176 } 1177 1178 /* 1179 * process() -- pass a buffer to a plugin 1180 */ 1181 static void * 1182 process(void *arg) 1183 { 1184 plugin_t *p = arg; 1185 int rc; 1186 audit_rec_t *b_node; 1187 audit_q_t *q_node; 1188 auditd_rc_t plugrc; 1189 char *error_string; 1190 struct timespec delay; 1191 int sendsignal; 1192 int queue_len; 1193 struct sched_param param; 1194 static boolean_t once = B_FALSE; 1195 1196 DPRINT((dbfp, "%s is thread %d\n", p->plg_path, p->plg_tid)); 1197 p->plg_priority = param.sched_priority = BASE_PRIORITY; 1198 (void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, ¶m); 1199 1200 delay.tv_nsec = 0; 1201 1202 for (;;) { 1203 while (audit_dequeue(&(p->plg_queue), (void *)&q_node) != 0) { 1204 DUMP("process", p, p->plg_last_seq_out, "blocked"); 1205 (void) pthread_cond_signal(&(in_thr.thd_cv)); 1206 1207 (void) pthread_mutex_lock(&(p->plg_mutex)); 1208 p->plg_waiting++; 1209 (void) pthread_cond_wait(&(p->plg_cv), 1210 &(p->plg_mutex)); 1211 p->plg_waiting--; 1212 (void) pthread_mutex_unlock(&(p->plg_mutex)); 1213 1214 if (p->plg_removed) 1215 goto plugin_removed; 1216 1217 DUMP("process", p, p->plg_last_seq_out, "unblocked"); 1218 } 1219 #if DEBUG 1220 if (q_node->aqq_sequence != p->plg_last_seq_out + 1) 1221 (void) fprintf(dbfp, 1222 "process(%d): buffer sequence=%llu but prev=%llu\n", 1223 p->plg_tid, q_node->aqq_sequence, 1224 p->plg_last_seq_out); 1225 #endif 1226 error_string = NULL; 1227 1228 b_node = q_node->aqq_data; 1229 retry_mode: 1230 plugrc = p->plg_fplugin(b_node->abq_buffer, 1231 b_node->abq_data_len, q_node->aqq_sequence, &error_string); 1232 1233 if (p->plg_removed) 1234 goto plugin_removed; 1235 #if DEBUG 1236 p->plg_last_seq_out = q_node->aqq_sequence; 1237 #endif 1238 switch (plugrc) { 1239 case AUDITD_RETRY: 1240 if (!once) { 1241 report_error(plugrc, error_string, p->plg_path); 1242 once = B_TRUE; 1243 } 1244 free(error_string); 1245 error_string = NULL; 1246 1247 DPRINT((dbfp, "process(%d) AUDITD_RETRY returned." 1248 " cnt=%d (if 1, enter retry)\n", 1249 p->plg_tid, p->plg_cnt)); 1250 1251 if (p->plg_cnt) /* if cnt is on, lose the buffer */ 1252 break; 1253 1254 delay.tv_sec = p->plg_retry_time; 1255 (void) pthread_mutex_lock(&(p->plg_mutex)); 1256 p->plg_waiting++; 1257 (void) pthread_cond_reltimedwait_np(&(p->plg_cv), 1258 &(p->plg_mutex), &delay); 1259 p->plg_waiting--; 1260 (void) pthread_mutex_unlock(&(p->plg_mutex)); 1261 1262 DPRINT((dbfp, "left retry mode for %d\n", p->plg_tid)); 1263 goto retry_mode; 1264 1265 case AUDITD_SUCCESS: 1266 p->plg_output++; 1267 once = B_FALSE; 1268 break; 1269 default: 1270 report_error(plugrc, error_string, p->plg_path); 1271 free(error_string); 1272 error_string = NULL; 1273 break; 1274 } /* end switch */ 1275 bpool_return(b_node); 1276 qpool_return(p, q_node); 1277 1278 sendsignal = 0; 1279 queue_len = audit_queue_size(&(p->plg_queue)); 1280 1281 (void) pthread_mutex_lock(&(in_thr.thd_mutex)); 1282 if (in_thr.thd_waiting && (queue_len > p->plg_qmin) && 1283 (queue_len < p->plg_q_threshold)) 1284 sendsignal = 1; 1285 1286 (void) pthread_mutex_unlock(&(in_thr.thd_mutex)); 1287 1288 if (sendsignal) { 1289 (void) pthread_cond_signal(&(in_thr.thd_cv)); 1290 /* 1291 * sched_yield(); does not help 1292 * performance and in artificial tests 1293 * (high sustained volume) appears to 1294 * hurt by adding wide variability in 1295 * the results. 1296 */ 1297 } else if ((p->plg_priority < BASE_PRIORITY) && 1298 (queue_len < p->plg_q_threshold)) { 1299 p->plg_priority = param.sched_priority = 1300 BASE_PRIORITY; 1301 (void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, 1302 ¶m); 1303 } 1304 } /* end for (;;) */ 1305 plugin_removed: 1306 DUMP("process", p, p->plg_last_seq_out, "exit"); 1307 error_string = NULL; 1308 if ((rc = p->plg_fplugin_close(&error_string)) != 1309 AUDITD_SUCCESS) 1310 report_error(rc, error_string, p->plg_path); 1311 1312 free(error_string); 1313 1314 (void) pthread_mutex_lock(&plugin_mutex); 1315 (void) unload_plugin(p); 1316 (void) pthread_mutex_unlock(&plugin_mutex); 1317 return (NULL); 1318 } 1319