diff --git a/NEWS.md b/NEWS.md index 3c3b2ac..4049a05 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,9 +4,13 @@ - Add capability to omit the `sid` field of processes. - Rewritten event loop for improved behaviour under load (issue #33). - No longer shelling out to `kextload` to load kext (issue #17). +- Capability to log all environment variables at image exec (`full`), + only log variables affecting dyld (`dyld`) or not log the environment + (`none`) (issue #7). Configuration changes: +- Added `envlevel`. - Added `omit_sid`. Event schema changes: diff --git a/aev.c b/aev.c index 6223845..5b254c4 100644 --- a/aev.c +++ b/aev.c @@ -10,28 +10,26 @@ #include "aev.h" +#include "str.h" + #include #include #include +#include /* - * Construct a newly allocated argv/env-style vector, copying over *aec* - * strings from *aev*. The resulting vector will be NULL-terminated and no - * separate count of the number of elements needs to be stored. Performs a - * deep copy, i.e. the memory in *aev* does not need to be kept around. + * sz is the total length of all the strings in aev including terminating + * zeroes. */ -char ** -aev_new(size_t aec, char **aev) { - size_t sz = 0; +static char ** +aev_new_internal(size_t aec, char **aev, size_t sz) { char **buf; char *sp, *dp; - if (aec == 0) - return NULL; - for (size_t i = 0; i < aec; i++) - sz += sizeof(char *) + strlen(aev[i]) + 1; - sz += sizeof(char *); + sz += sizeof(char *) * (aec + 1); buf = malloc(sz); + if (!buf) + return NULL; buf[aec] = NULL; dp = (char *)&buf[aec+1]; for (size_t i = 0; i < aec; i++) { @@ -45,3 +43,51 @@ aev_new(size_t aec, char **aev) { return buf; } +/* + * Construct a newly allocated argv/env-style vector, copying over *aec* + * strings from *aev*. The resulting vector will be NULL-terminated and no + * separate count of the number of elements needs to be stored. Performs a + * deep copy, i.e. the memory in *aev* does not need to be kept around. + * + * Returns NULL if aec is 0, aev is NULL, or on memory allocation failure, in + * which case errno is set to ENOMEM. + */ +char ** +aev_new(size_t aec, char **aev) { + size_t sz = 0; + + errno = 0; + if (aec == 0 || !aev) + return NULL; + for (size_t i = 0; i < aec; i++) + sz += strlen(aev[i]) + 1; + return aev_new_internal(aec, aev, sz); +} + +/* + * Like aev_new, but only considers entries in aev which begin with prefix. + * Returns NULL if no entry in aev begins with prefix. + */ +char ** +aev_new_prefix(size_t aec, char **aev, const char *prefix) { + size_t sz = 0; + char *filtered_aev[aec]; + size_t filtered_aec = 0; + + if (!prefix) + return aev_new(aec, aev); + + errno = 0; + if (aec == 0 || !aev) + return NULL; + for (size_t i = 0; i < aec; i++) { + if (str_beginswith(aev[i], prefix)) { + filtered_aev[filtered_aec++] = aev[i]; + sz += strlen(aev[i]) + 1; + } + } + if (sz == 0) + return NULL; + return aev_new_internal(filtered_aec, filtered_aev, sz); +} + diff --git a/aev.h b/aev.h index 1fca6ee..a2c55f5 100644 --- a/aev.h +++ b/aev.h @@ -15,7 +15,8 @@ #include -char ** aev_new(size_t, char **) MALLOC NONNULL(2); +char ** aev_new(size_t, char **) MALLOC; +char ** aev_new_prefix(size_t, char **, const char *) MALLOC; #endif diff --git a/auevent.c b/auevent.c index d40c10a..69ded5a 100644 --- a/auevent.c +++ b/auevent.c @@ -93,7 +93,7 @@ auevent_type_in_typelist(const uint16_t type, const uint16_t typelist[]) { * returns -1 on errors */ ssize_t -auevent_fread(audit_event_t *ev, const uint16_t aues[], FILE *f) { +auevent_fread(audit_event_t *ev, const uint16_t aues[], int flags, FILE *f) { int rv; int reclen; u_char *recbuf; @@ -381,12 +381,23 @@ auevent_fread(audit_event_t *ev, const uint16_t aues[], FILE *f) { break; /* exec env */ case AUT_EXEC_ENV: + if (!(flags & (AUEVENT_FLAG_ENV_DYLD | + AUEVENT_FLAG_ENV_FULL))) + break; assert(ev->execenv == NULL); if (ev->execenv) free(ev->execenv); - ev->execenv = aev_new(tok.tt.execenv.count, - tok.tt.execenv.text); - if (!ev->execenv) + if (flags & AUEVENT_FLAG_ENV_DYLD) { + ev->execenv = aev_new_prefix( + tok.tt.execenv.count, + tok.tt.execenv.text, + "DYLD_"); + } else { + assert(flags & AUEVENT_FLAG_ENV_FULL); + ev->execenv = aev_new(tok.tt.execenv.count, + tok.tt.execenv.text); + } + if (!ev->execenv && errno == ENOMEM) ev->flags |= AEFLAG_ENOMEM; break; /* process exit status */ diff --git a/auevent.h b/auevent.h index ada2f8f..bafc674 100644 --- a/auevent.h +++ b/auevent.h @@ -88,7 +88,10 @@ typedef struct { } audit_event_t; void auevent_create(audit_event_t *) NONNULL(1); -ssize_t auevent_fread(audit_event_t *ev, const uint16_t[], FILE *) NONNULL(1,3); +ssize_t auevent_fread(audit_event_t *ev, const uint16_t[], int, FILE *) + NONNULL(1,4); +#define AUEVENT_FLAG_ENV_DYLD 1 +#define AUEVENT_FLAG_ENV_FULL 2 void auevent_destroy(audit_event_t *) NONNULL(1); void auevent_fprint(FILE *, audit_event_t *) NONNULL(1,2); diff --git a/cf.c b/cf.c index 332de7b..43d6db6 100644 --- a/cf.c +++ b/cf.c @@ -103,7 +103,8 @@ cf_cstrv(CFArrayRef arr) { * * This is not the most efficient way to do it, but given that we don't know * the effective length of each string before copying it out, there is no good - * alternative. + * alternative. Also, this function is not used in very performance critical + * code paths. */ char ** cf_aev(CFArrayRef arr) { diff --git a/evtloop.c b/evtloop.c index 75aa2b9..33dc506 100644 --- a/evtloop.c +++ b/evtloop.c @@ -183,7 +183,7 @@ auef_readable(UNUSED int fd, void *udata) { int rv; auevent_create(&ev); - rv = auevent_fread(&ev, NULL, auef); + rv = auevent_fread(&ev, NULL, cfg->envlevel /* HACK */, auef); if (rv == -1 || rv == 0) { if (ev.flags & AEFLAG_ENOMEM) ooms++; diff --git a/logevt.c b/logevt.c index e477596..d4c6055 100644 --- a/logevt.c +++ b/logevt.c @@ -662,15 +662,12 @@ logevt_image_exec(logfmt_t *fmt, FILE *f, void *arg0) { fmt->list_end(f); /* argv */ } - if (ie->envv && config->envlevel > ENVLEVEL_NONE) { + if (ie->envv) { fmt->dict_item(f, "env"); fmt->list_begin(f); for (int i = 0; ie->envv[i]; i++) { - if (config->envlevel > ENVLEVEL_DYLD || - str_beginswith(ie->envv[i], "DYLD_")) { - fmt->list_item(f, "var"); - fmt->value_string(f, ie->envv[i]); - } + fmt->list_item(f, "var"); + fmt->value_string(f, ie->envv[i]); } fmt->list_end(f); /* env */ }