Fix audit records - #1188
Conversation
The audit system only recognizes key=value word pairs. It uses the first
whitespace after the '=' to determine the end of the value associated
with the field name. The op field contains multiple words describing what
operation is being performed on the user account. However, due to white
space between the words, the audit parser cannot get the whole operation
description as intended.
This patch is the least invasive way to fix the problem. What it does is
replace white space in the op field with dashes soo that the parser keeps
all of the words togther. Below are before and after events:
type=ADD_GROUP msg=audit(01/18/2025 13:50:27.903:685) : pid=116430 uid=root
auid=sgrubb ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
msg='op=adding group acct=test exe=/home/sgrubb/shadow-utils/src/useradd
hostname=x2 addr=? terminal=pts/1 res=success'
type=ADD_GROUP msg=audit(01/18/2025 13:56:45.031:709) : pid=107681 uid=root
auid=sgrubb ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
msg='op=adding-group acct=test1 exe=/home/sgrubb/shadow-utils/src/useradd
hostname=x2 addr=? terminal=pts/1 res=success'
To show the effect using auformat which captures just the field asked for:
Before:
ausearch --start 13:50 -m ADD_USER --format raw | \
/home/sgrubb/test/auformat "%OP\n"
adding
After:
ausearch --start 13:55 -m ADD_USER --format raw | \
/home/sgrubb/test/auformat "%OP\n"
adding-user
| */ | ||
| char *fixed_op = strreplace (strdup (op), ' ', '-'); | ||
| audit_log_acct_message (audit_fd, type, NULL, | ||
| fixed_op ? fixed_op : op, name, |
There was a problem hiding this comment.
I don't think it's a good idea to fall back to op on allocation error. This means that two formats can coexist in the same file, and software (and humans) must expect both (but one will be rare enough that humans will forget to search for it).
I think I would rather report the error to the caller (and maybe abort the program).
There was a problem hiding this comment.
If you make sure that op is always passed as a string literal, maybe you could use strdupa(3).
To make sure that an argument is a string literal, you could use this code:
https://github.com/shadow-maint/shadow/pull/1189/files
(we can merge it before this one, so that you can use it in your patch.) Cc: @hallyn, @ikerexxe
For now, you can cherry-pick that commit in your branch.
Then, you could define this:
#define audit_logger(..., op, ...) audit_logger_(..., STRDUPA(op), ...)
void audit_logger_(...)
{...}| /* | ||
| * This takes a string and replaces the old character with the new. | ||
| */ | ||
| static char *strreplace (char *str, char old, char new) |
There was a problem hiding this comment.
I'd put this API under lib/string/strtr/. We already have an extense string library:
$ find lib/string/
lib/string/
lib/string/strftime.c
lib/string/strtok
lib/string/strtok/stpsep.c
lib/string/strtok/stpsep.h
lib/string/strftime.h
lib/string/strchr
lib/string/strchr/strchrcnt.h
lib/string/strchr/stpspn.h
lib/string/strchr/strrspn.h
lib/string/strchr/strnul.h
lib/string/strchr/strrspn.c
lib/string/strchr/strnul.c
lib/string/strchr/strchrcnt.c
lib/string/strchr/stpspn.c
lib/string/memset
lib/string/memset/memzero.c
lib/string/memset/memzero.h
lib/string/strcmp
lib/string/strcmp/streq.h
lib/string/strcmp/streq.c
lib/string/strcpy
lib/string/strcpy/stpecpy.c
lib/string/strcpy/strtcpy.h
lib/string/strcpy/strncpy.c
lib/string/strcpy/stpecpy.h
lib/string/strcpy/strncat.c
lib/string/strcpy/strtcpy.c
lib/string/strcpy/strncpy.h
lib/string/strcpy/strncat.h
lib/string/sprintf
lib/string/sprintf/xasprintf.h
lib/string/sprintf/xasprintf.c
lib/string/sprintf/stpeprintf.c
lib/string/sprintf/snprintf.h
lib/string/sprintf/snprintf.c
lib/string/sprintf/stpeprintf.h
lib/string/strdup
lib/string/strdup/xstrndup.c
lib/string/strdup/strndupa.h
lib/string/strdup/xstrdup.c
lib/string/strdup/xstrdup.h
lib/string/strdup/strndupa.c
lib/string/strdup/xstrndup.hMade the following changes based on feedback: Changed the function name to strtr, drop strdup/free in favor of alloca, changed while loop to a for loop, and added missing inline attribute.
|
I made a few changes. Changed the function name to strtr, drop strdup/free in favor of alloca, changed while loop to a for loop, and added missing inline attribute. I would not suggest adding a 1 use function to a library. If something else uses, sure. I also wonder if putting string functions in a library will lose the FORTIFY_SOURCE protection they have if used directly? I also like keeping C code readable without having to look up macros. (I worked on Xinetd back in the day and you cannot understand that code without digging through many header files.) MUSL C also does not have strdupa. So, I work around that with alloca + strcpy. Nothing should fail now. I also don't like the idea of aborting in the middle of a multi-step process. You have a user half installed or deleted. This should work and is readable. |
Thanks!
That's just an internal library. Don't worry. I prefer having it more organized there. Anyway, we make those APIs inline, so in the end the compiler will inline it. But in the library it's more organized, and we know we have the API just by looking at the library file structure.
I don't think so. glibc is a library, and code calling it is still fortified. Anyway, we inline all of our string APIs, so it's as if it had been defined in the translation units.
We have a quite consistent rule in this project that macros with upper-case names that are called like a function are thin wrappers that only add type checks. In many cases, we also implicitly calculate a size: $ grepc STRNCPY .
./lib/string/strcpy/strncpy.h:#define STRNCPY(dst, src) strncpy(dst, src, NITEMS(dst))This STRDUPA() is consistent with this pattern, so I'd find it easy to read.
|
| * be replaced with dashes so that parsers get the whole | ||
| * field. Not all C libraries have strdupa. | ||
| */ | ||
| char *tmp_op = alloca (strlen (op) + 1); |
There was a problem hiding this comment.
strlen() + 1 doesn't enforce a string literal.
Using alloca(3) with arbitrary input is dangerous.
Please add a macro that validates the input and calls alloca().
There was a problem hiding this comment.
These are hard-coded strings embedded in the shadow-utils code. They cannot be attacker influenced.
There was a problem hiding this comment.
Yeah, but we might forget and change some of those in the future. That's why I wanted a STRDUPA() macro that enforces that the input is a string literal.
Don't check for NULL string being passed, put returned type on a separate line, use streq, remove some curly braces, use strdupa, and constify the returned pointer.
|
New updates pushed. |
|
Superseded by #1199 |
The audit system only recognizes key=value word pairs. It uses the first whitespace after the '=' to determine the end of the value associated with the field name. The op field contains multiple words describing what operation is being performed on the user account. However, due to white space between the words, the audit parser cannot get the whole operation description as intended.
This patch is the least invasive way to fix the problem. What it does is replace white space in the op field with dashes soo that the parser keeps all of the words togther. Below are before and after events:
type=ADD_GROUP msg=audit(01/18/2025 13:50:27.903:685) : pid=116430 uid=root auid=sgrubb ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=adding group acct=test exe=/home/sgrubb/shadow-utils/src/useradd hostname=x2 addr=? terminal=pts/1 res=success'
type=ADD_GROUP msg=audit(01/18/2025 13:56:45.031:709) : pid=107681 uid=root auid=sgrubb ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=adding-group acct=test1 exe=/home/sgrubb/shadow-utils/src/useradd hostname=x2 addr=? terminal=pts/1 res=success'
To show the effect using auformat which captures just the field asked for:
Before:
ausearch --start 13:50 -m ADD_USER --format raw |
/home/sgrubb/test/auformat "%OP\n"
adding
After:
ausearch --start 13:55 -m ADD_USER --format raw |
/home/sgrubb/test/auformat "%OP\n"
adding-user