Bug Summary

File:bsm.c
Location:line 443, column 13
Description:Access to field 'bm_raw' results in a dereference of a null pointer (loaded from variable 'bm')

Annotated Source Code

1/*-
2 * Copyright (c) 2007 Aaron L. Meihm
3 * Copyright (c) 2007 Christian S.J. Peron
4 * All rights reserved.
5 *
6 * $Id: bsm.c,v 1.45 2007/10/09 02:24:30 csjp Exp $
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30#include "includes.h"
31
32b_head_t s_parent, s_dynamic;
33
34static int
35bsm_match_event(struct bsm_state *bm, struct bsm_record_data *bd)
36{
37 struct au_event_ent *aue;
38 int i, match, evdata;
39 struct array *a;
40
41 switch (bm->bm_event_type) {
42 case SET_TYPE_AUCLASS:
43 /*
44 * XXXCSJP: Could this get quite expensive under high loads if
45 * not cached?
46 */
47 aue = getauevnum(bd->br_event);
48 if (aue == NULL((void *)0)) {
49 bsmtrace_error(0, "invalid event type: %d",
50 bd->br_event);
51 return (0);
52 }
53 evdata = aue->ae_class;
54 break;
55 case SET_TYPE_AUEVENT:
56 evdata = bd->br_event;
57 break;
58 default:
59 assert(0)((0) ? (void)0 : __assert(__func__, "bsm.c", 59, "0"));
60 }
61 assert(bm->bm_event_type == SET_TYPE_AUCLASS ||((bm->bm_event_type == SET_TYPE_AUCLASS || bm->bm_event_type
== SET_TYPE_AUEVENT) ? (void)0 : __assert(__func__, "bsm.c",
62, "bm->bm_event_type == SET_TYPE_AUCLASS || bm->bm_event_type == SET_TYPE_AUEVENT"
))
62 bm->bm_event_type == SET_TYPE_AUEVENT)((bm->bm_event_type == SET_TYPE_AUCLASS || bm->bm_event_type
== SET_TYPE_AUEVENT) ? (void)0 : __assert(__func__, "bsm.c",
62, "bm->bm_event_type == SET_TYPE_AUCLASS || bm->bm_event_type == SET_TYPE_AUEVENT"
))
;
63 a = &bm->bm_auditevent;
64 match = 0;
65 for (i = 0; i < a->a_cnt; i++) {
66 switch (bm->bm_event_type) {
67 case SET_TYPE_AUCLASS:
68 if ((evdata & a->a_data.value[i]) != 0)
69 match = 1;
70 break;
71 case SET_TYPE_AUEVENT:
72 if (a->a_data.value[i] == evdata)
73 match = 1;
74 }
75 }
76 if ((bm->bm_event_flags & BSM_STATE_EVENT_ANY0x00000001U) != 0)
77 match = 1;
78 if (a->a_negated != 0)
79 match = !match;
80 if (!match)
81 return (0);
82 switch (bm->bm_status) {
83 case EVENT_SUCCESS_OR_FAILURE:
84 match = 1;
85 break;
86 case EVENT_SUCCESS:
87 match = (bd->br_status == 0);
88 break;
89 case EVENT_FAILURE:
90 match = (bd->br_status != 0);
91 break;
92 default:
93 assert(0)((0) ? (void)0 : __assert(__func__, "bsm.c", 93, "0"));
94 }
95 return (match);
96}
97
98static int
99bsm_match_object(struct bsm_state *bm, struct bsm_record_data *bd)
100{
101 int i, slen, match;
102 struct array *ap;
103#ifdef PCRE
104 int rc;
105#endif
106
107 /*
108 * XXXCSJP
109 *
110 * It is possible for various file events to NOT audit the pathname
111 * because they are operating on file descriptors. As a direct result
112 * our event specification could have specified a generic file event
113 * class like "fr" and "fw" which includes events like ftruncate(2)
114 * which does not audit the pathname:
115 *
116 * header,108,10,ftruncate(2),0,Sat Apr 14 19:15:11 2007, + 966 msec
117 * argument,1,0x3,fd
118 * attribute,644,test,test,80,8078349,32267048
119 * subject,test,test,test,test,test,4810,4805,56278,207.161.19.21
120 * return,success,0
121 * trailer,108
122 *
123 * The question becomes, since we can not prove that there was a write
124 * on the object we are interested in, but a write on some anonymous
125 * object has occured, should we still raise an alert?
126 */
127
128 /*
129 * Check to see if the user has supplied any objects. If not, then this
130 * is a member match.
131 */
132 ap = &bm->bm_objects;
133 if (ap->a_cnt == 0)
134 return (1);
135 /*
136 * For BSM records which reference a file but do not contain a path
137 * (i.e. fstat(2), fchmod(2) et al), scan the pathname cache for it's
138 * device and see if we can pullup the pathname.
139 */
140 if (bd->br_dev != 0 && bd->br_inode != 0 && bd->br_path == NULL((void *)0))
141 bd->br_path = fcache_search(bd->br_dev, bd->br_inode);
142 /*
143 * We are interested in particular objects, but the audit record has
144 * not supplied any. We will treat this as a fail to match.
145 */
146 if (bd->br_path == NULL((void *)0))
147 return (0);
148 /*
149 * Otherwise, the record contains a pathname which may be represented as
150 * a static string, or as a pcre.
151 */
152 if (ap->a_type == STRING_ARRAY2) {
153 for (match = 0, i = 0; i < ap->a_cnt; i++) {
154 slen = strlen(ap->a_data.string[i]);
155 if (strncmp(ap->a_data.string[i], bd->br_path, slen)
156 == 0) {
157 match = 1;
158 break;
159 }
160 }
161#ifdef PCRE
162 } else if (ap->a_type == PCRE_ARRAY) {
163 slen = strlen(bd->br_path);
164 for (match = 0, i = 0; i < ap->a_cnt; i++) {
165 rc = pcre_exec(ap->a_data.pcre[i], NULL((void *)0), bd->br_path,
166 slen, 0, 0, NULL((void *)0), 0);
167 if (rc == 0) {
168 match = 1;
169 break;
170 } else if (rc < -1) {
171 bsmtrace_error(0, "pcre exec failed for pattern"
172 " %s on path %s", ap->a_data.pcre[i],
173 bd->br_path);
174 }
175 }
176#endif
177 } else
178 /* No other type makes sense. */
179 assert(0)((0) ? (void)0 : __assert(__func__, "bsm.c", 179, "0"));
180 /* Handle negation. */
181 if (ap->a_negated != 0)
182 match = !match;
183 return (match);
184}
185
186static void
187bsm_log_sequence(struct bsm_sequence *bs, struct bsm_record_data *bd)
188{
189 struct logchannel *lc;
190
191 /*
192 * If the user specified the -b flag, dump the last BSM record which
193 * resulted in the sequence match to stdout.
194 */
195 if (opts.bflag != 0)
196 (void) write(1, bd->br_raw, bd->br_raw_len);
197 /*
198 * For now, if there is no log channel specified which this particular
199 * sequence, use stderr. This really needs to be fixed to look at what
200 * if anything is specified in the global logging options.
201 */
202 if (TAILQ_EMPTY(&bs->bs_log_channel)((&bs->bs_log_channel)->tqh_first == ((void *)0)) && opts.Fflag != 0) {
203 log_bsm_stderr(NULL((void *)0), bs, bd);
204 return;
205 }
206 TAILQ_FOREACH(lc, &bs->bs_log_channel, log_glue)for ((lc) = (((&bs->bs_log_channel))->tqh_first); (
lc); (lc) = (((lc))->log_glue.tqe_next))
207 (*lc->log_handler)(lc, bs, bd);
208}
209
210static int
211bsm_state_match(struct bsm_sequence *bs, struct bsm_record_data *bd)
212{
213 struct bsm_state *bm;
214 int match;
215
216 assert((bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0)(((bs->bs_seq_flags & 0x00000002U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 216, "(bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0"
))
;
217 bm = bs->bs_cur_state;
218 /*
219 * Do we have a subject match? At this point we EXPLICITLY do not handle
220 * negation as it should have been handled by the parent.
221 */
222 match = (bs->bs_subj.bs_dyn_subj == bsm_get_subj(bs, bd));
223 if (match == 0)
224 return (0);
225 /* Match event. */
226 match = bsm_match_event(bm, bd);
227 if (match == 0)
228 return (0);
229 /* Match object. */
230 match = bsm_match_object(bm, bd);
231 return (match);
232}
233
234static int
235bsm_check_subj_array(u_int subj, struct array *ap)
236{
237 int match, i;
238
239 for (match = 0, i = 0; i < ap->a_cnt; i++)
240 if (ap->a_data.value[i] == subj)
241 match = 1;
242 if (ap->a_negated != 0)
243 match = !match;
244 return (match);
245}
246
247int
248bsm_get_subj(struct bsm_sequence *bs, struct bsm_record_data *bd)
249{
250 u_int subj;
251
252 switch (bs->bs_subj_type) {
253 case SET_TYPE_AUID:
254 subj = bd->br_auid;
255 break;
256 case SET_TYPE_RUID:
257 subj = bd->br_ruid;
258 break;
259 case SET_TYPE_EUID:
260 subj = bd->br_euid;
261 break;
262 case SET_TYPE_RGID:
263 subj = bd->br_rgid;
264 break;
265 case SET_TYPE_EGID:
266 subj = bd->br_egid;
267 break;
268 default:
269 bsmtrace_error(0, "invalid subject type %d", bs->bs_subj_type);
270 assert(0)((0) ? (void)0 : __assert(__func__, "bsm.c", 270, "0"));
271 }
272 return (subj);
273}
274
275static int
276bsm_check_parent_sequence(struct bsm_sequence *bs, struct bsm_record_data *bd)
277{
278 struct bsm_state *bm;
279 u_int subj, match;
280
281 assert((bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0)(((bs->bs_seq_flags & 0x00000001U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 281, "(bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0"
))
;
282 subj = bsm_get_subj(bs, bd);
283 match = bsm_check_subj_array(subj, &bs->bs_subj.bs_par_subj);
284 if (match == 0 && (bs->bs_seq_flags & BSM_SEQUENCE_SUBJ_ANY0x00000008U) == 0)
285 return (0);
286 assert(bs->bs_cur_state == NULL && !TAILQ_EMPTY(&bs->bs_mhead))((bs->bs_cur_state == ((void *)0) && !((&bs->
bs_mhead)->tqh_first == ((void *)0))) ? (void)0 : __assert
(__func__, "bsm.c", 286, "bs->bs_cur_state == NULL && !TAILQ_EMPTY(&bs->bs_mhead)"
))
;
287 bm = TAILQ_FIRST(&bs->bs_mhead)((&bs->bs_mhead)->tqh_first);
288 /* Match event. */
289 match = bsm_match_event(bm, bd);
290 if (match == 0)
291 return (0);
292 /* Match object. */
293 match = bsm_match_object(bm, bd);
294 return (match);
295}
296
297static struct bsm_sequence *
298bsm_dyn_sequence_find(struct bsm_sequence *bs, struct bsm_record_data *bd,
299 u_int subj)
300{
301 struct bsm_sequence *bs_dyn;
302
303 assert((bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0)(((bs->bs_seq_flags & 0x00000001U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 303, "(bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0"
))
;
304 TAILQ_FOREACH(bs_dyn, &s_dynamic, bs_glue)for ((bs_dyn) = (((&s_dynamic))->tqh_first); (bs_dyn);
(bs_dyn) = (((bs_dyn))->bs_glue.tqe_next))
305 if (bs_dyn->bs_par_sequence == bs &&
306 bs_dyn->bs_subj_type == bs->bs_subj_type &&
307 bs_dyn->bs_subj.bs_dyn_subj == subj)
308 return (bs_dyn);
309 return (NULL((void *)0));
310}
311
312static void
313bsm_free_raw_data(struct bsm_sequence *bs)
314{
315 struct bsm_state *bm;
316
317 TAILQ_FOREACH(bm, &bs->bs_mhead, bm_glue)for ((bm) = (((&bs->bs_mhead))->tqh_first); (bm); (
bm) = (((bm))->bm_glue.tqe_next))
{
318 if (bm->bm_raw != NULL((void *)0))
319 free(bm->bm_raw);
320 bm->bm_raw_len = 0;
321 }
322}
323
324static void
325bsm_copy_states(struct bsm_sequence *bs_old, struct bsm_sequence *bs_new)
326{
327 struct bsm_state *bm, *bm2;
328
329 /*
330 * Make sure that we initialize the new tailq head to NULL
331 * otherwise we would be recursively adding states.
332 */
333 dprintf("%s: copying states from sequence %p\n", __func__, bs_old);
334 TAILQ_INIT(&bs_new->bs_mhead)do { (((&bs_new->bs_mhead))->tqh_first) = ((void *)
0); (&bs_new->bs_mhead)->tqh_last = &(((&bs_new
->bs_mhead))->tqh_first);; } while (0)
;
15
Within the expansion of the macro 'TAILQ_INIT':
a
Null pointer value stored to field 'tqh_first'
335 TAILQ_FOREACH(bm, &bs_old->bs_mhead, bm_glue)for ((bm) = (((&bs_old->bs_mhead))->tqh_first); (bm
); (bm) = (((bm))->bm_glue.tqe_next))
{
336 bm2 = calloc(1, sizeof(*bm2));
337 if (bm2 == NULL((void *)0)) {
338 bsmtrace_error(0, "%s: calloc failed",
339 __func__);
340 exit(1);
341 }
342 *bm2 = *bm;
343 TAILQ_INSERT_TAIL(&bs_new->bs_mhead, bm2, bm_glue)do {; (((bm2))->bm_glue.tqe_next) = ((void *)0); (bm2)->
bm_glue.tqe_prev = (&bs_new->bs_mhead)->tqh_last; *
(&bs_new->bs_mhead)->tqh_last = (bm2); (&bs_new
->bs_mhead)->tqh_last = &(((bm2))->bm_glue.tqe_next
);;; } while (0)
;
344 }
345}
346
347static caddr_t
348bsm_copy_record_data(struct bsm_record_data *bd)
349{
350 caddr_t record;
351
352 record = malloc(bd->br_raw_len);
353 if (record == NULL((void *)0))
354 bsmtrace_error(1, "malloc failed");
355 bcopy(bd->br_raw, record, bd->br_raw_len);
356 return (record);
357}
358
359static void
360bsm_free_sequence(struct bsm_sequence *bs)
361{
362 struct bsm_state *bm;
363
364 dprintf("%s: freeing sequence %p\n", __func__, bs);
365 assert((bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0)(((bs->bs_seq_flags & 0x00000002U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 365, "(bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0"
))
;
366 bsm_free_raw_data(bs);
367 while (!TAILQ_EMPTY(&bs->bs_mhead)((&bs->bs_mhead)->tqh_first == ((void *)0))) {
368 bm = TAILQ_FIRST(&bs->bs_mhead)((&bs->bs_mhead)->tqh_first);
369 TAILQ_REMOVE(&bs->bs_mhead, bm, bm_glue)do {;;;; if (((((bm))->bm_glue.tqe_next)) != ((void *)0)) (
((bm))->bm_glue.tqe_next)->bm_glue.tqe_prev = (bm)->
bm_glue.tqe_prev; else { (&bs->bs_mhead)->tqh_last =
(bm)->bm_glue.tqe_prev;; } *(bm)->bm_glue.tqe_prev = (
((bm))->bm_glue.tqe_next);;;; } while (0)
;
370 free(bm);
371 }
372 free(bs);
373#ifdef INVARIANTS
374 bs = 0xdeadc0de;
375#endif
376}
377
378/*
379 * Implement a function which produces random values with an interesting
380 * property. This function will produce a random value, where the probability
381 * of this value being between 0 and size is specified by prob.
382 *
383 * Let v be > 0 and < 1 (random value)
384 * Let P (probability) be > 0 and < 1
385 *
386 * Rv = v * (range / P);
387 *
388 */
389static float
390bsm_rand_bias(float size, float prob)
391{
392 unsigned int val;
393 float r;
394
395 val = arc4random();
396 r = (float)val;
397 while (r > 1)
398 r = r / 10;
399 return (r * (size / prob));
400}
401
402static struct bsm_sequence *
403bsm_sequence_clone(struct bsm_sequence *bs, u_int subj,
404 struct bsm_record_data *bd)
405{
406 struct bsm_sequence *bs_new;
407 struct bsm_state *bm;
408 float size, prob;
409 int rnd;
410
411 bs_new = bsm_dyn_sequence_find(bs, bd, subj);
412 if (bs_new != NULL((void *)0)) {
11
Taking false branch
413 if ((bs_new->bs_seq_flags & BSM_SEQUENCE_DESTROY0x00000004U) != 0) {
414 TAILQ_REMOVE(&s_dynamic, bs_new, bs_glue)do {;;;; if (((((bs_new))->bs_glue.tqe_next)) != ((void *)
0)) (((bs_new))->bs_glue.tqe_next)->bs_glue.tqe_prev = (
bs_new)->bs_glue.tqe_prev; else { (&s_dynamic)->tqh_last
= (bs_new)->bs_glue.tqe_prev;; } *(bs_new)->bs_glue.tqe_prev
= (((bs_new))->bs_glue.tqe_next);;;; } while (0)
;
415 bsm_free_sequence(bs_new);
416 }
417 return (NULL((void *)0));
418 }
419 bs_new = calloc(1, sizeof(*bs_new));
420 if (bs_new == NULL((void *)0)) {
12
Assuming 'bs_new' is not equal to null
13
Taking false branch
421 bsmtrace_error(0, "%s: calloc failed", __func__);
422 return (NULL((void *)0));
423 }
424 dprintf("%u:%s: sequence %p cloned and linked\n",
425 time(NULL((void *)0)), bs->bs_label, bs_new);
426 *bs_new = *bs;
427 /*
428 * The BSM sequence flags are mutually exclusive.
429 */
430 bs_new->bs_seq_flags &= ~BSM_SEQUENCE_PARENT0x00000001U;
431 bs_new->bs_seq_flags |= BSM_SEQUENCE_DYNAMIC0x00000002U;
432 bs_new->bs_subj.bs_dyn_subj = subj;
433 bs_new->bs_par_sequence = bs;
434 bs_new->bs_first_match = bd->br_sec;
435 bs_new->bs_mtime = bd->br_sec;
436 bsm_copy_states(bs, bs_new);
14
Calling 'bsm_copy_states'
16
Returning from 'bsm_copy_states'
437 /*
438 * If we have made it this far, we can assume that we have more than
439 * one finite state defined.
440 */
441 assert(TAILQ_FIRST(&bs->bs_mhead) != TAILQ_LAST(&bs->bs_mhead, tailq))((((&bs->bs_mhead)->tqh_first) != (*(((struct tailq
*)((&bs->bs_mhead)->tqh_last))->tqh_last))) ? (
void)0 : __assert(__func__, "bsm.c", 441, "TAILQ_FIRST(&bs->bs_mhead) != TAILQ_LAST(&bs->bs_mhead, tailq)"
))
;
442 bm = TAILQ_FIRST(&bs_new->bs_mhead)((&bs_new->bs_mhead)->tqh_first);
17
Null pointer value stored to 'bm'
443 bm->bm_raw = bsm_copy_record_data(bd);
18
Access to field 'bm_raw' results in a dereference of a null pointer (loaded from variable 'bm')
444 bm->bm_raw_len = bd->br_raw_len;
445 bs_new->bs_cur_state = TAILQ_NEXT(bm, bm_glue)((bm)->bm_glue.tqe_next);
446 /*
447 * Handle the randomization of the timeout window here.
448 */
449 if (bs_new->bs_seq_time_wnd != 0) {
450 size = bs_new->bs_seq_time_wnd;
451 if (bs_new->bs_seq_time_wnd_prob > 0)
452 prob = (float)bs_new->bs_seq_time_wnd_prob / 100;
453 else
454 prob = (float)(65 / 100);
455 rnd = bsm_rand_bias(size, prob);
456 bs_new->bs_timeout = bs_new->bs_timeout + rnd;
457 }
458 return (bs_new);
459}
460
461static void
462bsm_sequence_scan(struct bsm_record_data *bd)
463{
464 struct bsm_sequence *bs, *bs_dyn, *bs_temp;
465 struct bsm_state *bm;
466 u_int match, subj;
467
468 /* Match dynamic sequences. */
469 TAILQ_FOREACH_SAFE(bs, &s_dynamic, bs_glue, bs_temp)for ((bs) = (((&s_dynamic))->tqh_first); (bs) &&
((bs_temp) = (((bs))->bs_glue.tqe_next), 1); (bs) = (bs_temp
))
{
470 assert((bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0)(((bs->bs_seq_flags & 0x00000002U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 470, "(bs->bs_seq_flags & BSM_SEQUENCE_DYNAMIC) != 0"
))
;
471 /*
472 * Make sure that every sequence here has multiple states.
473 */
474 assert(TAILQ_LAST(&bs->bs_mhead, tailq) !=(((*(((struct tailq *)((&bs->bs_mhead)->tqh_last))->
tqh_last)) != ((&bs->bs_mhead)->tqh_first)) ? (void
)0 : __assert(__func__, "bsm.c", 475, "TAILQ_LAST(&bs->bs_mhead, tailq) != TAILQ_FIRST(&bs->bs_mhead)"
))
475 TAILQ_FIRST(&bs->bs_mhead))(((*(((struct tailq *)((&bs->bs_mhead)->tqh_last))->
tqh_last)) != ((&bs->bs_mhead)->tqh_first)) ? (void
)0 : __assert(__func__, "bsm.c", 475, "TAILQ_LAST(&bs->bs_mhead, tailq) != TAILQ_FIRST(&bs->bs_mhead)"
))
;
476 /*
477 * If the sequence was marked for destruction and it didn't
478 * match any parent sequences, destroy it here. The only
479 * reason we do not destroy is we do not want the parent
480 * matching on it.
481 */
482 if ((bs->bs_seq_flags & BSM_SEQUENCE_DESTROY0x00000004U) != 0) {
483 TAILQ_REMOVE(&s_dynamic, bs, bs_glue)do {;;;; if (((((bs))->bs_glue.tqe_next)) != ((void *)0)) (
((bs))->bs_glue.tqe_next)->bs_glue.tqe_prev = (bs)->
bs_glue.tqe_prev; else { (&s_dynamic)->tqh_last = (bs)
->bs_glue.tqe_prev;; } *(bs)->bs_glue.tqe_prev = (((bs)
)->bs_glue.tqe_next);;;; } while (0)
;
484 bsm_free_sequence(bs);
485 continue;
486 }
487 if (bs->bs_timeout > 0 &&
488 (bd->br_sec - bs->bs_mtime) > bs->bs_timeout) {
489 TAILQ_REMOVE(&s_dynamic, bs, bs_glue)do {;;;; if (((((bs))->bs_glue.tqe_next)) != ((void *)0)) (
((bs))->bs_glue.tqe_next)->bs_glue.tqe_prev = (bs)->
bs_glue.tqe_prev; else { (&s_dynamic)->tqh_last = (bs)
->bs_glue.tqe_prev;; } *(bs)->bs_glue.tqe_prev = (((bs)
)->bs_glue.tqe_next);;;; } while (0)
;
490 bsm_free_sequence(bs);
491 continue;
492 }
493 match = bsm_state_match(bs, bd);
494 if (match == 0)
495 continue;
496 bm = bs->bs_cur_state;
497 bsm_run_trigger(bd, bm);
498 if (opts.bflag)
499 (void) write(1, bd->br_raw, bd->br_raw_len);
500 bm->bm_raw = bsm_copy_record_data(bd);
501 bm->bm_raw_len = bd->br_raw_len;
502 /* Final state (complete sequence) has been matched. */
503 if (bm == TAILQ_LAST(&bs->bs_mhead, tailq)(*(((struct tailq *)((&bs->bs_mhead)->tqh_last))->
tqh_last))
) {
504 assert((bs->bs_seq_flags & BSM_SEQUENCE_DESTROY) == 0)(((bs->bs_seq_flags & 0x00000004U) == 0) ? (void)0 : __assert
(__func__, "bsm.c", 504, "(bs->bs_seq_flags & BSM_SEQUENCE_DESTROY) == 0"
))
;
505 bsm_log_sequence(bs, bd);
506 bs->bs_seq_flags |= BSM_SEQUENCE_DESTROY0x00000004U;
507 continue;
508 }
509 dprintf("%s: state transition cur=%p\n", bs->bs_label,
510 TAILQ_NEXT(bm, bm_glue)((bm)->bm_glue.tqe_next));
511 bs->bs_cur_state = TAILQ_NEXT(bm, bm_glue)((bm)->bm_glue.tqe_next);
512 }
513 /* Match parent sequences. */
514 TAILQ_FOREACH(bs, &s_parent, bs_glue)for ((bs) = (((&s_parent))->tqh_first); (bs); (bs) = (
((bs))->bs_glue.tqe_next))
{
515 assert((bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0)(((bs->bs_seq_flags & 0x00000001U) != 0) ? (void)0 : __assert
(__func__, "bsm.c", 515, "(bs->bs_seq_flags & BSM_SEQUENCE_PARENT) != 0"
))
;
516 match = bsm_check_parent_sequence(bs, bd);
517 if (match == 0)
1
Taking true branch
3
Taking true branch
5
Taking true branch
7
Taking false branch
518 continue;
2
Execution continues on line 514
4
Execution continues on line 514
6
Execution continues on line 514
519 bsm_run_trigger(bd, TAILQ_FIRST(&bs->bs_mhead)((&bs->bs_mhead)->tqh_first));
520 if (opts.bflag)
8
Taking false branch
521 (void) write(1, bd->br_raw, bd->br_raw_len);
522 /*
523 * It's possible that the parent sequence has only one state
524 * defined, in which case, raise an alert and don't bother
525 * creating a dynamic object for it.
526 */
527 if (TAILQ_FIRST(&bs->bs_mhead)((&bs->bs_mhead)->tqh_first) ==
9
Taking false branch
528 TAILQ_LAST(&bs->bs_mhead, tailq)(*(((struct tailq *)((&bs->bs_mhead)->tqh_last))->
tqh_last))
) {
529 bsm_log_sequence(bs, bd);
530 continue;
531 }
532 dprintf("%d:%s: state transition\n", time(NULL((void *)0)), bs->bs_label);
533 subj = bsm_get_subj(bs, bd);
534 bs_dyn = bsm_sequence_clone(bs, subj, bd);
10
Calling 'bsm_sequence_clone'
535 if (bs_dyn == NULL((void *)0))
536 continue;
537 TAILQ_INSERT_HEAD(&s_dynamic, bs_dyn, bs_glue)do {; if (((((bs_dyn))->bs_glue.tqe_next) = (((&s_dynamic
))->tqh_first)) != ((void *)0)) (((&s_dynamic))->tqh_first
)->bs_glue.tqe_prev = &(((bs_dyn))->bs_glue.tqe_next
); else (&s_dynamic)->tqh_last = &(((bs_dyn))->
bs_glue.tqe_next); (((&s_dynamic))->tqh_first) = (bs_dyn
); (bs_dyn)->bs_glue.tqe_prev = &(((&s_dynamic))->
tqh_first);;; } while (0)
;
538 }
539}
540
541void
542bsm_loop(char *atrail)
543{
544 struct bsm_record_data bd;
545 int reclen, bytesread, recsread;
546 u_char *bsm_rec;
547 tokenstr_t tok;
548 FILE *fp;
549
550 if (strcmp(opts.aflag, "-") == 0)
551 fp = stdin__stdinp;
552 else
553 fp = fopen(opts.aflag, "r");
554 if (fp == NULL((void *)0))
555 bsmtrace_error(1, "%s: %s", opts.aflag, strerror(errno(* __error())));
556 if (strcmp(opts.aflag, DEFAULT_AUDIT_TRAIL"/dev/auditpipe") == 0)
557 audit_pipe_fd = fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp));
558 dprintf("opened '%s' for audit monitoring\n", opts.aflag);
559 /*
560 * Process the BSM record, one token at a time.
561 */
562 recsread = 0;
563 while ((reclen = au_read_rec(fp, &bsm_rec)) != -1) {
564 /*
565 * If we are reading data from the audit pipe, we need check
566 * how many records, if any have been dropped by the kernel.
567 * If any record loss has been identified, pipe_analyze_loss()
568 * should increase the internal audit pipe queue length.
569 */
570 if (audit_pipe_fd > 0 && (recsread % 50) == 0)
571 pipe_analyze_loss(audit_pipe_fd);
572 bzero(&bd, sizeof(bd));
573 bd.br_raw = bsm_rec;
574 bd.br_raw_len = reclen;
575 bytesread = 0;
576 /*
577 * Iterate through each BSM token, extracting the bits that are
578 * required to starting processing sequences.
579 */
580 while (bytesread < reclen) {
581 if (au_fetch_tok(&tok, bsm_rec + bytesread,
582 reclen - bytesread) < 0) {
583 bsmtrace_error(0, "incomplete record");
584 break;
585 }
586 switch (tok.id) {
587 case AUT_HEADER320x14:
588 bd.br_event = tok.tt.hdr32.e_type;
589 bd.br_sec = tok.tt.hdr32.s;
590 bd.br_usec = tok.tt.hdr32.ms;
591 break;
592 case AUT_HEADER32_EX0x15:
593 bd.br_event = tok.tt.hdr32_ex.e_type;
594 bd.br_sec = tok.tt.hdr32_ex.s;
595 bd.br_usec = tok.tt.hdr32_ex.ms;
596 break;
597 case AUT_HEADER640x74:
598 bd.br_event = tok.tt.hdr64.e_type;
599 bd.br_sec = tok.tt.hdr64.s;
600 bd.br_usec = tok.tt.hdr64.ms;
601 break;
602 case AUT_HEADER64_EX0x79:
603 bd.br_event = tok.tt.hdr32_ex.e_type;
604 bd.br_sec = tok.tt.hdr64_ex.s;
605 bd.br_usec = tok.tt.hdr64_ex.ms;
606 break;
607 case AUT_SUBJECT320x24:
608 bd.br_auid = tok.tt.subj32.auid;
609 bd.br_euid = tok.tt.subj32.euid;
610 bd.br_egid = tok.tt.subj32.egid;
611 bd.br_ruid = tok.tt.subj32.ruid;
612 bd.br_rgid = tok.tt.subj32.rgid;
613 bd.br_pid = tok.tt.subj32.pid;
614 bd.br_sid = tok.tt.subj32.sid;
615 break;
616 case AUT_SUBJECT640x75:
617 bd.br_auid = tok.tt.subj64.auid;
618 bd.br_euid = tok.tt.subj64.euid;
619 bd.br_egid = tok.tt.subj64.egid;
620 bd.br_ruid = tok.tt.subj64.ruid;
621 bd.br_rgid = tok.tt.subj64.rgid;
622 bd.br_pid = tok.tt.subj64.pid;
623 bd.br_sid = tok.tt.subj64.sid;
624 break;
625 case AUT_SUBJECT32_EX0x7a:
626 bd.br_auid = tok.tt.subj32_ex.auid;
627 bd.br_euid = tok.tt.subj32_ex.euid;
628 bd.br_egid = tok.tt.subj32_ex.egid;
629 bd.br_ruid = tok.tt.subj32_ex.ruid;
630 bd.br_rgid = tok.tt.subj32_ex.rgid;
631 bd.br_pid = tok.tt.subj32.pid;
632 bd.br_sid = tok.tt.subj32.sid;
633 break;
634 case AUT_RETURN320x27:
635 bd.br_status = (u_int64_t)tok.tt.ret32.status;
636 break;
637 case AUT_RETURN640x72:
638 bd.br_status = tok.tt.ret64.err;
639 break;
640 case AUT_ATTR0x31:
641 case AUT_ATTR320x3e:
642 bd.br_dev = tok.tt.attr32.fsid;
643 bd.br_inode = tok.tt.attr32.nid;
644 break;
645 case AUT_PATH0x23:
646 bd.br_path = tok.tt.path.path;
647 break;
648 }
649 bytesread += tok.len;
650 }
651 if (bd.br_path != NULL((void *)0) && bd.br_dev != 0 && bd.br_inode != 0)
652 fcache_add_entry(bd.br_dev, bd.br_inode, bd.br_path);
653 bsm_sequence_scan(&bd);
654 free(bsm_rec);
655 recsread++;
656 }
657 (void) fclose(fp);
658}