Deleted Added
sdiff udiff text old ( 156884 ) new ( 159269 )
full compact
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

--- 11 unchanged lines hidden (view full) ---

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 156884 2006-03-19 15:39:03Z 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>

--- 13 unchanged lines hidden (view full) ---

50#include <security/audit/audit.h>
51#include <security/audit/audit_ioctl.h>
52#include <security/audit/audit_private.h>
53
54/*
55 * Implementation of a clonable special device providing a live stream of BSM
56 * audit data. This is a "tee" of the data going to the file. It provides
57 * unreliable but timely access to audit events. Consumers of this interface
58 * should be very careful to avoid introducing event cycles.
59 */
60
61/*
62 * Memory types.
63 */
64static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes");
65static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent",
66 "Audit pipe entries and buffers");
67
68/*
69 * Audit pipe buffer parameters.
70 */
71#define AUDIT_PIPE_QLIMIT_DEFAULT (128)
72#define AUDIT_PIPE_QLIMIT_MIN (0)
73#define AUDIT_PIPE_QLIMIT_MAX (1024)
74
75/*
76 * Description of an entry in an audit_pipe.
77 */
78struct audit_pipe_entry {
79 void *ape_record;
80 u_int ape_record_len;
81 TAILQ_ENTRY(audit_pipe_entry) ape_queue;
82};
83
84/*
85 * Description of an individual audit_pipe. Consists largely of a bounded
86 * length queue.
87 */
88#define AUDIT_PIPE_ASYNC 0x00000001
89#define AUDIT_PIPE_NBIO 0x00000002
90struct audit_pipe {
91 int ap_open; /* Device open? */
92 u_int ap_flags;

--- 4 unchanged lines hidden (view full) ---

97 u_int ap_qlen;
98 u_int ap_qlimit;
99
100 u_int64_t ap_inserts; /* Records added. */
101 u_int64_t ap_reads; /* Records read. */
102 u_int64_t ap_drops; /* Records dropped. */
103 u_int64_t ap_truncates; /* Records too long. */
104
105 TAILQ_HEAD(, audit_pipe_entry) ap_queue;
106
107 TAILQ_ENTRY(audit_pipe) ap_list;
108};
109
110/*
111 * Global list of audit pipes, mutex to protect it and the pipes. Finder
112 * grained locking may be desirable at some point.
113 */
114static TAILQ_HEAD(, audit_pipe) audit_pipe_list;
115static struct mtx audit_pipe_mtx;
116
117/*
118 * This CV is used to wakeup on an audit record write. Eventually, it should
119 * probably be per-pipe.
120 */
121static struct cv audit_pipe_cv;
122
123/*
124 * Cloning related variables and constants.
125 */
126#define AUDIT_PIPE_NAME "auditpipe"
127static eventhandler_tag audit_pipe_eh_tag;

--- 5 unchanged lines hidden (view full) ---

133static d_open_t audit_pipe_open;
134static d_close_t audit_pipe_close;
135static d_read_t audit_pipe_read;
136static d_ioctl_t audit_pipe_ioctl;
137static d_poll_t audit_pipe_poll;
138
139static struct cdevsw audit_pipe_cdevsw = {
140 .d_version = D_VERSION,
141 .d_flags = D_PSEUDO,
142 .d_open = audit_pipe_open,
143 .d_close = audit_pipe_close,
144 .d_read = audit_pipe_read,
145 .d_ioctl = audit_pipe_ioctl,
146 .d_poll = audit_pipe_poll,
147 .d_name = AUDIT_PIPE_NAME,
148};
149

--- 12 unchanged lines hidden (view full) ---

162audit_pipe_entry_free(struct audit_pipe_entry *ape)
163{
164
165 free(ape->ape_record, M_AUDIT_PIPE_ENTRY);
166 free(ape, M_AUDIT_PIPE_ENTRY);
167}
168
169/*
170 * Apparent individual record to a queue -- allocate queue-local buffer, and
171 * add to the queue. We try to drop from the head of the queue so that more
172 * recent events take precedence over older ones, but if allocation fails we
173 * do drop the new event.
174 */
175static void
176audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len)
177{
178 struct audit_pipe_entry *ape, *ape_remove;

--- 35 unchanged lines hidden (view full) ---

214 pgsigio(&ap->ap_sigio, SIGIO, 0);
215}
216
217/*
218 * audit_pipe_submit(): audit_worker submits audit records via this
219 * interface, which arranges for them to be delivered to pipe queues.
220 */
221void
222audit_pipe_submit(void *record, u_int record_len)
223{
224 struct audit_pipe *ap;
225
226 /*
227 * Lockless read to avoid mutex overhead if pipes are not in use.
228 */
229 if (TAILQ_FIRST(&audit_pipe_list) == NULL)
230 return;
231
232 mtx_lock(&audit_pipe_mtx);
233 TAILQ_FOREACH(ap, &audit_pipe_list, ap_list)
234 audit_pipe_append(ap, record, record_len);
235 audit_pipe_records++;
236 mtx_unlock(&audit_pipe_mtx);
237 cv_signal(&audit_pipe_cv);
238}
239
240/*
241 * Read the next record off of an audit pipe.
242 */
243static struct audit_pipe_entry *
244audit_pipe_pop(struct audit_pipe *ap)
245{
246 struct audit_pipe_entry *ape;
247
248 mtx_assert(&audit_pipe_mtx, MA_OWNED);
249

--- 18 unchanged lines hidden (view full) ---

268
269 mtx_assert(&audit_pipe_mtx, MA_OWNED);
270
271 ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO);
272 if (ap == NULL)
273 return (NULL);
274 ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT;
275 TAILQ_INIT(&ap->ap_queue);
276 TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list);
277 audit_pipe_count++;
278 audit_pipe_ever++;
279 return (ap);
280}
281
282/*
283 * Free an audit pipe. Assumes mutex is held, audit_pipe is still on the
284 * global list. Frees any audit pipe entries in the queue.
285 */
286static void
287audit_pipe_free(struct audit_pipe *ap)
288{
289 struct audit_pipe_entry *ape;
290
291 mtx_assert(&audit_pipe_mtx, MA_OWNED);
292
293 TAILQ_REMOVE(&audit_pipe_list, ap, ap_list);
294 while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) {
295 TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
296 audit_pipe_entry_free(ape);
297 ap->ap_qlen--;
298 }
299 KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qlen"));
300 free(ap, M_AUDIT_PIPE);
301 audit_pipe_count--;
302}
303
304/*
305 * Audit pipe clone routine -- provide specific requested audit pipe, or a
306 * fresh one if a specific one is not requested.
307 */

--- 78 unchanged lines hidden (view full) ---

386 *
387 * Would be desirable to support filtering, although perhaps something simple
388 * like an event mask, as opposed to something complicated like BPF.
389 */
390static int
391audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
392 struct thread *td)
393{
394 struct audit_pipe *ap;
395 int error;
396
397 ap = dev->si_drv1;
398 KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL"));
399 switch (cmd) {
400 case FIONBIO:
401 mtx_lock(&audit_pipe_mtx);
402 if (*(int *)data)
403 ap->ap_flags |= AUDIT_PIPE_NBIO;
404 else
405 ap->ap_flags &= ~AUDIT_PIPE_NBIO;
406 mtx_unlock(&audit_pipe_mtx);

--- 55 unchanged lines hidden (view full) ---

462 error = 0;
463 break;
464
465 case AUDITPIPE_GET_QLIMIT_MAX:
466 *(u_int *)data = AUDIT_PIPE_QLIMIT_MAX;
467 error = 0;
468 break;
469
470 case AUDITPIPE_GET_INSERTS:
471 *(u_int *)data = ap->ap_inserts;
472 error = 0;
473 break;
474
475 case AUDITPIPE_GET_READS:
476 *(u_int *)data = ap->ap_reads;
477 error = 0;

--- 13 unchanged lines hidden (view full) ---

491 error = ENOTTY;
492 }
493 return (error);
494}
495
496/*
497 * Audit pipe read. Pull one record off the queue and copy to user space.
498 * On error, the record is dropped.
499 */
500static int
501audit_pipe_read(struct cdev *dev, struct uio *uio, int flag)
502{
503 struct audit_pipe_entry *ape;
504 struct audit_pipe *ap;
505 int error;
506

--- 81 unchanged lines hidden ---