AUDIT.RULES(7)
π AUDIT.RULES(7) π
okay bestie, welcome to audit.rules(7) β yes that's the manual name, we're doing this π«Ά
β¨ NAME β¨
audit.rules β a whole set of rules that get loaded into the kernel audit system. it's giving rulebook energy, and honestly? iconic.
π DESCRIPTION π
so audit.rules is a file (yes, a literal file) that holds audit rules, and the audit daemon's init script loads all of them every single time the daemon starts up. the auditctl program is what the initscripts use to actually do the loading, no cap.
the syntax for these rules is basically the exact same as when you'd type an auditctl command at a shell prompt β with one lil glow-up: you do not need to type the auditctl command name, because that part is implied. she's lowkey self-explanatory like that. π
the audit rules come in 3 varieties:
- control
- file
- syscall
π Control π
control commands are less "watch this" and more "let's set the vibes of the whole audit system." they generally involve configuring the audit system rather than telling it what to watch for.
these commands typically include:
- deleting all rules
- setting the size of the kernel's backlog queue
- setting the failure mode
- setting the event rate limit
- telling
auditctlto ignore syntax errors in the rules and just keep loading
generally, these rules live at the top of the rules file. main character placement, honestly. π
π¦ File System π¦
File System rules are sometimes called watches (cute, right?). these rules are used to audit access to particular files or directories that you're interested in.
heads up bestie: if the path given in a watch rule is a directory, then the rule used is recursive all the way to the bottom of the directory tree β excluding any directories that may be mount points.
the syntax of these watch rules generally follows this format:
-a always,exit -F arch=b64 -F path=path-to-file -F perm=permissions -F key=keyname
where the permissions are any one of the following:
rβ read of the filewβ write to the filexβ execute the fileaβ change in the file's attribute
for best performance, you should supply an arch field in the rule. why? because the individual permissions will cause the selection of specific system calls that use that kind of access. if you don't supply the arch, it causes the selection of all system calls, which affects performance since every single syscall will be evaluated. π
watches can also be created using the deprecated -w format, which allows for backwards compatibility at the expense of system performance (as explained above). using syscall rules as shown above, you can choose between path and dir, which is against a specific inode or directory tree respectively. also worth noting: the recursive directory watch will stop if there is a mount point below the parent directory. there is an option to make the mounted subdirectory equivalent by using a -q rule. π§
π₯ System Call π₯
system call rules are loaded into a matching engine that intercepts each syscall that all programs on the system makes. so yeah, it is very important to only use syscall rules when you have to, since these affect performance. the more rules, the bigger the performance hit. you can help the performance though, by combining syscalls into one rule whenever possible. team work makes the dream work π
the Linux kernel has 6 rule matching lists, or filters as they're sometimes called. they are:
taskexituserexcludefilesystemio_uring
the task list is checked only during the fork or clone syscalls. it is rarely used in practice.
the exit filter is the place where all syscall and file system audit requests are evaluated.
the user filter is used to filter (remove) some events that originate in user space. by default, any event originating in user space is allowed. so, if there are some events that you do not want to see, then this is a place where some can be removed. see auditctl(8) for fields that are valid.
the exclude filter is used to exclude certain events from being emitted. the msgtype and a number of subject attribute fields can be used to tell the kernel which message types you do not want to record. this filter can remove the event as a whole and is not selective about any other attribute. the user and exit filters are better suited to selectively auditing events. the action is ignored for this filter, defaulting to "never".
the io_uring filter is used to watch underlying syscalls performed by io_uring operations.
syscall rules take the general form of:
-a action,list -S syscall -F field=value -k keyname
the -a option tells the kernel's rule matching engine that we want to append a rule at the end of the rule list. but we need to specify which rule list it goes on and what action to take when it triggers. valid actions are:
alwaysβ always create an eventneverβ never create an event
the action and list are separated by a comma but no space in between. valid lists are: task, exit, user, exclude, filesystem, and io_uring. their meaning was explained earlier (scroll up bestie π«Ά).
next in the rule would normally be the -S option. this field can either be the syscall name or number. for readability, the name is almost always used. you may give more than one syscall in a rule by specifying another -S option. when sent into the kernel, all syscall fields are put into a mask so that one compare can determine if the syscall is of interest. so, adding multiple syscalls in one rule is very efficient. β¨
when you specify a syscall name, auditctl will look up the name and get its syscall number. this leads to some problems on bi-arch machines. the 32 and 64 bit syscall numbers sometimes, but not always, line up. so, to solve this problem, you would generally need to break the rule into 2 β with one specifying -F arch=b32 and the other specifying -F arch=b64. this needs to go in front of the -S option so that auditctl looks at the right lookup table when returning the number.
after the syscall is specified, you would normally have one or more -F options that fine tune what to match against. rather than list all the valid field types here, the reader should look at the auditctl man page, which has a full listing of each field and what it means. but it's worth mentioning a couple things:
the audit system considers uids to be unsigned numbers. the audit system uses the number -1 to indicate that a loginuid is not set. this means that when it's printed out, it looks like 4294967295. but when you write rules, you can use either "unset" (easy to remember π
), or -1, or 4294967295. they are all equivalent.
if you write a rule where you wanted to try to get the valid users of the system, you need to look in /etc/login.defs to see where user accounts start. for example, if UID_MIN is 1000, then you would also need to take into account that the unsigned representation of -1 is higher than 500. so you would address this with the following piece of a rule:
-F auid>=1000 -F auid!=unset
these individual checks are "anded" and both have to be true. no skipping, both of y'all gotta show up.
the last thing to know about syscall rules is that you can add a key field, which is a free form text string that you want inserted into the event to help identify its meaning. this is discussed in more detail in the NOTES section. π
π NOTES π
the purpose of auditing is to be able to do an investigation periodically or whenever an incident occurs. a few simple steps in planning up front will make this job so much easier. the best advice is to use keys in both the watches and system call rules to give the rule a meaning. if rules are related or together meet a specific requirement, then give them a common key name. you can use this during your investigation to select only results with a specific meaning. it's giving organized queen energy. π
when doing an investigation, you would normally start off with the main aureport output to just get an idea about what is happening on the system. this report mostly tells you about events that are hard coded by the audit system such as:
- login/out
- uses of authentication
- system anomalies
- how many users have been on the machine
- and if SE Linux has detected any AVCs
aureport --start this-week
after looking at the report, you probably want to get a second view about what rules you loaded that have been triggering. this is where keys become important. you would generally run the key summary report like this:
aureport --start this-week --key --summary
this will give you an ordered listing of the keys associated with rules that have been triggering. so, if for example you had a syscall audit rule that triggered on the failure to open files with EPERM that had a key field of access like this:
-a always,exit -F arch=b64 -S open -S openat -S openat2 -F exit=-EPERM -k access
then you can isolate these failures with ausearch and pipe the results to aureport for display. suppose your investigation noticed a lot of the access denied events. if you wanted to see the files that unauthorized access has been attempted on, you could run the following command:
ausearch --start this-week -k access --raw | aureport --file --summary
this will give you an ordered list showing which files are being accessed with the EPERM failure. suppose you wanted to see which users might be having failed access, you would run the following command:
ausearch --start this-week -k access --raw | aureport --user --summary
if your investigation showed a lot of failed accesses to a particular file, you could run the following report to see who is doing it:
ausearch --start this-week -k access -f /path-to/file --raw | aureport --user -i
this report will give you the individual access attempts by person. if you needed to see the actual audit event that is being reported, you would look at the date, time, and event columns. assuming the event was 822 and it occurred at 2:30 on 09/01/2009 and you use the en_US.utf8 locale, the command would look something like this:
ausearch --start 09/01/2009 02:30 -a 822 -i --just-one
this will select the first event from that day and time with the matching event id and interpret the numeric values into human readable values. π¦
the most important step in being able to do this kind of analysis is setting up key fields when the rules were originally written. it should also be pointed out that you can have more than one key field associated with any given rule.
π©Ί TROUBLESHOOTING π©Ί
okay bestie, if your syscall rules are giving absolutely nothing when they should be giving everything, here's the move: run a lil test program under strace so you can literally watch the syscalls scroll by. fr fr there's a real chance you just picked the wrong syscall and the whole rule is out here waiting for a ghost. π
If auditctl hits you with a warning like:
"32/64 bit syscall mismatch in line XX, you should specify an arch"
...then lowkey what happened is you wrote a syscall rule on a bi-arch system where that syscall has a different syscall number for the 32-bit and 64-bit interfaces. which means on one of those interfaces you're probably auditing the wrong syscall entirely. π the fix is giving each arch its own rule, so rewrite it as two rules with the intended arch spelled out for each one. for example, this:
-a always,exit -S openat -k access
would be rewritten as:
-a always,exit -F arch=b32 -S openat -k access
-a always,exit -F arch=b64 -S openat -k access
slay, now both arches know exactly what they're doing. β¨
And if you get a warning that says:
"entry rules deprecated, changing to exit rule"
...that means you wrote a rule for the entry filter, but bestie, that filter is no longer available. auditctl moved your rule over to the exit filter so it wouldn't just be lost to the void (very demure, very mindful of it). but to stop the warning from haunting you forever, you gotta change the offending rule from entry to exit. periodt. π
πΈ EXAMPLES πΈ
okay this first one is iconic β it shows how to audit failed access to files due to permission problems. note that it takes two rules for each arch ABI to fully audit this, because file access can fail with two different failure codes that both mean "permission problems":
-a always,exit -F arch=b32 -S open,openat,openat2 -F exit=-EACCES -k access
-a always,exit -F arch=b32 -S open,openat,openat2 -F exit=-EPERM -k access
-a always,exit -F arch=b64 -S open,openat,openat2 -F exit=-EACCES -k access
-a always,exit -F arch=b64 -S open,openat,openat2 -F exit=-EPERM -k access
see how it's giving thorough? two ABIs, two failure codes, four rules, zero gaps. π«Ά
π¦ IO_URING RULES π¦
so io_uring rules do not take an arch field β it's implicit in the specification of the filter, like it's already understood, no need to say it out loud. this example rule watches for file opens going through the io_uring subsystem:
-a always,io_uring -S openat,openat2 -F key=access
she's sleek, she's archless, she's doing her job. π
π HARD WIRED EVENTS π
if auditing is enabled, then you can get any event that is not caused by syscall or file watch rules β because you don't have any rules loaded, bestie, it's just vibing in there. so that means any event from 1100-1299, 1326, 1328, 1331 and higher can be emitted. π
the reason there are a bunch of events that are hardwired is because they're required by regulatory compliance and get sent automatically as a convenience. (for example, logon/logoff is a mandatory event in all security guidance. every single one. no escape.) if you don't want this, you can use the exclude filter to drop the events you don't want:
-a always,exclude -F msgtype=CRED_REFR
bye bye, CRED_REFR, you will not be missed. πβ¨
π SEE ALSO π
π AUTHOR π
Steve Grubb
and that's a wrap on this whole page, bestie!! this one came from the Red Hat girlies, Sep 2023, filed under AUDIT.RULES(7) β go forth and audit responsibly, mwah π
ππ¦
π¦ where this page comes from
- alpine 3.22: audit-doc 4.0.3-r0 Β· LGPL-2.1-or-later
- alpine 3.23: audit-doc 4.1.2-r2 Β· LGPL-2.1-or-later
- alpine 3.24: audit-doc 4.1.2-r6 Β· LGPL-2.1-or-later
- arch rolling: audit 4.2.1-1 Β· GPL-2.0-or-later AND LGPL-2.0-or-later
- centos-stream 10: audit-rules 4.2.1-3.el10 Β· GPL-2.0-or-later
- centos-stream 9: audit 3.1.5-9.el9 Β· GPLv2+
- debian trixie: auditd 1:4.0.2-2+deb13u1 Β· GPL-2.0-only
- fedora 43: audit-rules 4.1.1-2.fc43 Β· GPL-2.0-or-later
- fedora 43: audit-rules 4.2.1-1.fc43 Β· GPL-2.0-or-later
- fedora 44: audit-rules 4.1.4-1.fc44 Β· GPL-2.0-or-later
- fedora 44: audit-rules 4.2.1-1.fc44 Β· GPL-2.0-or-later
- nixpkgs unstable: audit 4.2.1
- opensuse-leap 16.0: audit-rules 4.0-160000.2.2 Β· LGPL-2.1-or-later
- opensuse-leap 16.0: audit-rules 4.0-160000.2.2 Β· LGPL-2.1-or-later
- opensuse-leap 16.0: audit-rules 4.0-160000.2.2 Β· LGPL-2.1-or-later
- opensuse-leap 16.0: audit-rules 4.0-160000.2.2 Β· LGPL-2.1-or-later
- ubuntu questing: auditd 1:4.0.5-1build1
- ubuntu resolute: auditd 1:4.1.2-1build1 Β· GPL-2.0-only
- ubuntu resolute: auditd 1:4.1.2-1ubuntu0.1 Β· GPL-2.0-only
- ubuntu stonking: auditd 1:4.1.2-1ubuntu1 Β· GPL-2.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms