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