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(plugin_t *); 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, 509 (void *(*)(void *))process, p)) { 510 report_error(INTERNAL_SYS_ERROR, 511 gettext("thread creation failed"), 512 p->plg_path); 513 p = unload_plugin(p); 514 continue; 515 } 516 } else if (p->plg_reopen) { 517 DPRINT((dbfp, "reopen %s\n", p->plg_path)); 518 error_string = NULL; 519 if ((rc = p->plg_fplugin_open(p->plg_kvlist, 520 &open_params, &error_string)) != AUDITD_SUCCESS) { 521 report_error(rc, error_string, p->plg_path); 522 free(error_string); 523 p = unload_plugin(p); 524 continue; 525 } 526 open_return(p, open_params); 527 p->plg_reopen = 0; 528 529 DPRINT((dbfp, "%s qmax=%d\n", 530 p->plg_path, p->plg_qmax)); 531 532 } 533 p->plg_q_threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100; 534 535 p = p->plg_next; 536 plugin_count++; 537 } 538 if (plugin_count == 0) { 539 report_error(INTERNAL_CONFIG_ERROR, 540 gettext("No plugins are configured"), NULL); 541 return (-1); 542 } 543 if (!threads_ready) { 544 /* unleash the kernel */ 545 rc = auditdoor(doorfd); 546 547 DPRINT((dbfp, "%d returned from auditdoor.\n", 548 rc)); 549 if (rc != 0) 550 return (1); /* fatal */ 551 552 threads_ready = 1; 553 } 554 return (0); 555 } 556 557 /* 558 * Door invocations that are in progress during a 559 * door_revoke() invocation are allowed to complete normally. 560 * -- man page for door_revoke() 561 */ 562 void 563 auditd_thread_close() 564 { 565 if (doorfd == -1) 566 return; 567 (void) door_revoke(doorfd); 568 doorfd = -1; 569 } 570 571 /* 572 * qpool_init() sets up pool for queue entries (audit_q_t) 573 * 574 */ 575 static void 576 qpool_init(plugin_t *p, int threshold) 577 { 578 int i; 579 audit_q_t *node; 580 581 audit_queue_init(&(p->plg_pool)); 582 583 DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n", 584 p->plg_tid, p->plg_qmax, p->plg_qmin, threshold)); 585 586 if (p->plg_qmax > largest_queue) 587 largest_queue = p->plg_qmax; 588 589 p->plg_q_threshold = threshold; 590 591 for (i = 0; i < p->plg_qmin; i++) { 592 node = malloc(sizeof (audit_q_t)); 593 if (node == NULL) 594 warn_or_fatal(1, gettext("no memory\n")); 595 /* doesn't return */ 596 597 audit_enqueue(&p->plg_pool, node); 598 } 599 } 600 601 /* 602 * bpool_init() sets up pool and queue for record entries (audit_rec_t) 603 * 604 */ 605 static void 606 bpool_init() 607 { 608 int i; 609 audit_rec_t *node; 610 611 audit_queue_init(&b_pool); 612 (void) pthread_mutex_init(&b_alloc_lock, NULL); 613 (void) pthread_mutex_init(&b_refcnt_lock, NULL); 614 615 for (i = 0; i < INPUT_MIN; i++) { 616 node = malloc(AUDIT_REC_HEADER + DEFAULT_BUF_SZ); 617 if (node == NULL) 618 warn_or_fatal(1, gettext("no memory\n")); 619 /* doesn't return */ 620 621 node->abq_buf_len = DEFAULT_BUF_SZ; 622 623 node->abq_data_len = 0; 624 audit_enqueue(&b_pool, node); 625 (void) pthread_mutex_lock(&b_alloc_lock); 626 b_allocated++; 627 (void) pthread_mutex_unlock(&b_alloc_lock); 628 } 629 } 630 631 /* 632 * qpool_close() discard queue and pool for a discontinued plugin 633 * 634 * there is no corresponding bpool_close() since it would only 635 * be called as auditd is going down. 636 */ 637 static void 638 qpool_close(plugin_t *p) 639 { 640 audit_q_t *q_node; 641 audit_rec_t *b_node; 642 643 if (!p->plg_initialized) 644 return; 645 646 while (audit_dequeue(&(p->plg_pool), (void *)&q_node) == 0) { 647 free(q_node); 648 } 649 audit_queue_destroy(&(p->plg_pool)); 650 651 while (audit_dequeue(&(p->plg_queue), (void *)&q_node) == 0) { 652 b_node = audit_release(&b_refcnt_lock, q_node->aqq_data); 653 if (b_node != NULL) 654 audit_enqueue(&b_pool, b_node); 655 free(q_node); 656 } 657 audit_queue_destroy(&(p->plg_queue)); 658 } 659 660 /* 661 * qpool_withdraw 662 */ 663 static audit_q_t * 664 qpool_withdraw(plugin_t *p) 665 { 666 audit_q_t *node; 667 int rc; 668 669 /* get a buffer from the pool, if any */ 670 rc = audit_dequeue(&(p->plg_pool), (void *)&node); 671 if (rc == 0) 672 return (node); 673 674 /* 675 * the pool is empty: allocate a new element 676 */ 677 node = malloc(sizeof (audit_q_t)); 678 679 if (node == NULL) 680 warn_or_fatal(1, gettext("no memory\n")); 681 /* doesn't return */ 682 683 return (node); 684 } 685 686 /* 687 * bpool_withdraw -- gets a buffer and fills it 688 * 689 */ 690 static audit_rec_t * 691 bpool_withdraw(char *buffer, size_t buff_size, size_t request_size) 692 { 693 audit_rec_t *node; 694 int rc; 695 size_t new_length; 696 697 new_length = (request_size > DEFAULT_BUF_SZ) ? 698 request_size : DEFAULT_BUF_SZ; 699 700 /* get a buffer from the pool, if any */ 701 rc = audit_dequeue(&b_pool, (void *)&node); 702 703 DPRINT((dbfp, "bpool_withdraw buf length=%d," 704 " requested size=%d, dequeue rc=%d\n", 705 new_length, request_size, rc)); 706 707 if (rc == 0) { 708 DPRINT((dbfp, "bpool_withdraw node=%p (pool=%d)\n", 709 (void *)node, audit_queue_size(&b_pool))); 710 711 if (new_length > node->abq_buf_len) { 712 node = realloc(node, AUDIT_REC_HEADER + new_length); 713 if (node == NULL) 714 warn_or_fatal(1, gettext("no memory\n")); 715 /* no return */ 716 } 717 } else { 718 /* 719 * the pool is empty: allocate a new element 720 */ 721 (void) pthread_mutex_lock(&b_alloc_lock); 722 if (b_allocated >= largest_queue) { 723 (void) pthread_mutex_unlock(&b_alloc_lock); 724 DPRINT((dbfp, "bpool_withdraw is over max (pool=%d)\n", 725 audit_queue_size(&b_pool))); 726 return (NULL); 727 } 728 (void) pthread_mutex_unlock(&b_alloc_lock); 729 730 node = malloc(AUDIT_REC_HEADER + new_length); 731 732 if (node == NULL) 733 warn_or_fatal(1, gettext("no memory\n")); 734 /* no return */ 735 736 (void) pthread_mutex_lock(&b_alloc_lock); 737 b_allocated++; 738 (void) pthread_mutex_unlock(&b_alloc_lock); 739 DPRINT((dbfp, "bpool_withdraw node=%p (alloc=%d, pool=%d)\n", 740 (void *)node, b_allocated, audit_queue_size(&b_pool))); 741 } 742 assert(request_size <= new_length); 743 744 (void) memcpy(node->abq_buffer, buffer, buff_size); 745 node->abq_data_len = buff_size; 746 node->abq_buf_len = new_length; 747 node->abq_ref_count = 0; 748 749 return (node); 750 } 751 752 /* 753 * qpool_return() moves queue nodes back to the pool queue. 754 * 755 * if the pool is over max, the node is discarded instead. 756 */ 757 static void 758 qpool_return(plugin_t *p, audit_q_t *node) 759 { 760 int qpool_size; 761 int q_size; 762 763 #if DEBUG 764 uint64_t sequence = node->aqq_sequence; 765 #endif 766 qpool_size = audit_queue_size(&(p->plg_pool)); 767 q_size = audit_queue_size(&(p->plg_queue)); 768 769 if (qpool_size + q_size > p->plg_qmax) 770 free(node); 771 else 772 audit_enqueue(&(p->plg_pool), node); 773 774 DPRINT((dbfp, 775 "qpool_return(%d): seq=%llu, q size=%d," 776 " pool size=%d (total alloc=%d), threshhold=%d\n", 777 p->plg_tid, sequence, q_size, qpool_size, 778 q_size + qpool_size, p->plg_q_threshold)); 779 } 780 781 /* 782 * bpool_return() moves queue nodes back to the pool queue. 783 */ 784 static void 785 bpool_return(audit_rec_t *node) 786 { 787 #if DEBUG 788 audit_rec_t *copy = node; 789 #endif 790 node = audit_release(&b_refcnt_lock, node); /* decrement ref cnt */ 791 792 if (node != NULL) { /* NULL if ref cnt is not zero */ 793 audit_enqueue(&b_pool, node); 794 DPRINT((dbfp, 795 "bpool_return: requeue %p (allocated=%d," 796 " pool size=%d)\n", (void *)node, b_allocated, 797 audit_queue_size(&b_pool))); 798 } 799 #if DEBUG 800 else { 801 DPRINT((dbfp, 802 "bpool_return: decrement count for %p (allocated=%d," 803 " pool size=%d)\n", (void *)copy, b_allocated, 804 audit_queue_size(&b_pool))); 805 } 806 #endif 807 } 808 809 #if DEBUG 810 static void 811 dump_state(char *src, plugin_t *p, uint64_t count, char *msg) 812 { 813 struct sched_param param; 814 int policy; 815 /* 816 * count is message sequence 817 */ 818 (void) pthread_getschedparam(p->plg_tid, &policy, ¶m); 819 (void) fprintf(dbfp, "%7s(%d/%llu) %11s:" 820 " input_in_wait=%d" 821 " priority=%d" 822 " queue size=%d pool size=%d" 823 "\n\t" 824 "process wait=%d" 825 " tossed=%d" 826 " queued=%d" 827 " written=%d" 828 "\n", 829 src, p->plg_tid, count, msg, 830 in_thr.thd_waiting, param.sched_priority, 831 audit_queue_size(&(p->plg_queue)), 832 audit_queue_size(&(p->plg_pool)), 833 p->plg_waiting, p->plg_tossed, 834 p->plg_queued, p->plg_output); 835 836 (void) fflush(dbfp); 837 } 838 #endif 839 840 /* 841 * policy_is_block: return 1 if the continue policy is off for any active 842 * plugin, else 0 843 */ 844 static int 845 policy_is_block() 846 { 847 plugin_t *p; 848 849 (void) pthread_mutex_lock(&plugin_mutex); 850 p = plugin_head; 851 852 while (p != NULL) { 853 if (p->plg_cnt == 0) { 854 (void) pthread_mutex_unlock(&plugin_mutex); 855 DPRINT((dbfp, 856 "policy_is_block: policy is to block\n")); 857 return (1); 858 } 859 p = p->plg_next; 860 } 861 (void) pthread_mutex_unlock(&plugin_mutex); 862 DPRINT((dbfp, "policy_is_block: policy is to continue\n")); 863 return (0); 864 } 865 866 /* 867 * policy_update() -- the kernel has received a policy change. 868 * Presently, the only policy auditd cares about is AUDIT_CNT 869 */ 870 static void 871 policy_update(uint32_t newpolicy) 872 { 873 plugin_t *p; 874 875 DPRINT((dbfp, "policy change: %X\n", newpolicy)); 876 (void) pthread_mutex_lock(&plugin_mutex); 877 p = plugin_head; 878 while (p != NULL) { 879 p->plg_cnt = (newpolicy & AUDIT_CNT) ? 1 : 0; 880 (void) pthread_cond_signal(&(p->plg_cv)); 881 882 DPRINT((dbfp, "policy changed for thread %d\n", p->plg_tid)); 883 p = p->plg_next; 884 } 885 (void) pthread_mutex_unlock(&plugin_mutex); 886 } 887 888 /* 889 * queue_buffer() inputs a buffer and queues for each active plugin if 890 * it represents a complete audit record. Otherwise it builds a 891 * larger buffer to hold the record and take successive buffers from 892 * c2audit to build a complete record; then queues it for each plugin. 893 * 894 * return 0 if data is queued (or damaged and tossed). If resources 895 * are not available, return 0 if all active plugins have the cnt 896 * policy set, else 1. 0 is also returned if the input is a control 897 * message. (aub_buf is aligned on a 64 bit boundary, so casting 898 * it to an integer works just fine.) 899 */ 900 static int 901 queue_buffer(au_dbuf_t *kl) 902 { 903 plugin_t *p; 904 audit_rec_t *b_copy; 905 audit_q_t *q_copy; 906 boolean_t referenced = 0; 907 static char *invalid_msg = "invalid audit record discarded"; 908 static char *invalid_control = "invalid audit control discarded"; 909 910 static audit_rec_t *alt_b_copy = NULL; 911 static size_t alt_length; 912 static size_t alt_offset; 913 914 /* 915 * the buffer may be a kernel -> auditd message. (only 916 * the policy change message exists so far.) 917 */ 918 919 if ((kl->aub_type & AU_DBUF_NOTIFY) != 0) { 920 uint32_t control; 921 922 control = kl->aub_type & ~AU_DBUF_NOTIFY; 923 switch (control) { 924 case AU_DBUF_POLICY: 925 /* LINTED */ 926 policy_update(*(uint32_t *)kl->aub_buf); 927 break; 928 case AU_DBUF_SHUTDOWN: 929 (void) kill(getpid(), SIGTERM); 930 DPRINT((dbfp, "AU_DBUF_SHUTDOWN message\n")); 931 break; 932 default: 933 warn_or_fatal(0, gettext(invalid_control)); 934 break; 935 } 936 return (0); 937 } 938 /* 939 * The test for valid continuation/completion may fail. Need to 940 * assume the failure was earlier and that this buffer may 941 * be a valid first or complete buffer after discarding the 942 * incomplete record 943 */ 944 945 if (alt_b_copy != NULL) { 946 if ((kl->aub_type == AU_DBUF_FIRST) || 947 (kl->aub_type == AU_DBUF_COMPLETE)) { 948 DPRINT((dbfp, "copy is not null, partial is %d\n", 949 kl->aub_type)); 950 bpool_return(alt_b_copy); 951 warn_or_fatal(0, gettext(invalid_msg)); 952 alt_b_copy = NULL; 953 } 954 } 955 if (alt_b_copy != NULL) { /* continue collecting a long record */ 956 if (kl->aub_size + alt_offset > alt_length) { 957 bpool_return(alt_b_copy); 958 alt_b_copy = NULL; 959 warn_or_fatal(0, gettext(invalid_msg)); 960 return (0); 961 } 962 (void) memcpy(alt_b_copy->abq_buffer + alt_offset, kl->aub_buf, 963 kl->aub_size); 964 alt_offset += kl->aub_size; 965 if (kl->aub_type == AU_DBUF_MIDDLE) 966 return (0); 967 b_copy = alt_b_copy; 968 alt_b_copy = NULL; 969 b_copy->abq_data_len = alt_length; 970 } else if (kl->aub_type == AU_DBUF_FIRST) { 971 /* first buffer of a multiple buffer record */ 972 alt_length = getlen(kl->aub_buf); 973 if ((alt_length < MIN_RECORD_SIZE) || 974 (alt_length <= kl->aub_size)) { 975 warn_or_fatal(0, gettext(invalid_msg)); 976 return (0); 977 } 978 alt_b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 979 alt_length); 980 981 if (alt_b_copy == NULL) 982 return (policy_is_block()); 983 984 alt_offset = kl->aub_size; 985 return (0); 986 } else { /* one buffer, one record -- the basic case */ 987 if (kl->aub_type != AU_DBUF_COMPLETE) { 988 DPRINT((dbfp, "copy is null, partial is %d\n", 989 kl->aub_type)); 990 warn_or_fatal(0, gettext(invalid_msg)); 991 return (0); /* tossed */ 992 } 993 b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size, 994 kl->aub_size); 995 996 if (b_copy == NULL) 997 return (policy_is_block()); 998 } 999 1000 (void) pthread_mutex_lock(&plugin_mutex); 1001 p = plugin_head; 1002 while (p != NULL) { 1003 if (!p->plg_removed) { 1004 /* 1005 * Link the record buffer to the input queues. 1006 * To avoid a race, it is necessary to wait 1007 * until all reference count increments 1008 * are complete before queueing q_copy. 1009 */ 1010 audit_incr_ref(&b_refcnt_lock, b_copy); 1011 1012 q_copy = qpool_withdraw(p); 1013 q_copy->aqq_sequence = p->plg_sequence++; 1014 q_copy->aqq_data = b_copy; 1015 1016 p->plg_save_q_copy = q_copy; /* enqueue below */ 1017 referenced = 1; 1018 } else 1019 p->plg_save_q_copy = NULL; 1020 p = p->plg_next; 1021 } 1022 /* 1023 * now that the reference count is updated, queue it. 1024 */ 1025 if (referenced) { 1026 p = plugin_head; 1027 while ((p != NULL) && (p->plg_save_q_copy != NULL)) { 1028 audit_enqueue(&(p->plg_queue), p->plg_save_q_copy); 1029 (void) pthread_cond_signal(&(p->plg_cv)); 1030 p->plg_queued++; 1031 p = p->plg_next; 1032 } 1033 } else 1034 bpool_return(b_copy); 1035 1036 (void) pthread_mutex_unlock(&plugin_mutex); 1037 1038 return (0); 1039 } 1040 1041 /* 1042 * wait_a_while() -- timed wait in the door server to allow output 1043 * time to catch up. 1044 */ 1045 static void 1046 wait_a_while() 1047 { 1048 struct timespec delay = {0, 500000000}; /* 1/2 second */; 1049 1050 (void) pthread_mutex_lock(&(in_thr.thd_mutex)); 1051 in_thr.thd_waiting = 1; 1052 (void) pthread_cond_reltimedwait_np(&(in_thr.thd_cv), 1053 &(in_thr.thd_mutex), &delay); 1054 in_thr.thd_waiting = 0; 1055 (void) pthread_mutex_unlock(&(in_thr.thd_mutex)); 1056 } 1057 1058 /* 1059 * adjust_priority() -- check queue and pools and adjust the priority 1060 * for process() accordingly. If we're way ahead of output, do a 1061 * timed wait as well. 1062 */ 1063 static void 1064 adjust_priority() 1065 { 1066 int queue_near_full; 1067 plugin_t *p; 1068 int queue_size; 1069 struct sched_param param; 1070 1071 queue_near_full = 0; 1072 (void) pthread_mutex_lock(&plugin_mutex); 1073 p = plugin_head; 1074 while (p != NULL) { 1075 queue_size = audit_queue_size(&(p->plg_queue)); 1076 if (queue_size > p->plg_q_threshold) { 1077 if (p->plg_priority != HIGH_PRIORITY) { 1078 p->plg_priority = 1079 param.sched_priority = 1080 HIGH_PRIORITY; 1081 (void) pthread_setschedparam(p->plg_tid, 1082 SCHED_OTHER, ¶m); 1083 } 1084 if (queue_size > p->plg_qmax - p->plg_qmin) { 1085 queue_near_full = 1; 1086 break; 1087 } 1088 } 1089 p = p->plg_next; 1090 } 1091 (void) pthread_mutex_unlock(&plugin_mutex); 1092 1093 if (queue_near_full) { 1094 DPRINT((dbfp, 1095 "adjust_priority: input taking a short break\n")); 1096 wait_a_while(); 1097 DPRINT((dbfp, 1098 "adjust_priority: input back from my break\n")); 1099 } 1100 } 1101 1102 /* 1103 * input() is a door server; it blocks if any plugins have full queues 1104 * with the continue policy off. (auditconfig -setpolicy -cnt) 1105 * 1106 * input() is called synchronously from c2audit and is NOT 1107 * reentrant due to the (unprotected) static variables in 1108 * queue_buffer(). If multiple clients are created, a context 1109 * structure will be required for queue_buffer. 1110 * 1111 * timedwait is used when input() gets too far ahead of process(); 1112 * the wait terminates either when the set time expires or when 1113 * process() signals that it has nearly caught up. 1114 */ 1115 /* ARGSUSED */ 1116 static void 1117 input(void *cookie, void *argp, int arg_size, door_desc_t *dp, 1118 int n_descriptors) 1119 { 1120 int is_blocked; 1121 plugin_t *p; 1122 #if DEBUG 1123 int loop_count = 0; 1124 static int call_counter = 0; 1125 #endif 1126 if (argp == NULL) { 1127 warn_or_fatal(0, 1128 gettext("invalid data received from c2audit\n")); 1129 goto input_exit; 1130 } 1131 DPRINT((dbfp, "%d input new buffer: length=%u, " 1132 "partial=%u, arg_size=%d\n", 1133 ++call_counter, ((au_dbuf_t *)argp)->aub_size, 1134 ((au_dbuf_t *)argp)->aub_type, arg_size)); 1135 1136 if (((au_dbuf_t *)argp)->aub_size < 1) { 1137 warn_or_fatal(0, 1138 gettext("invalid data length received from c2audit\n")); 1139 goto input_exit; 1140 } 1141 /* 1142 * is_blocked is true only if one or more plugins have "no 1143 * continue" (-cnt) set and one of those has a full queue. 1144 * All plugins block until success is met. 1145 */ 1146 for (;;) { 1147 DPRINT((dbfp, "%d input is calling queue_buffer\n", 1148 call_counter)); 1149 1150 is_blocked = queue_buffer((au_dbuf_t *)argp); 1151 1152 if (!is_blocked) { 1153 adjust_priority(); 1154 break; 1155 } else { 1156 DPRINT((dbfp, 1157 "%d input blocked (loop=%d)\n", 1158 call_counter, loop_count)); 1159 1160 wait_a_while(); 1161 1162 DPRINT((dbfp, "%d input unblocked (loop=%d)\n", 1163 call_counter, loop_count)); 1164 } 1165 #if DEBUG 1166 loop_count++; 1167 #endif 1168 } 1169 input_exit: 1170 p = plugin_head; 1171 while (p != NULL) { 1172 (void) pthread_cond_signal(&(p->plg_cv)); 1173 p = p->plg_next; 1174 } 1175 ((au_dbuf_t *)argp)->aub_size = 0; /* return code */ 1176 (void) door_return(argp, sizeof (uint64_t), NULL, 0); 1177 } 1178 1179 /* 1180 * process() -- pass a buffer to a plugin 1181 */ 1182 static void 1183 process(plugin_t *p) 1184 { 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 } 1318