Skip to content

Fix audit records - #1188

Closed
stevegrubb wants to merge 4 commits into
shadow-maint:masterfrom
stevegrubb:audit-fixup
Closed

Fix audit records#1188
stevegrubb wants to merge 4 commits into
shadow-maint:masterfrom
stevegrubb:audit-fixup

Conversation

@stevegrubb

Copy link
Copy Markdown
Contributor

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

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
Comment thread lib/audit_help.c Outdated
*/
char *fixed_op = strreplace (strdup (op), ' ', '-');
audit_log_acct_message (audit_fd, type, NULL,
fixed_op ? fixed_op : op, name,

@alejandro-colomar alejandro-colomar Jan 18, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

@alejandro-colomar alejandro-colomar Jan 18, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_(...)
{...}

Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
/*
* This takes a string and replaces the old character with the new.
*/
static char *strreplace (char *str, char old, char new)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.h

Made 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.
Comment thread lib/audit_help.c Fixed
@stevegrubb

Copy link
Copy Markdown
Contributor Author

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.

Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c Outdated
@alejandro-colomar

Copy link
Copy Markdown
Collaborator

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.

Thanks!

I would not suggest adding a 1 use function to a library. If something else uses, sure.

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 also wonder if putting string functions in a library will lose the FORTIFY_SOURCE protection they have if used directly?

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.

I also like keeping C code readable without having to look up macros.

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.

(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.

Comment thread lib/audit_help.c Outdated
* be replaced with dashes so that parsers get the whole
* field. Not all C libraries have strdupa.
*/
char *tmp_op = alloca (strlen (op) + 1);

@alejandro-colomar alejandro-colomar Jan 21, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are hard-coded strings embedded in the shadow-utils code. They cannot be attacker influenced.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@stevegrubb

Copy link
Copy Markdown
Contributor Author

New updates pushed.

Comment thread lib/audit_help.c Outdated
Comment thread lib/audit_help.c
@alejandro-colomar

Copy link
Copy Markdown
Collaborator

Superseded by #1199

@stevegrubb
stevegrubb deleted the audit-fixup branch March 17, 2025 12:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants