diff --git a/auparse/auparse-idata.h b/auparse/auparse-idata.h index eaca86a3d..e55fa1a65 100644 --- a/auparse/auparse-idata.h +++ b/auparse/auparse-idata.h @@ -26,6 +26,7 @@ #include "config.h" #include "dso.h" +#include "auparse.h" #include "auparse-defs.h" typedef struct _idata { @@ -38,14 +39,16 @@ typedef struct _idata { const char *val; // value of field being interpreted } idata; +#define NEVER_LOADED 0xFFFF int auparse_interp_adjust_type(int rtype, const char *name, const char *val); -char *auparse_do_interpretation(int type, const idata *id, - auparse_esc_t escape_mode); -void _auparse_load_interpretations(const char *buf); -void _auparse_free_interpretations(void); -const char *_auparse_lookup_interpretation(const char *name); -void _auparse_flush_caches(void); +char *auparse_do_interpretation(auparse_state_t *au, int type, const idata *id, + auparse_esc_t escape_mode); +void _auparse_load_interpretations(auparse_state_t *au, const char *buf); +void _auparse_free_interpretations(auparse_state_t *au); +const char *_auparse_lookup_interpretation(auparse_state_t *au, + const char *name) __attribute_malloc__ __attr_dealloc_free; +void _auparse_flush_caches(auparse_state_t *au); #endif diff --git a/auparse/auparse.c b/auparse/auparse.c index 95e15d32d..7e7e0c41d 100644 --- a/auparse/auparse.c +++ b/auparse/auparse.c @@ -22,12 +22,6 @@ */ #include "config.h" -#include "expression.h" -#include "internal.h" -#include "auparse.h" -#include "interpret.h" -#include "auparse-idata.h" -#include "libaudit.h" #include #include #include @@ -35,6 +29,12 @@ #include #include #include +#include "internal.h" +#include "expression.h" +#include "auparse.h" +#include "interpret.h" +#include "auparse-idata.h" +#include "libaudit.h" #include "common.h" //#define LOL_EVENTS_DEBUG01 1 // add debug for list of list event @@ -46,12 +46,6 @@ static int debug = 0; static time_t eoe_timeout = EOE_TIMEOUT; -static void init_lib(void) __attribute__ ((constructor)); -static void init_lib(void) -{ - init_interpretation_list(); -} - /* like strchr except string is delimited by length, not null byte */ static char *strnchr(const char *s, int c, size_t n) { @@ -574,6 +568,11 @@ auparse_state_t *auparse_init(ausource_t source, const void *b) au->find_field = NULL; au->search_where = AUSEARCH_STOP_EVENT; au->tmp_translation = NULL; + au->uid_cache = NULL; + au->uid_cache_created = 0; + au->gid_cache = NULL; + au->gid_cache_created = 0; + init_interpretation_list(au); init_normalizer(&au->norm_data); return au; @@ -633,8 +632,8 @@ static void consume_feed(auparse_state_t *au, int flush) au->le = l; // make this current the event of interest aup_list_first(l); r = aup_list_get_cur(l); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); aup_list_first_field(l); if (au->callback) { @@ -722,22 +721,22 @@ void auparse_set_escape_mode(auparse_state_t *au, auparse_esc_t mode) * buf is a string of name value pairs to be used for interpreting. * Calling this function automatically releases the previous list. */ -void _auparse_load_interpretations(const char *buf) +void _auparse_load_interpretations(auparse_state_t *au, const char *buf) { - free_interpretation_list(); + free_interpretation_list(au); if (buf == NULL) return; - load_interpretation_list(buf); + load_interpretation_list(au, buf); } /* * Non-public function. Subject to change. */ -void _auparse_free_interpretations(void) +void _auparse_free_interpretations(auparse_state_t *au) { - free_interpretation_list(); + free_interpretation_list(au); } int auparse_reset(auparse_state_t *au) @@ -782,7 +781,7 @@ int auparse_reset(auparse_state_t *au) default: return -1; } - free_interpretation_list(); + free_interpretation_list((auparse_state_t *)au); return 0; } @@ -791,7 +790,7 @@ char *auparse_metrics(const auparse_state_t *au) char *metrics; unsigned int uid, gid; - aulookup_metrics(&uid, &gid); + aulookup_metrics(au, &uid, &gid); if (asprintf(&metrics, "max lol available: %lu\n" @@ -1038,7 +1037,7 @@ static void auparse_destroy_common(auparse_state_t *au) fclose(au->in); au->in = NULL; } - free_interpretation_list(); + free_interpretation_list(au); clear_normalizer(&au->norm_data); au_lol_clear(au->au_lo, 0); free((void *)au->tmp_translation); @@ -1048,8 +1047,8 @@ static void auparse_destroy_common(auparse_state_t *au) void auparse_destroy(auparse_state_t *au) { - _aulookup_destroy_uid_list(); - aulookup_destroy_gid_list(); + _aulookup_destroy_uid_list(au); + aulookup_destroy_gid_list(au); auparse_destroy_common(au); } @@ -1551,8 +1550,8 @@ static int au_auparse_next_event(auparse_state_t *au) aup_list_first(l); r = aup_list_get_cur(l); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 @@ -1603,8 +1602,8 @@ static int au_auparse_next_event(auparse_state_t *au) aup_list_first(l); r = aup_list_get_cur(l); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 @@ -1707,8 +1706,8 @@ static int au_auparse_next_event(auparse_state_t *au) aup_list_first(l); r = aup_list_get_cur(l); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 @@ -1842,7 +1841,7 @@ int auparse_first_record(auparse_state_t *au) return rc; } r = aup_list_get_cur(au->le); - if (r && r->item == 0 && interpretation_list_cnt()) { + if (r && r->item == 0 && interpretation_list_cnt(au)) { // If we are on the first record and the list has previously // been loaded, just pull cursor back and avoid loading the // interpretation list. @@ -1851,8 +1850,8 @@ int auparse_first_record(auparse_state_t *au) } aup_list_first(au->le); r = aup_list_get_cur(au->le); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); aup_list_first_field(au->le); return 1; @@ -1867,7 +1866,7 @@ int auparse_next_record(auparse_state_t *au) { rnode *r; - free_interpretation_list(); + free_interpretation_list(au); // Its OK if au->le == NULL because get_cnt handles it if (aup_list_get_cnt(au->le) == 0) { int rc = auparse_first_record(au); @@ -1876,19 +1875,19 @@ int auparse_next_record(auparse_state_t *au) } r = aup_list_next(au->le); if (r) { - load_interpretation_list(r->interp); + load_interpretation_list(au, r->interp); return 1; } else return 0; } -int auparse_goto_record_num(const auparse_state_t *au, unsigned int num) +int auparse_goto_record_num(auparse_state_t *au, unsigned int num) { rnode *r; r = aup_list_get_cur(au->le); - if (r && r->item == num && interpretation_list_cnt()) { + if (r && r->item == num && interpretation_list_cnt(au)) { // If we are on the first record and the list has previously // been loaded, just pull cursor back and avoid loading the // interpretation list. @@ -1897,14 +1896,15 @@ int auparse_goto_record_num(const auparse_state_t *au, unsigned int num) } /* Check if a request is out of range */ - free_interpretation_list(); + free_interpretation_list(au); + // Its OK if au->le == NULL because get_cnt handles it if (num >= aup_list_get_cnt(au->le)) return 0; r = aup_list_goto_rec(au->le, num); if (r != NULL) { - load_interpretation_list(r->interp); + load_interpretation_list(au, r->interp); aup_list_first_field(au->le); return 1; } else @@ -2065,7 +2065,7 @@ const char *auparse_find_field(auparse_state_t *au, const char *name) } /* Increment 1 location and then scan for next field */ -const char *auparse_find_field_next(const auparse_state_t *au) +const char *auparse_find_field_next(auparse_state_t *au) { if (au->le == NULL) return NULL; @@ -2089,8 +2089,8 @@ const char *auparse_find_field_next(const auparse_state_t *au) r = aup_list_next(au->le); if (r) { aup_list_first_field(au->le); - free_interpretation_list(); - load_interpretation_list(r->interp); + free_interpretation_list(au); + load_interpretation_list(au, r->interp); } } } @@ -2193,7 +2193,7 @@ const char *auparse_interpret_field(auparse_state_t *au) rnode *r = aup_list_get_cur(au->le); if (r) { r->cwd = NULL; - return nvlist_interp_cur_val(r, au->escape_mode); + return nvlist_interp_cur_val(au, r); } } return NULL; @@ -2213,7 +2213,7 @@ const char *auparse_interpret_realpath(const auparse_state_t *au) // Tell it to make a realpath r->cwd = au->le->cwd; - return nvlist_interp_cur_val(r, au->escape_mode); + return nvlist_interp_cur_val((auparse_state_t *)au, r); } } return NULL; @@ -2233,7 +2233,7 @@ static const char *auparse_interpret_sock_parts(auparse_state_t *au, if (nvlist_get_cur_type(r) != AUPARSE_TYPE_SOCKADDR) return NULL; // Get interpretation - const char *val = nvlist_interp_cur_val(r, au->escape_mode); + const char *val=nvlist_interp_cur_val((auparse_state_t *)au,r); if (val == NULL) return NULL; // make a copy since we modify it diff --git a/auparse/auparse.h b/auparse/auparse.h index 9a24f6c5e..48375e2c7 100644 --- a/auparse/auparse.h +++ b/auparse/auparse.h @@ -68,7 +68,8 @@ void auparse_add_callback(auparse_state_t *au, auparse_callback_ptr callback, void *user_data, user_destroy user_destroy_func); void auparse_set_escape_mode(auparse_state_t *au, auparse_esc_t mode); int auparse_reset(auparse_state_t *au); -char *auparse_metrics(const auparse_state_t *au) __attr_dealloc_free; +char *auparse_metrics(const auparse_state_t *au) + __attribute_malloc__ __attr_dealloc_free; /* Functions that are part of the search interface */ int ausearch_add_expression(auparse_state_t *au, const char *expression, @@ -145,7 +146,7 @@ unsigned int auparse_get_num_records(const auparse_state_t *au); int auparse_first_record(auparse_state_t *au); int auparse_next_record(auparse_state_t *au); unsigned int auparse_get_record_num(const auparse_state_t *au); -int auparse_goto_record_num(const auparse_state_t *au, unsigned int num); +int auparse_goto_record_num(auparse_state_t *au, unsigned int num); /* Accessors to record data */ int auparse_get_type(const auparse_state_t *au); @@ -158,7 +159,7 @@ unsigned int auparse_get_num_fields(const auparse_state_t *au); const char *auparse_get_record_text(const auparse_state_t *au); const char *auparse_get_record_interpretations(const auparse_state_t *au); const char *auparse_find_field(auparse_state_t *au, const char *name); -const char *auparse_find_field_next(const auparse_state_t *au); +const char *auparse_find_field_next(auparse_state_t *au); unsigned int auparse_get_field_num(const auparse_state_t *au); int auparse_goto_field_num(const auparse_state_t *au, unsigned int num); diff --git a/auparse/expression.c b/auparse/expression.c index 2f5644fe1..7b0dedc7b 100644 --- a/auparse/expression.c +++ b/auparse/expression.c @@ -1018,7 +1018,7 @@ eval_interpreted_value(const auparse_state_t *au, rnode *record, if (nvlist_find_name(&record->nv, expr->v.p.field.name) == 0) return NULL; *free_it = 0; - res = nvlist_interp_cur_val(record, au->escape_mode); + res = nvlist_interp_cur_val((auparse_state_t *)au, record); if (res == NULL) res = nvlist_get_cur_val(&record->nv); return (char *)res; diff --git a/auparse/internal.h b/auparse/internal.h index 7e758ee54..a7112917b 100644 --- a/auparse/internal.h +++ b/auparse/internal.h @@ -1,5 +1,5 @@ /* internal.h -- - * Copyright 2006-07,2013-17 Red Hat Inc., Durham, North Carolina. + * Copyright 2006-07,2013-17,2025 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -28,6 +28,8 @@ #include "data_buf.h" #include "normalize-llist.h" #include "dso.h" +#include "nvlist.h" +#include "lru.h" #include /* This is what state the parser is in */ @@ -140,6 +142,7 @@ typedef struct data struct opaque { + nvlist interpretations; // Per-parser interpretations list ausource_t source; // Source type char **source_list; // Array of buffers, or array of // file names @@ -178,6 +181,10 @@ struct opaque debug_message_t debug_message; // Whether or not messages are debug or not const char *tmp_translation; // Pointer to manage mem for field translation normalize_data norm_data; + Queue *uid_cache; // per-parser UID cache + int uid_cache_created; + Queue *gid_cache; // per-parser GID cache + int gid_cache_created; }; AUDIT_HIDDEN_START diff --git a/auparse/interpret.c b/auparse/interpret.c index 9d6ca3fc0..eb7b5ddd3 100644 --- a/auparse/interpret.c +++ b/auparse/interpret.c @@ -139,9 +139,6 @@ typedef enum { S_UNSET=-1, S_FAILED, S_SUCCESS } success_t; static char *print_escaped(const char *val); static const char *print_signals(const char *val, unsigned int base); -// FIXME: move next declaration to auparse_state_t -static nvlist il; // Interpretations list - /* * This function will take a pointer to a 2 byte Ascii character buffer and * return the actual hex value. @@ -398,32 +395,35 @@ char *au_unescape(char *buf) } /////////// Interpretation list functions /////////////// -#define NEVER_LOADED 0xFFFF -void init_interpretation_list(void) +void init_interpretation_list(auparse_state_t *au) { - nvlist_create(&il); - il.cnt = NEVER_LOADED; + if (au == NULL) + return; + nvlist_create(&au->interpretations); + au->interpretations.cnt = NEVER_LOADED; } /* * Returns 0 on error and 1 on success */ -int load_interpretation_list(const char *buffer) +int load_interpretation_list(auparse_state_t *au, const char *buffer) { char *saved = NULL, *ptr; char *buf, *val; nvnode n; + nvlist *il = &au->interpretations; + if (buffer == NULL) return 0; - if (il.cnt == NEVER_LOADED) - il.cnt = 0; + if (il->cnt == NEVER_LOADED) + il->cnt = 0; - il.record = buf = strdup(buffer); - if (buf == NULL) { + il->record = buf = strdup(buffer); + if (buf == NULL) goto err_out; - } + if (strncmp(buf, "SADDR=", 6) == 0) { // We have SOCKADDR record. It has no other values. // Handle it by itself. @@ -435,16 +435,16 @@ int load_interpretation_list(const char *buffer) // Just change the case n.name = strcpy(buf, "saddr"); n.val = val; - if (nvlist_append(&il, &n)) + if (nvlist_append(il, &n)) goto err_out; - nvlist_interp_fixup(&il); + nvlist_interp_fixup(il); return 1; } } err_out: free(buf); - il.record = NULL; - il.cnt = NEVER_LOADED; + il->record = NULL; + il->cnt = NEVER_LOADED; return 0; } else { // We handle everything else in this branch @@ -475,16 +475,16 @@ int load_interpretation_list(const char *buffer) tmp = 0; n.val = val; - if (nvlist_append(&il, &n)) + if (nvlist_append(il, &n)) continue; // assuming we loaded something - nvlist_interp_fixup(&il); + nvlist_interp_fixup(il); if (ptr) *ptr = tmp; } while ((ptr = audit_strsplit_r(NULL, &saved))); } // If for some reason it was useless, delete buf - if (il.cnt == 0) + if (il->cnt == 0) goto err_out; return 1; @@ -493,16 +493,17 @@ int load_interpretation_list(const char *buffer) /* * Returns malloc'ed buffer on success and NULL if no match */ -const char *_auparse_lookup_interpretation(const char *name) +const char *_auparse_lookup_interpretation(auparse_state_t *au,const char *name) { nvnode *n; - if (il.cnt == NEVER_LOADED) - return NULL; + nvlist *il = &au->interpretations; - nvlist_first(&il); - if (nvlist_find_name(&il, name)) { - n = nvlist_get_cur(&il); + if (il->cnt == NEVER_LOADED) + return NULL; + nvlist_first(il); + if (nvlist_find_name(il, name)) { + n = nvlist_get_cur(il); // This is only called from src/ausearch-lookup.c // it only looks up auid and syscall. One needs // escape, the other does not. @@ -514,7 +515,7 @@ const char *_auparse_lookup_interpretation(const char *name) return NULL; } -void free_interpretation_list(void) +void free_interpretation_list(auparse_state_t *au) { nvlist_clear(&il, 0); il.cnt = NEVER_LOADED; @@ -523,11 +524,13 @@ void free_interpretation_list(void) // This uses a sentinel to determine if the list has ever been loaded. // If never loaded, returns 0. Otherwise it returns 1 higher than how // many interpretations are loaded. -unsigned int interpretation_list_cnt(void) +unsigned int interpretation_list_cnt(const auparse_state_t *au) { - if (il.cnt == NEVER_LOADED) + const nvlist *il = &au->interpretations; + + if (il->cnt == NEVER_LOADED) return 0; - return il.cnt+1; + return il->cnt + 1; } //////////// Start Field Value Interpretations ///////////// @@ -546,9 +549,8 @@ static const char *aulookup_success(int s) } } -static Queue *uid_cache = NULL; -static int uid_cache_created = 0; -static const char *aulookup_uid(uid_t uid, char *buf, size_t size) +static const char *aulookup_uid(auparse_state_t *au, uid_t uid, + char *buf, size_t size) { char *name = NULL; unsigned int key; @@ -563,12 +565,12 @@ static const char *aulookup_uid(uid_t uid, char *buf, size_t size) } // Check the cache first - if (uid_cache_created == 0) { - uid_cache = init_lru(19, NULL, "uid"); - uid_cache_created = 1; + if (au->uid_cache_created == 0) { + au->uid_cache = init_lru(19, NULL, "uid"); + au->uid_cache_created = 1; } - key = compute_subject_key(uid_cache, uid); - q_node = check_lru_cache(uid_cache, key); + key = compute_subject_key(au->uid_cache, uid); + q_node = check_lru_cache(au->uid_cache, key); if (q_node) { if (q_node->id == uid) name = q_node->str; @@ -576,8 +578,8 @@ static const char *aulookup_uid(uid_t uid, char *buf, size_t size) // This getpw use is OK because its for protocol 1 // compatibility. Add it to cache. struct passwd *pw; - lru_evict(uid_cache, key); - q_node = check_lru_cache(uid_cache, key); + lru_evict(au->uid_cache, key); + q_node = check_lru_cache(au->uid_cache, key); pw = getpwuid(uid); if (pw) { q_node->str = strdup(pw->pw_name); @@ -593,18 +595,17 @@ static const char *aulookup_uid(uid_t uid, char *buf, size_t size) return buf; } -void _aulookup_destroy_uid_list(void) +void _aulookup_destroy_uid_list(auparse_state_t *au) { - if (uid_cache_created == 0) + if (au->uid_cache_created == 0) return; - destroy_lru(uid_cache); - uid_cache_created = 0; + destroy_lru(au->uid_cache); + au->uid_cache_created = 0; } -static Queue *gid_cache = NULL; -static int gid_cache_created = 0; -static const char *aulookup_gid(gid_t gid, char *buf, size_t size) +static const char *aulookup_gid(auparse_state_t *au, gid_t gid, + char *buf, size_t size) { char *name = NULL; unsigned int key; @@ -619,20 +620,20 @@ static const char *aulookup_gid(gid_t gid, char *buf, size_t size) } // Check the cache first - if (gid_cache_created == 0) { - gid_cache = init_lru(19, NULL, "gid"); - gid_cache_created = 1; + if (au->gid_cache_created == 0) { + au->gid_cache = init_lru(19, NULL, "gid"); + au->gid_cache_created = 1; } - key = compute_subject_key(gid_cache, gid); - q_node = check_lru_cache(gid_cache, key); + key = compute_subject_key(au->gid_cache, gid); + q_node = check_lru_cache(au->gid_cache, key); if (q_node) { if (q_node->id == gid) name = q_node->str; else { // Add it to cache struct group *gr; - lru_evict(gid_cache, key); - q_node = check_lru_cache(gid_cache, key); + lru_evict(au->gid_cache, key); + q_node = check_lru_cache(au->gid_cache, key); gr = getgrgid(gid); if (gr) { q_node->str = strdup(gr->gr_name); @@ -648,33 +649,35 @@ static const char *aulookup_gid(gid_t gid, char *buf, size_t size) return buf; } -void aulookup_destroy_gid_list(void) +void aulookup_destroy_gid_list(auparse_state_t *au) { - if (gid_cache_created == 0) + if (au->gid_cache_created == 0) return; - destroy_lru(gid_cache); - gid_cache_created = 0; + destroy_lru(au->gid_cache); + au->gid_cache_created = 0; } -void _auparse_flush_caches(void) +void _auparse_flush_caches(auparse_state_t *au) { - if (uid_cache_created) { - destroy_lru(uid_cache); - uid_cache_created = 0; + if (au->uid_cache_created) { + destroy_lru(au->uid_cache); + au->uid_cache_created = 0; } - if (gid_cache_created) { - destroy_lru(gid_cache); - gid_cache_created = 0; + if (au->gid_cache_created) { + destroy_lru(au->gid_cache); + au->gid_cache_created = 0; } } -void aulookup_metrics(unsigned int *uid, unsigned int *gid) +void aulookup_metrics(const auparse_state_t *au, + unsigned int *uid, unsigned int *gid) { - *uid = uid_cache->count; - *gid = gid_cache->count; + *uid = au->uid_cache ? au->uid_cache->count : 0; + *gid = au->gid_cache ? au->gid_cache->count : 0; } -static const char *print_uid(const char *val, unsigned int base) +static const char *print_uid(auparse_state_t *au, + const char *val, unsigned int base) { int uid; char name[64]; @@ -688,10 +691,11 @@ static const char *print_uid(const char *val, unsigned int base) return out; } - return strdup(aulookup_uid(uid, name, sizeof(name))); + return strdup(aulookup_uid(au, uid, name, sizeof(name))); } -static const char *print_gid(const char *val, unsigned int base) +static const char *print_gid(auparse_state_t *au, + const char *val, unsigned int base) { int gid; char name[64]; @@ -705,7 +709,7 @@ static const char *print_gid(const char *val, unsigned int base) return out; } - return strdup(aulookup_gid(gid, name, sizeof(name))); + return strdup(aulookup_gid(au, gid, name, sizeof(name))); } static const char *print_arch(const char *val, unsigned int machine) @@ -882,23 +886,30 @@ static char *print_escaped(const char *val) } // This code is loosely based on glibc-2.27 realpath. -static char working[PATH_MAX]; static char *path_norm(const char *name) { - char *rpath, *dest; + char *working, *rpath, *dest; + char *ret; const char *start, *end, *rpath_limit; int old_errno = errno; + working = malloc(PATH_MAX); + if (working == NULL) + return NULL; + errno = EINVAL; if (name == NULL) - return NULL; + goto err_out; if (name[0] == 0) - return NULL; + goto err_out; errno = old_errno; // If not absolute, give it back as is - if (name[0] == '.') - return strdup(name); + if (name[0] == '.') { + ret = strdup(name); + free(working); + return ret; + } rpath = working; dest = rpath; @@ -939,7 +950,12 @@ static char *path_norm(const char *name) *dest = 0; } } - return strdup(working); + ret = strdup(working); + free(working); + return ret; +err_out: + free(working); + return NULL; } static const char *print_escaped_ext(const idata *id) @@ -2512,7 +2528,8 @@ static const char *print_errno(const char *val) return out; } -static const char* print_a0(const char* val, const idata* id) +static const char* print_a0(auparse_state_t *au, const char* val, + const idata* id) { char* out; int machine = id->machine, syscall = id->syscall; @@ -2570,23 +2587,23 @@ static const char* print_a0(const char* val, const idata* id) return print_rlimit(val); else if (*sys == 's') { if (strcmp(sys, "setuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setreuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setresuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setfsuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setgid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "setregid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "setresgid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_domain(val); else if (strcmp(sys, "setfsgid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "socketcall") == 0) return print_socketcall(val, 16); else if (strcmp(sys, "setxattrat") == 0) @@ -2617,7 +2634,8 @@ static const char* print_a0(const char* val, const idata* id) return out; } -static const char *print_a1(const char *val, const idata *id) +static const char *print_a1(auparse_state_t *au, const char *val, + const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; @@ -2641,7 +2659,7 @@ static const char *print_a1(const char *val, const idata *id) if (strcmp(sys, "chmod") == 0) return print_mode_short(val, 16); else if (strstr(sys, "chown")) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "creat") == 0) return print_mode_short(val, 16); } @@ -2649,13 +2667,13 @@ static const char *print_a1(const char *val, const idata *id) return print_sock_opt_level(val); else if (*sys == 's') { if (strcmp(sys, "setreuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setresuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setregid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "setresgid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_type(val); else if (strcmp(sys, "setns") == 0) @@ -2697,7 +2715,8 @@ static const char *print_a1(const char *val, const idata *id) return out; } -static const char *print_a2(const char *val, const idata *id) +static const char *print_a2(auparse_state_t *au, const char *val, + const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; @@ -2717,7 +2736,7 @@ static const char *print_a2(const char *val, const idata *id) switch (id->a1) { case F_SETOWN: - return print_uid(val, 16); + return print_uid(au, val, 16); case F_SETFD: if (ival == FD_CLOEXEC) return strdup("FD_CLOEXEC"); @@ -2759,9 +2778,9 @@ static const char *print_a2(const char *val, const idata *id) return print_mount(val); } else if (*sys == 's') { if (strcmp(sys, "setresuid") == 0) - return print_uid(val, 16); + return print_uid(au, val, 16); else if (strcmp(sys, "setresgid") == 0) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_proto(val); else if (strcmp(sys, "sendmsg") == 0) @@ -2807,7 +2826,7 @@ static const char *print_a2(const char *val, const idata *id) return print_clone_flags(val); } else if (strstr(sys, "chown")) - return print_gid(val, 16); + return print_gid(au, val, 16); else if (strcmp(sys, "tgkill") == 0) return print_signals(val, 16); else if (strstr(sys, "getxattrat")) @@ -2819,7 +2838,8 @@ static const char *print_a2(const char *val, const idata *id) return out; } -static const char *print_a3(const char *val, const idata *id) +static const char *print_a3(auparse_state_t *au, const char *val, + const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; @@ -3232,7 +3252,7 @@ int lookup_type(const char *name) * This is the main entry point for the auparse library. Call chain is: * auparse_interpret_field -> nvlist_interp_cur_val -> do_interpret */ -const char *do_interpret(rnode *r, auparse_esc_t escape_mode) +const char *do_interpret(auparse_state_t *au, rnode *r) { nvlist *nv = &r->nv; int type; @@ -3249,7 +3269,7 @@ const char *do_interpret(rnode *r, auparse_esc_t escape_mode) id.val = nvlist_get_cur_val(nv); type = auparse_interp_adjust_type(r->type, id.name, id.val); - out = auparse_do_interpretation(type, &id, escape_mode); + out = auparse_do_interpretation(au, type, &id, au->escape_mode); n = nvlist_get_cur(nv); n->interp_val = (char *)out; @@ -3320,16 +3340,18 @@ int auparse_interp_adjust_type(int rtype, const char *name, const char *val) * This can be called by either interpret() or from ausearch-report or * auditctl-listing.c. Returns a malloc'ed buffer that the caller must free. */ -char *auparse_do_interpretation(int type, const idata *id, - auparse_esc_t escape_mode) +char *auparse_do_interpretation(auparse_state_t *au, int type, const idata *id, + auparse_esc_t escape_mode) { const char *out; + nvlist *il = &au->interpretations; + // Check the interpretations list first - if (interpretation_list_cnt()) { - nvlist_first(&il); - if (nvlist_find_name(&il, id->name)) { - nvnode* node = &il.array[il.cur]; + if (interpretation_list_cnt(au)) { + nvlist_first(il); + if (nvlist_find_name(il, id->name)) { + nvnode* node = &il->array[il->cur]; const char *val = node->interp_val; if (val) { @@ -3350,10 +3372,10 @@ char *auparse_do_interpretation(int type, const idata *id, switch(type) { case AUPARSE_TYPE_UID: - out = print_uid(id->val, 10); + out = print_uid(au, id->val, 10); break; case AUPARSE_TYPE_GID: - out = print_gid(id->val, 10); + out = print_gid(au, id->val, 10); break; case AUPARSE_TYPE_SYSCALL: out = print_syscall(id); @@ -3393,16 +3415,16 @@ char *auparse_do_interpretation(int type, const idata *id, out = print_success(id->val); break; case AUPARSE_TYPE_A0: - out = print_a0(id->val, id); + out = print_a0(au, id->val, id); break; case AUPARSE_TYPE_A1: - out = print_a1(id->val, id); + out = print_a1(au, id->val, id); break; case AUPARSE_TYPE_A2: - out = print_a2(id->val, id); + out = print_a2(au, id->val, id); break; case AUPARSE_TYPE_A3: - out = print_a3(id->val, id); + out = print_a3(au, id->val, id); break; case AUPARSE_TYPE_SIGNAL: out = print_signals(id->val, 10); @@ -3496,7 +3518,8 @@ char *auparse_do_interpretation(int type, const idata *id, } if (str == NULL) { // This is the normal path - unsigned int cnt = need_escaping(out, len, escape_mode); + unsigned int cnt = need_escaping(out, len, + escape_mode); if (cnt) { char *dest = malloc(len + 1 + (3*cnt)); if (dest) @@ -3513,7 +3536,8 @@ char *auparse_do_interpretation(int type, const idata *id, unsigned int klen = str - ptr; char tmp = *str; *str = 0; - cnt += need_escaping(ptr, klen, escape_mode); + cnt += need_escaping(ptr, klen, + escape_mode); *str = tmp; ptr = str; // If we are not at the end... diff --git a/auparse/interpret.h b/auparse/interpret.h index 037b322cf..194db615a 100644 --- a/auparse/interpret.h +++ b/auparse/interpret.h @@ -34,16 +34,17 @@ /* Make these hidden to prevent conflicts */ AUDIT_HIDDEN_START -void init_interpretation_list(void); -int load_interpretation_list(const char *buf); -void free_interpretation_list(void); -unsigned int interpretation_list_cnt(void); +void init_interpretation_list(auparse_state_t *au); +int load_interpretation_list(auparse_state_t *au, const char *buf); +void free_interpretation_list(auparse_state_t *au); +unsigned int interpretation_list_cnt(const auparse_state_t *au); int lookup_type(const char *name); -const char *do_interpret(rnode *r, auparse_esc_t escape_mode); -void _aulookup_destroy_uid_list(void); -void aulookup_destroy_gid_list(void); -void aulookup_metrics(unsigned int *uid, unsigned int *gid); -char *au_unescape(char *buf); +const char *do_interpret(auparse_state_t *au, rnode *r); +void _aulookup_destroy_uid_list(auparse_state_t *au); +void aulookup_destroy_gid_list(auparse_state_t *au); +void aulookup_metrics(const auparse_state_t *au, unsigned int *uid, + unsigned int *gid); +char *au_unescape(char *buf) __attribute_malloc__ __attr_dealloc_free; AUDIT_HIDDEN_END diff --git a/auparse/nvlist.c b/auparse/nvlist.c index 1868bfbad..b4e3ed46a 100644 --- a/auparse/nvlist.c +++ b/auparse/nvlist.c @@ -137,7 +137,7 @@ int nvlist_get_cur_type(rnode *r) return auparse_interp_adjust_type(r->type, node->name, node->val); } -const char *nvlist_interp_cur_val(rnode *r, auparse_esc_t escape_mode) +const char *nvlist_interp_cur_val(auparse_state_t *au, rnode *r) { nvlist *l = &r->nv; if (l->cnt == 0) @@ -145,7 +145,7 @@ const char *nvlist_interp_cur_val(rnode *r, auparse_esc_t escape_mode) nvnode *node = &l->array[l->cur]; if (node->interp_val) return node->interp_val; - return do_interpret(r, escape_mode); + return do_interpret(au, r); } // This function determines if a chunk of memory is part of the parsed up diff --git a/auparse/nvlist.h b/auparse/nvlist.h index 2e9606a9b..9bcb882c9 100644 --- a/auparse/nvlist.h +++ b/auparse/nvlist.h @@ -48,7 +48,7 @@ void nvlist_create(nvlist *l); void nvlist_clear(nvlist *l, int free_interp); nvnode *nvlist_next(nvlist *l); int nvlist_get_cur_type(rnode *r); -const char *nvlist_interp_cur_val(rnode *r, auparse_esc_t escape_mode); +const char *nvlist_interp_cur_val(auparse_state_t *au, rnode *r); int nvlist_append(nvlist *l, const nvnode *node); void nvlist_interp_fixup(const nvlist *l); diff --git a/src/Makefile.am b/src/Makefile.am index 59817115a..f6bf681fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ SUBDIRS = test AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/src/libev -I${top_srcdir}/auparse -I${top_srcdir}/audisp -I${top_srcdir}/common sbin_PROGRAMS = auditd auditctl aureport ausearch AM_CFLAGS = -D_GNU_SOURCE -Wno-pointer-sign ${WFLAGS} -noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h ausearch-lol.h auditctl-listing.h ausearch-checkpt.h +noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h ausearch-lol.h auditctl-listing.h ausearch-checkpt.h auparse-stub.h auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c if ENABLE_LISTENER diff --git a/src/auditctl-listing.c b/src/auditctl-listing.c index 9c322670f..cd078dc08 100644 --- a/src/auditctl-listing.c +++ b/src/auditctl-listing.c @@ -32,6 +32,8 @@ #include "private.h" #include "auditctl-llist.h" #include "auparse-idata.h" +#include "auparse-stub.h" + #ifndef IORING_OP_LAST #define IORING_OP_LAST 37 @@ -466,9 +468,10 @@ static void print_rule(const struct audit_rule_data *r) id.val = val; type = auparse_interp_adjust_type( AUDIT_SYSCALL, name, val); - out = auparse_do_interpretation(type, - &id, - AUPARSE_ESC_TTY); + out = auparse_do_interpretation( + (auparse_state_t *)&interp_au, + type, &id, + AUPARSE_ESC_TTY); printf(" -F %s%s%s", name, audit_operator_to_symbol(op), out); @@ -564,6 +567,12 @@ static const char *get_failure(unsigned f) */ int audit_print_reply(const struct audit_reply *rep, int fd) { + static int init_done = 0; + if (!init_done) { + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; + init_done = 1; + } _audit_elf = 0; switch (rep->type) { diff --git a/src/auditd-event.c b/src/auditd-event.c index a86ad6b45..afcc731ef 100644 --- a/src/auditd-event.c +++ b/src/auditd-event.c @@ -500,7 +500,7 @@ static const char *format_enrich(const struct audit_reply *rep) { // Flush before adding to pickup new associations case AUDIT_ADD_USER: case AUDIT_ADD_GROUP: - _auparse_flush_caches(); + _auparse_flush_caches(au); break; default: break; @@ -542,7 +542,7 @@ static const char *format_enrich(const struct audit_reply *rep) case AUDIT_DEL_USER: case AUDIT_DEL_GROUP: case AUDIT_GRP_MGMT: - _auparse_flush_caches(); + _auparse_flush_caches(au); break; default: break; diff --git a/src/auparse-stub.h b/src/auparse-stub.h new file mode 100644 index 000000000..e3622f615 --- /dev/null +++ b/src/auparse-stub.h @@ -0,0 +1,34 @@ +#ifndef AUPARSE_STUB_H +#define AUPARSE_STUB_H + +#include "auparse-idata.h" + +/* + * Stub definitions for using interpretation helpers without auparse + * initialization. Each translation unit that needs them gets its own + * static copy. + */ + +typedef struct interp_nvnode { + char *name; + char *val; + char *interp_val; + unsigned int item; +} interp_nvnode; + +typedef struct interp_nvlist { + interp_nvnode *array; + unsigned int cur; + unsigned int cnt; + unsigned int size; + char *record; + char *end; +} interp_nvlist; + +typedef struct { + interp_nvlist interpretations; +} interp_state_t; + +static interp_state_t interp_au; + +#endif /* AUPARSE_STUB_H */ diff --git a/src/aureport.c b/src/aureport.c index e4560b50b..76e7bf890 100644 --- a/src/aureport.c +++ b/src/aureport.c @@ -42,6 +42,8 @@ #include "ausearch-lol.h" #include "ausearch-lookup.h" #include "auparse-idata.h" +#include "auparse-stub.h" + #include "ausearch-parse.h" @@ -98,6 +100,8 @@ int main(int argc, char *argv[]) set_aumessage_mode(MSG_STDERR, DBG_NO); (void) umask( umask( 077 ) | 027 ); very_first_event.sec = 0; + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; reset_counters(); /* Load config so we know where logs are and eoe_timeout */ @@ -236,13 +240,16 @@ static void process_event(llist *entries) { if (scan(entries)) { // If its a single event or SYSCALL load interpretations - if ((entries->cnt == 1) || - (entries->head->type == AUDIT_SYSCALL)) - _auparse_load_interpretations(entries->head->interp); + if ((entries->cnt == 1) || + (entries->head->type == AUDIT_SYSCALL)) { + _auparse_load_interpretations( + (auparse_state_t *)&interp_au, + entries->head->interp); + } // This is the per entry action item if (per_event_processing(entries)) found = 1; - _auparse_free_interpretations(); + _auparse_free_interpretations((auparse_state_t *)&interp_au); } } diff --git a/src/ausearch-lookup.c b/src/ausearch-lookup.c index 2d6f48caa..19948f531 100644 --- a/src/ausearch-lookup.c +++ b/src/ausearch-lookup.c @@ -32,6 +32,8 @@ #include "ausearch-options.h" #include "ausearch-nvpair.h" #include "auparse-idata.h" +#include "auparse-stub.h" +static int interp_init = 0; /* This is the name/value pair used by search tables */ struct nv_pair { @@ -73,12 +75,19 @@ const char *aulookup_syscall(llist *l, char *buf, size_t size) { const char *sys; + if (!interp_init) { + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; + interp_init = 1; + } + if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", l->s.syscall); return buf; } - sys = _auparse_lookup_interpretation("syscall"); + sys = _auparse_lookup_interpretation((auparse_state_t *)&interp_au, + "syscall"); if (sys) { snprintf(buf, size, "%s", sys); free((void *)sys); @@ -197,6 +206,12 @@ const char *aulookup_uid(uid_t uid, char *buf, size_t size) const char *name; int rc; + if (!interp_init) { + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; + interp_init = 1; + } + if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", uid); return buf; @@ -206,7 +221,8 @@ const char *aulookup_uid(uid_t uid, char *buf, size_t size) return buf; } - name = _auparse_lookup_interpretation("auid"); + name = _auparse_lookup_interpretation((auparse_state_t *)&interp_au, + "auid"); if (name) { snprintf(buf, size, "%s", name); free((void *)name); diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c index e4724bf99..7a77dab9e 100644 --- a/src/ausearch-parse.c +++ b/src/ausearch-parse.c @@ -39,8 +39,10 @@ #include "ausearch-lookup.h" #include "ausearch-parse.h" #include "auparse-idata.h" +#include "auparse-stub.h" #include "ausearch-nvpair.h" + #define NAME_OFFSET 28 static const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 }; @@ -209,10 +211,19 @@ int extract_search_items(llist *l) */ static nvlist uid_nvl; static int uid_list_created=0; +static int interp_init = 0; static const char *lookup_uid(const char *field, uid_t uid) { const char *value; - value = _auparse_lookup_interpretation(field); + + if (!interp_init) { + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; + interp_init = 1; + } + + value = _auparse_lookup_interpretation((auparse_state_t *)&interp_au, + field); if (value) return value; if (uid == 0) diff --git a/src/ausearch-report.c b/src/ausearch-report.c index e07f1a1d7..788160433 100644 --- a/src/ausearch-report.c +++ b/src/ausearch-report.c @@ -33,8 +33,11 @@ #include "ausearch-lookup.h" #include "auparse.h" #include "auparse-idata.h" +#include "auparse-stub.h" #include "auditd-config.h" +static int interp_init = 0; + /* Local functions */ static void output_raw(llist *l); static void output_default(llist *l); @@ -49,6 +52,9 @@ static void text_event(auparse_state_t *au, extern time_t lol_get_eoe_timeout(void); +static auparse_state_t *au = NULL; + + /* The machine based on elf type */ static unsigned long machine = -1; static int cur_syscall = -1; @@ -62,7 +68,13 @@ static int loaded = 0; void ausearch_load_interpretations(const lnode *n) { if (loaded == 0) { - _auparse_load_interpretations(n->interp); + if (!interp_init) { + memset(&interp_au, 0, sizeof(interp_au)); + interp_au.interpretations.cnt = NEVER_LOADED; + interp_init = 1; + } + _auparse_load_interpretations((auparse_state_t *)&interp_au, + n->interp); loaded = 1; } } @@ -70,7 +82,7 @@ void ausearch_load_interpretations(const lnode *n) void ausearch_free_interpretations(void) { if (loaded) { - _auparse_free_interpretations(); + _auparse_free_interpretations((auparse_state_t *)&interp_au); loaded = 0; } } @@ -382,7 +394,8 @@ static void report_interpret(char *name, char *val, int comma, int rtype) id.val = val; id.cwd = NULL; - char *out = auparse_do_interpretation(type, &id, escape_mode); + char *out = auparse_do_interpretation((auparse_state_t *)&interp_au, + type, &id, escape_mode); if (type == AUPARSE_TYPE_UNCLASSIFIED) printf("%s%c", val, comma ? ',' : ' '); else if (name[0] == 'k' && strcmp(name, "key") == 0) { @@ -797,7 +810,6 @@ static void text_event(auparse_state_t *au, /* This function will push an event into auparse. The callback arg will * perform all formatting for the intended report option. */ -static auparse_state_t *au = NULL; static void feed_auparse(llist *l, auparse_callback_ptr callback) { const lnode *n;