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