xref: /illumos-gate/usr/src/cmd/auditd/doorway.c (revision d6beba26)
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(void *);
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(int rc,char * error_text,char * plugin_path)152 report_error(int rc, char *error_text, char *plugin_path)
153 {
154 	int		warn = 0;
155 	char		rcbuf[100]; /* short error name string */
156 	char		message[FATAL_MESSAGE_LEN];
157 	int		bad_count = 0;
158 	char		*name;
159 	char		empty[] = "..";
160 
161 	static int	no_plug = 0;
162 	static int	no_load = 0;
163 	static int	no_thread;
164 	static int	no_memory = 0;
165 	static int	invalid = 0;
166 	static int	retry = 0;
167 	static int	fail = 0;
168 
169 	name = plugin_path;
170 	if (error_text == NULL)
171 		error_text = empty;
172 	if (name == NULL)
173 		name = empty;
174 
175 	switch (rc) {
176 	case INTERNAL_LOAD_ERROR:
177 		warn = 1;
178 		bad_count = ++no_load;
179 		(void) strcpy(rcbuf, "load_error");
180 		break;
181 	case INTERNAL_SYS_ERROR:
182 		warn = 1;
183 		bad_count = ++no_thread;
184 		(void) strcpy(rcbuf, "sys_error");
185 		break;
186 	case INTERNAL_CONFIG_ERROR:
187 		warn = 1;
188 		bad_count = ++no_plug;
189 		(void) strcpy(rcbuf, "config_error");
190 		name = strdup("--");
191 		break;
192 	case AUDITD_SUCCESS:
193 		break;
194 	case AUDITD_NO_MEMORY:	/* no_memory */
195 		warn = 1;
196 		bad_count = ++no_memory;
197 		(void) strcpy(rcbuf, "no_memory");
198 		break;
199 	case AUDITD_INVALID:	/* invalid */
200 		warn = 1;
201 		bad_count = ++invalid;
202 		(void) strcpy(rcbuf, "invalid");
203 		break;
204 	case AUDITD_RETRY:
205 		warn = 1;
206 		bad_count = ++retry;
207 		(void) strcpy(rcbuf, "retry");
208 		break;
209 	case AUDITD_COMM_FAIL:	/* comm_fail */
210 		(void) strcpy(rcbuf, "comm_fail");
211 		break;
212 	case AUDITD_FATAL:	/* failure */
213 		warn = 1;
214 		bad_count = ++fail;
215 		(void) strcpy(rcbuf, "failure");
216 		break;
217 	default:
218 		(void) strcpy(rcbuf, "error");
219 		break;
220 	}
221 	DPRINT((dbfp, "report_error(%d - %s): %s\n\t%s\n",
222 	    bad_count, name, rcbuf, error_text));
223 	if (warn)
224 		__audit_dowarn2("plugin", name, rcbuf, error_text, bad_count);
225 	else {
226 		(void) snprintf(message, FATAL_MESSAGE_LEN,
227 		    gettext("audit plugin %s reported error = \"%s\": %s\n"),
228 		    name, rcbuf, error_text);
229 		warn_or_fatal(0, message);
230 	}
231 }
232 
233 static size_t
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 		    &param);
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, process, p)) {
509 				report_error(INTERNAL_SYS_ERROR,
510 				    gettext("thread creation failed"),
511 				    p->plg_path);
512 				p = unload_plugin(p);
513 				continue;
514 			}
515 		} else if (p->plg_reopen) {
516 			DPRINT((dbfp, "reopen %s\n", p->plg_path));
517 			error_string = NULL;
518 			if ((rc = p->plg_fplugin_open(p->plg_kvlist,
519 			    &open_params, &error_string)) != AUDITD_SUCCESS) {
520 				report_error(rc, error_string, p->plg_path);
521 				free(error_string);
522 				p = unload_plugin(p);
523 				continue;
524 			}
525 			open_return(p, open_params);
526 			p->plg_reopen = 0;
527 
528 			DPRINT((dbfp, "%s qmax=%d\n",
529 			    p->plg_path, p->plg_qmax));
530 
531 		}
532 		p->plg_q_threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100;
533 
534 		p = p->plg_next;
535 		plugin_count++;
536 	}
537 	if (plugin_count == 0) {
538 		report_error(INTERNAL_CONFIG_ERROR,
539 		    gettext("No plugins are configured"), NULL);
540 		return (-1);
541 	}
542 	if (!threads_ready) {
543 		/* unleash the kernel */
544 		rc = auditdoor(doorfd);
545 
546 		DPRINT((dbfp, "%d returned from auditdoor.\n",
547 		    rc));
548 		if (rc != 0)
549 			return (1);	/* fatal */
550 
551 		threads_ready = 1;
552 	}
553 	return (0);
554 }
555 
556 /*
557  * Door invocations that are in progress during a
558  * door_revoke() invocation are allowed to complete normally.
559  * -- man page for door_revoke()
560  */
561 void
auditd_thread_close()562 auditd_thread_close()
563 {
564 	if (doorfd == -1)
565 		return;
566 	(void) door_revoke(doorfd);
567 	doorfd = -1;
568 }
569 
570 /*
571  * qpool_init() sets up pool for queue entries (audit_q_t)
572  *
573  */
574 static void
qpool_init(plugin_t * p,int threshold)575 qpool_init(plugin_t *p, int threshold)
576 {
577 	int		i;
578 	audit_q_t	*node;
579 
580 	audit_queue_init(&(p->plg_pool));
581 
582 	DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n",
583 	    p->plg_tid, p->plg_qmax, p->plg_qmin, threshold));
584 
585 	if (p->plg_qmax > largest_queue)
586 		largest_queue = p->plg_qmax;
587 
588 	p->plg_q_threshold = threshold;
589 
590 	for (i = 0; i < p->plg_qmin; i++) {
591 		node = malloc(sizeof (audit_q_t));
592 		if (node == NULL)
593 			warn_or_fatal(1, gettext("no memory\n"));
594 			/* doesn't return */
595 
596 		audit_enqueue(&p->plg_pool, node);
597 	}
598 }
599 
600 /*
601  * bpool_init() sets up pool and queue for record entries (audit_rec_t)
602  *
603  */
604 static void
bpool_init()605 bpool_init()
606 {
607 	int		i;
608 	audit_rec_t	*node;
609 
610 	audit_queue_init(&b_pool);
611 	(void) pthread_mutex_init(&b_alloc_lock, NULL);
612 	(void) pthread_mutex_init(&b_refcnt_lock, NULL);
613 
614 	for (i = 0; i < INPUT_MIN; i++) {
615 		node = malloc(AUDIT_REC_HEADER + DEFAULT_BUF_SZ);
616 		if (node == NULL)
617 			warn_or_fatal(1, gettext("no memory\n"));
618 			/* doesn't return */
619 
620 		node->abq_buf_len = DEFAULT_BUF_SZ;
621 
622 		node->abq_data_len = 0;
623 		audit_enqueue(&b_pool, node);
624 		(void) pthread_mutex_lock(&b_alloc_lock);
625 		b_allocated++;
626 		(void) pthread_mutex_unlock(&b_alloc_lock);
627 	}
628 }
629 
630 /*
631  * qpool_close() discard queue and pool for a discontinued plugin
632  *
633  * there is no corresponding bpool_close() since it would only
634  * be called as auditd is going down.
635  */
636 static void
qpool_close(plugin_t * p)637 qpool_close(plugin_t *p)
638 {
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, &param);
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, &param);
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(void * arg)1182 process(void *arg)
1183 {
1184 	plugin_t *p		= arg;
1185 	int			rc;
1186 	audit_rec_t		*b_node;
1187 	audit_q_t		*q_node;
1188 	auditd_rc_t		plugrc;
1189 	char			*error_string;
1190 	struct timespec		delay;
1191 	int			sendsignal;
1192 	int			queue_len;
1193 	struct sched_param	param;
1194 	static boolean_t	once = B_FALSE;
1195 
1196 	DPRINT((dbfp, "%s is thread %d\n", p->plg_path, p->plg_tid));
1197 	p->plg_priority = param.sched_priority = BASE_PRIORITY;
1198 	(void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, &param);
1199 
1200 	delay.tv_nsec = 0;
1201 
1202 	for (;;) {
1203 		while (audit_dequeue(&(p->plg_queue), (void *)&q_node) != 0) {
1204 			DUMP("process", p, p->plg_last_seq_out, "blocked");
1205 			(void) pthread_cond_signal(&(in_thr.thd_cv));
1206 
1207 			(void) pthread_mutex_lock(&(p->plg_mutex));
1208 			p->plg_waiting++;
1209 			(void) pthread_cond_wait(&(p->plg_cv),
1210 			    &(p->plg_mutex));
1211 			p->plg_waiting--;
1212 			(void) pthread_mutex_unlock(&(p->plg_mutex));
1213 
1214 			if (p->plg_removed)
1215 				goto plugin_removed;
1216 
1217 			DUMP("process", p, p->plg_last_seq_out, "unblocked");
1218 		}
1219 #if DEBUG
1220 		if (q_node->aqq_sequence != p->plg_last_seq_out + 1)
1221 			(void) fprintf(dbfp,
1222 			    "process(%d): buffer sequence=%llu but prev=%llu\n",
1223 			    p->plg_tid, q_node->aqq_sequence,
1224 			    p->plg_last_seq_out);
1225 #endif
1226 		error_string = NULL;
1227 
1228 		b_node = q_node->aqq_data;
1229 retry_mode:
1230 		plugrc = p->plg_fplugin(b_node->abq_buffer,
1231 		    b_node->abq_data_len, q_node->aqq_sequence, &error_string);
1232 
1233 		if (p->plg_removed)
1234 			goto plugin_removed;
1235 #if DEBUG
1236 		p->plg_last_seq_out = q_node->aqq_sequence;
1237 #endif
1238 		switch (plugrc) {
1239 		case AUDITD_RETRY:
1240 			if (!once) {
1241 				report_error(plugrc, error_string, p->plg_path);
1242 				once = B_TRUE;
1243 			}
1244 			free(error_string);
1245 			error_string = NULL;
1246 
1247 			DPRINT((dbfp, "process(%d) AUDITD_RETRY returned."
1248 			    " cnt=%d (if 1, enter retry)\n",
1249 			    p->plg_tid, p->plg_cnt));
1250 
1251 			if (p->plg_cnt)	/* if cnt is on, lose the buffer */
1252 				break;
1253 
1254 			delay.tv_sec = p->plg_retry_time;
1255 			(void) pthread_mutex_lock(&(p->plg_mutex));
1256 			p->plg_waiting++;
1257 			(void) pthread_cond_reltimedwait_np(&(p->plg_cv),
1258 			    &(p->plg_mutex), &delay);
1259 			p->plg_waiting--;
1260 			(void) pthread_mutex_unlock(&(p->plg_mutex));
1261 
1262 			DPRINT((dbfp, "left retry mode for %d\n", p->plg_tid));
1263 			goto retry_mode;
1264 
1265 		case AUDITD_SUCCESS:
1266 			p->plg_output++;
1267 			once = B_FALSE;
1268 			break;
1269 		default:
1270 			report_error(plugrc, error_string, p->plg_path);
1271 			free(error_string);
1272 			error_string = NULL;
1273 			break;
1274 		}	/* end switch */
1275 		bpool_return(b_node);
1276 		qpool_return(p, q_node);
1277 
1278 		sendsignal = 0;
1279 		queue_len = audit_queue_size(&(p->plg_queue));
1280 
1281 		(void) pthread_mutex_lock(&(in_thr.thd_mutex));
1282 		if (in_thr.thd_waiting && (queue_len > p->plg_qmin) &&
1283 		    (queue_len < p->plg_q_threshold))
1284 			sendsignal = 1;
1285 
1286 		(void) pthread_mutex_unlock(&(in_thr.thd_mutex));
1287 
1288 		if (sendsignal) {
1289 			(void) pthread_cond_signal(&(in_thr.thd_cv));
1290 			/*
1291 			 * sched_yield(); does not help
1292 			 * performance and in artificial tests
1293 			 * (high sustained volume) appears to
1294 			 * hurt by adding wide variability in
1295 			 * the results.
1296 			 */
1297 		} else if ((p->plg_priority < BASE_PRIORITY) &&
1298 		    (queue_len < p->plg_q_threshold)) {
1299 			p->plg_priority = param.sched_priority =
1300 			    BASE_PRIORITY;
1301 			(void) pthread_setschedparam(p->plg_tid, SCHED_OTHER,
1302 			    &param);
1303 		}
1304 	}	/* end for (;;) */
1305 plugin_removed:
1306 	DUMP("process", p, p->plg_last_seq_out, "exit");
1307 	error_string = NULL;
1308 	if ((rc = p->plg_fplugin_close(&error_string)) !=
1309 	    AUDITD_SUCCESS)
1310 		report_error(rc, error_string, p->plg_path);
1311 
1312 	free(error_string);
1313 
1314 	(void) pthread_mutex_lock(&plugin_mutex);
1315 	(void) unload_plugin(p);
1316 	(void) pthread_mutex_unlock(&plugin_mutex);
1317 	return (NULL);
1318 }
1319