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