audit_pipe.c revision 155408
1/*-
2 * Copyright (c) 2006 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * This software was developed by Robert Watson for the TrustedBSD Project.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/security/audit/audit_pipe.c 155408 2006-02-06 22:50:39Z rwatson $
29 */
30
31#include <sys/param.h>
32#include <sys/condvar.h>
33#include <sys/conf.h>
34#include <sys/eventhandler.h>
35#include <sys/filio.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/malloc.h>
39#include <sys/mutex.h>
40#include <sys/poll.h>
41#include <sys/proc.h>
42#include <sys/queue.h>
43#include <sys/selinfo.h>
44#include <sys/sigio.h>
45#include <sys/signal.h>
46#include <sys/signalvar.h>
47#include <sys/systm.h>
48#include <sys/uio.h>
49
50#include <security/audit/audit.h>
51#include <security/audit/audit_private.h>
52
53/*
54 * Implementation of a clonable special device providing a live stream of BSM
55 * audit data.  This is a "tee" of the data going to the file.  It provides
56 * unreliable but timely access to audit events.  Consumers of this interface
57 * should be very careful to avoid introducing event cycles.
58 */
59
60/*
61 * Memory types.
62 */
63static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes");
64static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent",
65    "Audit pipe entries and buffers");
66
67/*
68 * Audit pipe buffer parameters.
69 */
70#define	AUDIT_PIPE_QLIMIT_DEFAULT	(32)
71#define	AUDIT_PIPE_QLIMIT_MAX		(1024)
72
73/*
74 * Description of an entry in an audit_pipe.
75 */
76struct audit_pipe_entry {
77	void				*ape_record;
78	u_int				 ape_record_len;
79	TAILQ_ENTRY(audit_pipe_entry)	 ape_queue;
80};
81
82/*
83 * Description of an individual audit_pipe.  Consists largely of a bounded
84 * length queue.
85 */
86#define	AUDIT_PIPE_ASYNC	0x00000001
87#define	AUDIT_PIPE_NBIO		0x00000002
88struct audit_pipe {
89	int				 ap_open;	/* Device open? */
90	u_int				 ap_flags;
91
92	struct selinfo			 ap_selinfo;
93	struct sigio			*ap_sigio;
94
95	u_int				 ap_qlen;
96	u_int				 ap_qlimit;
97
98	u_int64_t			 ap_inserts;	/* Records added. */
99	u_int64_t			 ap_reads;	/* Records read. */
100	u_int64_t			 ap_drops;	/* Records dropped. */
101	u_int64_t			 ap_truncates;	/* Records too long. */
102
103	TAILQ_HEAD(, audit_pipe_entry)	 ap_queue;
104
105	TAILQ_ENTRY(audit_pipe)		 ap_list;
106};
107
108/*
109 * Global list of audit pipes, mutex to protect it and the pipes.  Finder
110 * grained locking may be desirable at some point.
111 */
112static TAILQ_HEAD(, audit_pipe)	 audit_pipe_list;
113static struct mtx		 audit_pipe_mtx;
114
115/*
116 * This CV is used to wakeup on an audit record write.  Eventually, it should
117 * probably be per-pipe.
118 */
119static struct cv		 audit_pipe_cv;
120
121/*
122 * Cloning related variables and constants.
123 */
124#define	AUDIT_PIPE_NAME		"auditpipe"
125static eventhandler_tag		 audit_pipe_eh_tag;
126static struct clonedevs		*audit_pipe_clones;
127
128/*
129 * Special device methods and definition.
130 */
131static d_open_t		audit_pipe_open;
132static d_close_t	audit_pipe_close;
133static d_read_t		audit_pipe_read;
134static d_ioctl_t	audit_pipe_ioctl;
135static d_poll_t		audit_pipe_poll;
136
137static struct cdevsw	audit_pipe_cdevsw = {
138	.d_version =	D_VERSION,
139	.d_flags =	D_PSEUDO,
140	.d_open =	audit_pipe_open,
141	.d_close =	audit_pipe_close,
142	.d_read =	audit_pipe_read,
143	.d_ioctl =	audit_pipe_ioctl,
144	.d_poll =	audit_pipe_poll,
145	.d_name =	AUDIT_PIPE_NAME,
146};
147
148/*
149 * Some global statistics on audit pipes.
150 */
151static int		audit_pipe_count;	/* Current number of pipes. */
152static u_int64_t	audit_pipe_ever;	/* Pipes ever allocated. */
153static u_int64_t	audit_pipe_records;	/* Records seen. */
154static u_int64_t	audit_pipe_drops;	/* Global record drop count. */
155
156/*
157 * Free an audit pipe entry.
158 */
159static void
160audit_pipe_entry_free(struct audit_pipe_entry *ape)
161{
162
163	free(ape->ape_record, M_AUDIT_PIPE_ENTRY);
164	free(ape, M_AUDIT_PIPE_ENTRY);
165}
166
167/*
168 * Apparent individual record to a queue -- allocate queue-local buffer, and
169 * add to the queue.  We try to drop from the head of the queue so that more
170 * recent events take precedence over older ones, but if allocation fails we
171 * do drop the new event.
172 */
173static void
174audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len)
175{
176	struct audit_pipe_entry *ape, *ape_remove;
177
178	mtx_assert(&audit_pipe_mtx, MA_OWNED);
179
180	ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO);
181	if (ape == NULL) {
182		ap->ap_drops++;
183		return;
184	}
185
186	ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT);
187	if (ape->ape_record == NULL) {
188		free(ape, M_AUDIT_PIPE_ENTRY);
189		ap->ap_drops++;
190		audit_pipe_drops++;
191		return;
192	}
193
194	bcopy(record, ape->ape_record, record_len);
195	ape->ape_record_len = record_len;
196
197	if (ap->ap_qlen >= ap->ap_qlimit) {
198		ape_remove = TAILQ_FIRST(&ap->ap_queue);
199		TAILQ_REMOVE(&ap->ap_queue, ape_remove, ape_queue);
200		audit_pipe_entry_free(ape_remove);
201		ap->ap_drops++;
202		audit_pipe_drops++;
203	}
204
205	TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue);
206	ap->ap_inserts++;
207	ap->ap_qlen++;
208	selwakeuppri(&ap->ap_selinfo, PSOCK);
209	if (ap->ap_flags & AUDIT_PIPE_ASYNC)
210		pgsigio(&ap->ap_sigio, SIGIO, 0);
211}
212
213/*
214 * audit_pipe_submit(): audit_worker submits audit records via this
215 * interface, which arranges for them to be delivered to pipe queues.
216 */
217void
218audit_pipe_submit(void *record, u_int record_len)
219{
220	struct audit_pipe *ap;
221
222	/*
223	 * Lockless read to avoid mutex overhead if pipes are not in use.
224	 */
225	if (TAILQ_FIRST(&audit_pipe_list) == NULL)
226		return;
227
228	mtx_lock(&audit_pipe_mtx);
229	TAILQ_FOREACH(ap, &audit_pipe_list, ap_list)
230		audit_pipe_append(ap, record, record_len);
231	audit_pipe_records++;
232	mtx_unlock(&audit_pipe_mtx);
233	cv_signal(&audit_pipe_cv);
234}
235
236/*
237 * Read the next record off of an audit pipe.
238 */
239static struct audit_pipe_entry *
240audit_pipe_pop(struct audit_pipe *ap)
241{
242	struct audit_pipe_entry *ape;
243
244	mtx_assert(&audit_pipe_mtx, MA_OWNED);
245
246	ape = TAILQ_FIRST(&ap->ap_queue);
247	KASSERT((ape == NULL && ap->ap_qlen == 0) ||
248	    (ape != NULL && ap->ap_qlen != 0), ("audit_pipe_pop: qlen"));
249	if (ape == NULL)
250		return (NULL);
251	TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
252	ap->ap_qlen--;
253	return (ape);
254}
255
256/*
257 * Allocate a new audit pipe.  Connects the pipe, on success, to the global
258 * list and updates statistics.
259 */
260static struct audit_pipe *
261audit_pipe_alloc(void)
262{
263	struct audit_pipe *ap;
264
265	mtx_assert(&audit_pipe_mtx, MA_OWNED);
266
267	ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO);
268	if (ap == NULL)
269		return (NULL);
270	ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT;
271	TAILQ_INIT(&ap->ap_queue);
272	TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list);
273	audit_pipe_count++;
274	audit_pipe_ever++;
275	return (ap);
276}
277
278/*
279 * Free an audit pipe.  Assumes mutex is held, audit_pipe is still on the
280 * global list.  Frees any audit pipe entries in the queue.
281 */
282static void
283audit_pipe_free(struct audit_pipe *ap)
284{
285	struct audit_pipe_entry *ape;
286
287	mtx_assert(&audit_pipe_mtx, MA_OWNED);
288
289	TAILQ_REMOVE(&audit_pipe_list, ap, ap_list);
290	while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) {
291		TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
292		audit_pipe_entry_free(ape);
293		ap->ap_qlen--;
294	}
295	KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen"));
296	free(ap, M_AUDIT_PIPE);
297	audit_pipe_count--;
298}
299
300/*
301 * Audit pipe clone routine -- provide specific requested audit pipe, or a
302 * fresh one if a specific one is not requested.
303 */
304static void
305audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen,
306    struct cdev **dev)
307{
308	int i, u;
309
310	if (*dev != NULL)
311		return;
312
313	if (strcmp(name, AUDIT_PIPE_NAME) == 0)
314		u = -1;
315	else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1)
316		return;
317
318	i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0);
319	if (i) {
320		*dev = make_dev(&audit_pipe_cdevsw, unit2minor(u), UID_ROOT,
321		    GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u);
322		if (*dev != NULL) {
323			dev_ref(*dev);
324			(*dev)->si_flags |= SI_CHEAPCLONE;
325		}
326	}
327}
328
329/*
330 * Audit pipe open method.  Explicit suser check isn't used as this allows
331 * file permissions on the special device to be used to grant audit review
332 * access.
333 */
334static int
335audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
336{
337	struct audit_pipe *ap;
338
339	mtx_lock(&audit_pipe_mtx);
340	ap = dev->si_drv1;
341	if (ap == NULL) {
342		ap = audit_pipe_alloc();
343		if (ap == NULL) {
344			mtx_unlock(&audit_pipe_mtx);
345			return (ENOMEM);
346		}
347		dev->si_drv1 = ap;
348	} else {
349		KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open"));
350		mtx_unlock(&audit_pipe_mtx);
351		return (EBUSY);
352	}
353	ap->ap_open = 1;
354	mtx_unlock(&audit_pipe_mtx);
355	fsetown(td->td_proc->p_pid, &ap->ap_sigio);
356	return (0);
357}
358
359/*
360 * Close audit pipe, tear down all records, etc.
361 */
362static int
363audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
364{
365	struct audit_pipe *ap;
366
367	ap = dev->si_drv1;
368	KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL"));
369	KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open"));
370	funsetown(&ap->ap_sigio);
371	mtx_lock(&audit_pipe_mtx);
372	ap->ap_open = 0;
373	audit_pipe_free(ap);
374	dev->si_drv1 = NULL;
375	mtx_unlock(&audit_pipe_mtx);
376	return (0);
377}
378
379/*
380 * Audit pipe ioctl() routine.  Nothing for now, but eventually will allow
381 * setting and retrieval of current queue depth, queue limit, flush, etc.
382 *
383 * Would be desirable to support filtering, although perhaps something simple
384 * like an event mask, as opposed to something complicated like BPF.
385 */
386static int
387audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
388    struct thread *td)
389{
390	struct audit_pipe *ap;
391	int error;
392
393	ap = dev->si_drv1;
394	KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL"));
395	switch (cmd) {
396	case FIONBIO:
397		mtx_lock(&audit_pipe_mtx);
398		if (*(int *)data)
399			ap->ap_flags |= AUDIT_PIPE_NBIO;
400		else
401			ap->ap_flags &= ~AUDIT_PIPE_NBIO;
402		mtx_unlock(&audit_pipe_mtx);
403		error = 0;
404		break;
405
406	case FIONREAD:
407		mtx_lock(&audit_pipe_mtx);
408		if (TAILQ_FIRST(&ap->ap_queue) != NULL)
409			*(int *)data =
410			    TAILQ_FIRST(&ap->ap_queue)->ape_record_len;
411		else
412			*(int *)data = 0;
413		mtx_unlock(&audit_pipe_mtx);
414		error = 0;
415		break;
416
417	case FIOASYNC:
418		mtx_lock(&audit_pipe_mtx);
419		if (*(int *)data)
420			ap->ap_flags |= AUDIT_PIPE_ASYNC;
421		else
422			ap->ap_flags &= ~AUDIT_PIPE_ASYNC;
423		mtx_unlock(&audit_pipe_mtx);
424		error = 0;
425		break;
426
427	case FIOSETOWN:
428		error = fsetown(*(int *)data, &ap->ap_sigio);
429		break;
430
431	case FIOGETOWN:
432		*(int *)data = fgetown(&ap->ap_sigio);
433		error = 0;
434
435	default:
436		error = ENOTTY;
437	}
438	return (error);
439}
440
441/*
442 * Audit pipe read.  Pull one record off the queue and copy to user space.
443 * On error, the record is dropped.
444 */
445static int
446audit_pipe_read(struct cdev *dev, struct uio *uio, int flag)
447{
448	struct audit_pipe_entry *ape;
449	struct audit_pipe *ap;
450	int error;
451
452	ap = dev->si_drv1;
453	KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL"));
454	mtx_lock(&audit_pipe_mtx);
455	do {
456		/*
457		 * Wait for a record that fits into the read buffer, dropping
458		 * records that would be truncated if actually passed to the
459		 * process.  This helps maintain the discreet record read
460		 * interface.
461		 */
462		while ((ape = audit_pipe_pop(ap)) == NULL) {
463			if (ap->ap_flags & AUDIT_PIPE_NBIO) {
464				mtx_unlock(&audit_pipe_mtx);
465				return (EAGAIN);
466			}
467			error = cv_wait_sig(&audit_pipe_cv, &audit_pipe_mtx);
468			if (error) {
469				mtx_unlock(&audit_pipe_mtx);
470				return (error);
471			}
472		}
473		if (ape->ape_record_len <= uio->uio_resid)
474			break;
475		audit_pipe_entry_free(ape);
476		ap->ap_truncates++;
477	} while (1);
478	mtx_unlock(&audit_pipe_mtx);
479
480	/*
481	 * Now read record to user space memory.  Even if the read is short,
482	 * we abandon the remainder of the record, supporting only discreet
483	 * record reads.
484	 */
485	error = uiomove(ape->ape_record, ape->ape_record_len, uio);
486	audit_pipe_entry_free(ape);
487	return (error);
488}
489
490/*
491 * Audit pipe poll.
492 */
493static int
494audit_pipe_poll(struct cdev *dev, int events, struct thread *td)
495{
496	struct audit_pipe *ap;
497	int revents;
498
499	revents = 0;
500	ap = dev->si_drv1;
501	KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL"));
502	if (events & (POLLIN | POLLRDNORM)) {
503		mtx_lock(&audit_pipe_mtx);
504		if (TAILQ_FIRST(&ap->ap_queue) != NULL)
505			revents |= events & (POLLIN | POLLRDNORM);
506		else
507			selrecord(td, &ap->ap_selinfo);
508		mtx_unlock(&audit_pipe_mtx);
509	}
510	return (revents);
511}
512
513/*
514 * Initialize the audit pipe system.
515 */
516static void
517audit_pipe_init(void *unused)
518{
519
520	TAILQ_INIT(&audit_pipe_list);
521	mtx_init(&audit_pipe_mtx, "audit_pipe_mtx", NULL, MTX_DEF);
522	cv_init(&audit_pipe_cv, "audit_pipe_cv");
523
524	clone_setup(&audit_pipe_clones);
525	audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone,
526	    audit_pipe_clone, 0, 1000);
527	if (audit_pipe_eh_tag == NULL)
528		panic("audit_pipe_init: EVENTHANDLER_REGISTER");
529}
530
531SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init,
532    NULL);
533