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