Kernel support to audit io_uring operations filtering was added with
commit 67daf270cebc ("audit: add filtering for io_uring records"). Add support
for the "uring" filter list to auditctl.
Signed-off-by: Richard Guy Briggs <[email protected]>
---
docs/audit.rules.7 | 19 ++++--
docs/audit_add_rule_data.3 | 4 ++
docs/auditctl.8 | 10 ++-
lib/flagtab.h | 11 ++--
lib/libaudit.c | 50 ++++++++++++---
lib/libaudit.h | 7 +++
lib/lookup_table.c | 20 ++++++
lib/private.h | 1 +
src/auditctl-listing.c | 52 ++++++++++------
src/auditctl.c | 121 ++++++++++++++++++++++++++++++++-----
10 files changed, 240 insertions(+), 55 deletions(-)
diff --git a/docs/audit.rules.7 b/docs/audit.rules.7
index 40263ec6807d..ec4fa7ececc7 100644
--- a/docs/audit.rules.7
+++ b/docs/audit.rules.7
@@ -3,7 +3,7 @@
audit.rules \- a set of rules loaded in the kernel audit system
.SH DESCRIPTION
\fBaudit.rules\fP is a file containing audit rules that will be loaded by the
audit daemon's init script whenever the daemon is started. The auditctl program
is used by the initscripts to perform this operation. The syntax for the rules
is essentially the same as when typing in an auditctl command at a shell prompt
except you do not need to type the auditctl command name since that is implied.
The audit rules come in 3 varieties:
-.IR control ", " file ", and " syscall ".
+.IR control ", " file ", and " syscall/uringop ".
.SS Control
Control commands 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, or to tell auditctl to ignore syntax errors
in the rules and continue loading. Generally, these rules are at the top of the
rules file.
@@ -32,7 +32,7 @@ where the permission are any one of the following:
- change in the file's attribute
.RE
-Watches can also be created using the syscall format described below which
allow for greater flexibility and options. Using syscall rules you can choose
between
+Watches can also be created using the syscall format described below which
allow for greater flexibility and options. Using syscall/uringop rules you can
choose between
.B path
and
.B dir
@@ -43,9 +43,9 @@ rule.
.SS System Call
The system call rules are loaded into a matching engine that intercepts each
syscall that all programs on the system makes. Therefore 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.
-The Linux kernel has 5 rule matching lists or filters as they are sometimes
called. They are: task, exit, user, exclude and filesystem. The task list is
checked only during the fork or clone syscalls. It is rarely used in practice.
+The Linux kernel has 6 rule matching lists or filters as they are sometimes
called. They are: task, exit, user, exclude, filesystem, and 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 exit filter is the place where all syscall and file system audit requests
are evaluated. The uring filter is the place where all uring operations 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.
@@ -71,7 +71,7 @@ option tells the kernel's rule matching engine that we want
to append a rule at
.RE
The action and list are separated by a comma but no space in between. Valid
lists are:
-.IR task ", " exit ", " user ", " exclude ", and " filesystem ". Their meaning
was explained earlier.
+.IR task ", " exit ", " user ", " exclude ", " filesystem ", and " uring ".
Their meaning was explained earlier.
Next in the rule would normally be the
.B \-S
@@ -95,6 +95,15 @@ These individual checks are "anded" and both have to be true.
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.
+.SS Uring Operations
+Uring operations are similar to system calls in that they are initiated by
user actions, but once the action is set up, information is passed between
userspace and kernel space bidirectionally via shared buffers. There is a
different list of operations that use the same operations list mechanism so
system calls and uring operations are mutually exclusive.
+
+Uring op rules take the general form of:
+
+.nf
+.B \-a action,list \-U uringop \-F field=value \-k keyname
+.fi
+
.SH 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 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.
diff --git a/docs/audit_add_rule_data.3 b/docs/audit_add_rule_data.3
index 61d1902e702b..e86c3a1b0fef 100644
--- a/docs/audit_add_rule_data.3
+++ b/docs/audit_add_rule_data.3
@@ -27,6 +27,10 @@ AUDIT_FILTER_EXCLUDE - Apply rule at audit_log_start. This
is the exclude filter
\(bu
AUDIT_FILTER_FS - Apply rule when adding PATH auxiliary records to SYSCALL
events. This is the filesystem filter. This is used to ignore PATH records that
are not of interest.
.LP
+.TP
+\(bu
+AUDIT_FILTER_URING_EXIT - Apply rule at uring exit. This is the main filter
that is used for uring ops and filesystem watches. Normally all uring ops do
not trigger events, so this is normally used to specify events that are of
interest.
+.LP
.PP
The rule's action has two possible values:
diff --git a/docs/auditctl.8 b/docs/auditctl.8
index 8069259bcb47..515c5a71f861 100644
--- a/docs/auditctl.8
+++ b/docs/auditctl.8
@@ -92,6 +92,9 @@ Add a rule to the event type exclusion filter list. This list
is used to filter
.TP
.B filesystem
Add a rule that will be applied to a whole filesystem. The filesystem must be
identified with a fstype field. Normally this filter is used to exclude any
events for a whole filesystem such as tracefs or debugfs.
+.TP
+.B uring
+Add a rule to the uring op exit list. This list is used upon exit from a uring
operation call to determine if an audit event should be created.
.RE
The following describes the valid \fIactions\fP for the rule:
@@ -101,7 +104,7 @@ The following describes the valid \fIactions\fP for the
rule:
No audit records will be generated. This can be used to suppress event
generation. In general, you want suppressions at the top of the list instead of
the bottom. This is because the event triggers on the first matching rule.
.TP
.B always
-Allocate an audit context, always fill it in at syscall entry time, and always
write out a record at syscall exit time.
+Allocate an audit context, always fill it in at syscall/uringop entry time,
and always write out a record at syscall/uringop exit time.
.RE
.TP
.BI \-A\ list , action
@@ -120,7 +123,7 @@ The two groups of uid and gid cannot be mixed. But any
comparison within the gro
.TP
.BI \-d\ list , action
-Delete rule from \fIlist\fP with \fIaction\fP. The rule is deleted only if it
exactly matches syscall name(s) and every field name and value.
+Delete rule from \fIlist\fP with \fIaction\fP. The rule is deleted only if it
exactly matches syscall/uringop name(s) and every field name and value.
.TP
\fB\-F\fP [\fIn\fP\fB=\fP\fIv\fP | \fIn\fP\fB!=\fP\fIv\fP |
\fIn\fP\fB<\fP\fIv\fP | \fIn\fP\fB>\fP\fIv\fP | \fIn\fP\fB<=\fP\fIv\fP |
\fIn\fP\fB>=\fP\fIv\fP | \fIn\fP\fB&\fP\fIv\fP | \fIn\fP\fB&=\fP\fIv\fP]
Build a rule field: name, operation, value. You may have up to 64 fields
passed on a single command line. Each one must start with \fB\-F\fP. Each field
equation is anded with each other (as well as equations starting with
\fB\-C\fP) to trigger an audit record. There are 8 operators supported - equal,
not equal, less than, greater than, less than or equal, and greater than or
equal, bit mask, and bit test respectively. Bit test will "and" the values and
check that they are equal, bit mask just "ands" the values. Fields that take a
user ID may instead have the user's name; the program will convert the name to
user ID. The same is true of group names. Valid fields are:
@@ -260,6 +263,9 @@ Describe the permission access type that a file system
watch will trigger on. \f
\fB\-S\fP [\fISyscall name or number\fP|\fBall\fP]
Any \fIsyscall name\fP or \fInumber\fP may be used. The word '\fBall\fP' may
also be used. If the given syscall is made by a program, then start an audit
record. If a field rule is given and no syscall is specified, it will default
to all syscalls. You may also specify multiple syscalls in the same rule by
using multiple \-S options in the same rule. Doing so improves performance
since fewer rules need to be evaluated. Alternatively, you may pass a comma
separated list of syscall names. If you are on a bi-arch system, like x86_64,
you should be aware that auditctl simply takes the text, looks it up for the
native arch (in this case b64) and sends that rule to the kernel. If there are
no additional arch directives, IT WILL APPLY TO BOTH 32 & 64 BIT SYSCALLS. This
can have undesirable effects since there is no guarantee that any syscall has
the same number on both 32 and 64 bit interfaces. You will likely want to
control this and write 2 rules, one with arch equal to b32 and one with
b64 to make sure the kernel finds the events that you intend. See the arch
field discussion for more info.
.TP
+\fB\-U\fP [\fIUring operation name or number\fP|\fBall\fP]
+Any \fIuring operation name\fP or \fInumber\fP may be used. The word
'\fBall\fP' may also be used. If the given uring operation is made by a
program, then start an audit record. If a field rule is given and no uring
operation is specified, it will default to all uring operations. You may also
specify multiple uring operations in the same rule by using multiple \-S
options in the same rule. Doing so improves performance since fewer rules need
to be evaluated. Alternatively, you may pass a comma separated list of uring
operation names.
+.TP
.BI \-w\ path
Insert a watch for the file system object at \fIpath\fP. You cannot insert a
watch to the top level directory. This is prohibited by the kernel. Wildcards
are not supported either and will generate a warning. The way that watches work
is by tracking the inode internally. If you place a watch on a file, its the
same as using the \-F path option on a syscall rule. If you place a watch on a
directory, its the same as using the \-F dir option on a syscall rule. The \-w
form of writing watches is for backwards compatibility and the syscall based
form is more expressive. Unlike most syscall auditing rules, watches do not
impact performance based on the number of rules sent to the kernel. The only
valid options when using a watch are the \-p and \-k. If you need to do
anything fancy like audit a specific user accessing a file, then use the
syscall auditing form with the path or dir fields. See the EXAMPLES section for
an example of converting one form to another.
.TP
diff --git a/lib/flagtab.h b/lib/flagtab.h
index 7a618e0fe126..0fa4443e6ce3 100644
--- a/lib/flagtab.h
+++ b/lib/flagtab.h
@@ -20,8 +20,9 @@
* Steve Grubb <[email protected]>
* Richard Guy Briggs <[email protected]>
*/
-_S(AUDIT_FILTER_TASK, "task" )
-_S(AUDIT_FILTER_EXIT, "exit" )
-_S(AUDIT_FILTER_USER, "user" )
-_S(AUDIT_FILTER_EXCLUDE, "exclude" )
-_S(AUDIT_FILTER_FS, "filesystem")
+_S(AUDIT_FILTER_TASK, "task" )
+_S(AUDIT_FILTER_EXIT, "exit" )
+_S(AUDIT_FILTER_USER, "user" )
+_S(AUDIT_FILTER_EXCLUDE, "exclude" )
+_S(AUDIT_FILTER_FS, "filesystem")
+_S(AUDIT_FILTER_URING_EXIT, "uring" )
diff --git a/lib/libaudit.c b/lib/libaudit.c
index 54e276156ef0..3790444f4497 100644
--- a/lib/libaudit.c
+++ b/lib/libaudit.c
@@ -86,6 +86,7 @@ static const struct nv_list failure_actions[] =
int _audit_permadded = 0;
int _audit_archadded = 0;
int _audit_syscalladded = 0;
+int _audit_uringopadded = 0;
int _audit_exeadded = 0;
int _audit_filterfsadded = 0;
unsigned int _audit_elf = 0U;
@@ -999,6 +1000,26 @@ int audit_rule_syscallbyname_data(struct audit_rule_data
*rule,
return -1;
}
+int audit_rule_uringopbyname_data(struct audit_rule_data *rule,
+ const char *uringop)
+{
+ int nr, i;
+
+ if (!strcmp(uringop, "all")) {
+ for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+ rule->mask[i] = ~0;
+ return 0;
+ }
+ nr = audit_name_to_uringop(uringop);
+ if (nr < 0) {
+ if (isdigit(uringop[0]))
+ nr = strtol(uringop, NULL, 0);
+ }
+ if (nr >= 0)
+ return audit_rule_syscall_data(rule, nr);
+ return -1;
+}
+
int audit_rule_interfield_comp_data(struct audit_rule_data **rulep,
const char *pair,
int flags)
@@ -1044,7 +1065,7 @@ int audit_rule_interfield_comp_data(struct
audit_rule_data **rulep,
return -EAU_COMPVALUNKNOWN;
/* Interfield comparison can only be in exit filter */
- if (flags != AUDIT_FILTER_EXIT)
+ if (flags != AUDIT_FILTER_EXIT && flags != AUDIT_FILTER_URING_EXIT)
return -EAU_EXITONLY;
// It should always be AUDIT_FIELD_COMPARE
@@ -1557,7 +1578,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
}
break;
case AUDIT_EXIT:
- if (flags != AUDIT_FILTER_EXIT)
+ if (flags != AUDIT_FILTER_EXIT &&
+ flags != AUDIT_FILTER_URING_EXIT)
return -EAU_EXITONLY;
vlen = strlen(v);
if (isdigit((char)*(v)))
@@ -1599,7 +1621,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
case AUDIT_DIR:
/* Watch & object filtering is invalid on anything
* but exit */
- if (flags != AUDIT_FILTER_EXIT)
+ if (flags != AUDIT_FILTER_EXIT &&
+ flags != AUDIT_FILTER_URING_EXIT)
return -EAU_EXITONLY;
if (field == AUDIT_WATCH || field == AUDIT_DIR)
_audit_permadded = 1;
@@ -1621,9 +1644,11 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
_audit_exeadded = 1;
}
if (field == AUDIT_FILTERKEY &&
- !(_audit_syscalladded || _audit_permadded ||
- _audit_exeadded ||
- _audit_filterfsadded))
+ !(_audit_syscalladded ||
+ _audit_uringopadded ||
+ _audit_permadded ||
+ _audit_exeadded ||
+ _audit_filterfsadded))
return -EAU_KEYDEP;
vlen = strlen(v);
if (field == AUDIT_FILTERKEY &&
@@ -1712,7 +1737,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
}
break;
case AUDIT_FILETYPE:
- if (!(flags == AUDIT_FILTER_EXIT))
+ if (!(flags == AUDIT_FILTER_EXIT ||
+ flags == AUDIT_FILTER_URING_EXIT))
return -EAU_EXITONLY;
rule->values[rule->field_count] =
audit_name_to_ftype(v);
@@ -1754,7 +1780,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
return -EAU_FIELDNOSUPPORT;
if (flags != AUDIT_FILTER_EXCLUDE &&
flags != AUDIT_FILTER_USER &&
- flags != AUDIT_FILTER_EXIT)
+ flags != AUDIT_FILTER_EXIT &&
+ flags != AUDIT_FILTER_URING_EXIT)
return -EAU_FIELDNOFILTER;
// Do positive & negative separate for 32 bit systems
vlen = strlen(v);
@@ -1775,7 +1802,8 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
break;
case AUDIT_DEVMAJOR...AUDIT_INODE:
case AUDIT_SUCCESS:
- if (flags != AUDIT_FILTER_EXIT)
+ if (flags != AUDIT_FILTER_EXIT &&
+ flags != AUDIT_FILTER_URING_EXIT)
return -EAU_EXITONLY;
/* fallthrough */
default:
@@ -1785,7 +1813,9 @@ int audit_rule_fieldpair_data(struct audit_rule_data
**rulep, const char *pair,
return -EAU_OPEQNOTEQ;
}
- if (field == AUDIT_PPID && !(flags==AUDIT_FILTER_EXIT))
+ if (field == AUDIT_PPID &&
+ !(flags == AUDIT_FILTER_EXIT ||
+ flags == AUDIT_FILTER_URING_EXIT))
return -EAU_EXITONLY;
if (!isdigit((char)*(v)))
diff --git a/lib/libaudit.h b/lib/libaudit.h
index 08b7d22678aa..a73edc677df0 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -341,6 +341,9 @@ extern "C" {
#ifndef AUDIT_FILTER_EXCLUDE
#define AUDIT_FILTER_EXCLUDE AUDIT_FILTER_TYPE
#endif
+#ifndef AUDIT_FILTER_URING_EXIT
+#define AUDIT_FILTER_URING_EXIT 0x07 /* filter on exit from io_uring op
*/
+#endif
#define AUDIT_FILTER_MASK 0x07 /* Mask to get actual filter */
#define AUDIT_FILTER_UNSET 0x80 /* This value means filter is unset */
@@ -612,6 +615,8 @@ extern int audit_name_to_field(const char *field);
extern const char *audit_field_to_name(int field);
extern int audit_name_to_syscall(const char *sc, int machine);
extern const char *audit_syscall_to_name(int sc, int machine);
+extern int audit_name_to_uringop(const char *uringopop);
+extern const char *audit_uringop_to_name(int uringop);
extern int audit_name_to_flag(const char *flag);
extern const char *audit_flag_to_name(int flag);
extern int audit_name_to_action(const char *action);
@@ -706,6 +711,8 @@ extern struct audit_rule_data *audit_rule_create_data(void);
extern void audit_rule_init_data(struct audit_rule_data *rule);
extern int audit_rule_syscallbyname_data(struct audit_rule_data *rule,
const char *scall);
+extern int audit_rule_uringopbyname_data(struct audit_rule_data *rule,
+ const char *uringop);
/* Note that the following function takes a **, where audit_rule_fieldpair()
* takes just a *. That structure may need to be reallocated as a result of
* adding new fields */
diff --git a/lib/lookup_table.c b/lib/lookup_table.c
index 23678a4d142e..ca619fba930d 100644
--- a/lib/lookup_table.c
+++ b/lib/lookup_table.c
@@ -142,6 +142,18 @@ int audit_name_to_syscall(const char *sc, int machine)
return -1;
}
+int audit_name_to_uringop(const char *uringop)
+{
+ int res = -1, found = 0;
+
+#ifndef NO_TABLES
+ //found = uringop_s2i(uringop, &res);
+#endif
+ if (found)
+ return res;
+ return -1;
+}
+
const char *audit_syscall_to_name(int sc, int machine)
{
#ifndef NO_TABLES
@@ -172,6 +184,14 @@ const char *audit_syscall_to_name(int sc, int machine)
return NULL;
}
+const char *audit_uringop_to_name(int uringop)
+{
+#ifndef NO_TABLES
+ //return uringop_i2s(uringop);
+#endif
+ return NULL;
+}
+
int audit_name_to_flag(const char *flag)
{
int res;
diff --git a/lib/private.h b/lib/private.h
index c3a7364fcfb8..b0d3fa4109c5 100644
--- a/lib/private.h
+++ b/lib/private.h
@@ -135,6 +135,7 @@ AUDIT_HIDDEN_END
extern int _audit_permadded;
extern int _audit_archadded;
extern int _audit_syscalladded;
+extern int _audit_uringopadded;
extern int _audit_exeadded;
extern int _audit_filterfsadded;
extern unsigned int _audit_elf;
diff --git a/src/auditctl-listing.c b/src/auditctl-listing.c
index a5d6bc2b046f..3d80906ffd24 100644
--- a/src/auditctl-listing.c
+++ b/src/auditctl-listing.c
@@ -137,15 +137,22 @@ static int print_syscall(const struct audit_rule_data *r,
unsigned int *sc)
int all = 1;
unsigned int i;
int machine = audit_detect_machine();
-
- /* Rules on the following filters do not take a syscall */
- if (((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_USER) ||
- ((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_TASK) ||
- ((r->flags &AUDIT_FILTER_MASK) == AUDIT_FILTER_EXCLUDE) ||
- ((r->flags &AUDIT_FILTER_MASK) == AUDIT_FILTER_FS))
+ int uring = 0;
+
+ /* Rules on the following filters do not take a syscall (or uringop) */
+ switch (r->flags & AUDIT_FILTER_MASK) {
+ case AUDIT_FILTER_USER:
+ case AUDIT_FILTER_TASK:
+ case AUDIT_FILTER_EXCLUDE:
+ case AUDIT_FILTER_FS:
return 0;
+ break;
+ case AUDIT_FILTER_URING_EXIT:
+ uring = 1;
+ break;
+ }
- /* See if its all or specific syscalls */
+ /* See if its all or specific syscalls/uringops */
for (i = 0; i < (AUDIT_BITMASK_SIZE-1); i++) {
if (r->mask[i] != (uint32_t)~0) {
all = 0;
@@ -154,21 +161,32 @@ static int print_syscall(const struct audit_rule_data *r,
unsigned int *sc)
}
if (all) {
- printf(" -S all");
+ if (uring)
+ printf(" -U all");
+ else
+ printf(" -S all");
count = i;
} else for (i = 0; i < AUDIT_BITMASK_SIZE * 32; i++) {
int word = AUDIT_WORD(i);
int bit = AUDIT_BIT(i);
if (r->mask[word] & bit) {
const char *ptr;
- if (_audit_elf)
- machine = audit_elf_to_machine(_audit_elf);
- if (machine < 0)
- ptr = NULL;
- else
- ptr = audit_syscall_to_name(i, machine);
+
+ if (uring)
+ ptr = audit_uringop_to_name(i);
+ else {
+ if (_audit_elf)
+ machine =
audit_elf_to_machine(_audit_elf);
+ if (machine < 0)
+ ptr = NULL;
+ else
+ ptr = audit_syscall_to_name(i, machine);
+ }
if (!count)
- printf(" -S ");
+ if (uring)
+ printf(" -U ");
+ else
+ printf(" -S ");
if (ptr)
printf("%s%s", !count ? "" : ",", ptr);
else
@@ -297,7 +315,7 @@ static void print_rule(const struct audit_rule_data *r)
int mach = -1, watch = is_watch(r);
unsigned long long a0 = 0, a1 = 0;
- if (!watch) { /* This is syscall auditing */
+ if (!watch) { /* This is syscall or uring auditing */
printf("-a %s,%s",
audit_action_to_name((int)r->action),
audit_flag_to_name(r->flags));
@@ -310,7 +328,7 @@ static void print_rule(const struct audit_rule_data *r)
mach = print_arch(r->values[i], op);
}
}
- // And last do the syscalls
+ // And last do the syscalls/uringops
count = print_syscall(r, &sc);
}
diff --git a/src/auditctl.c b/src/auditctl.c
index f9bfc2a247d2..74df4f17f887 100644
--- a/src/auditctl.c
+++ b/src/auditctl.c
@@ -76,6 +76,7 @@ static int reset_vars(void)
{
list_requested = 0;
_audit_syscalladded = 0;
+ _audit_uringopadded = 0;
_audit_permadded = 0;
_audit_archadded = 0;
_audit_exeadded = 0;
@@ -110,7 +111,7 @@ static void usage(void)
" -C f=f Compare collected fields if
available:\n"
" Field name, operator(=,!=), field
name\n"
" -d <l,a> Delete rule from <l>ist with
<a>ction\n"
- "
l=task,exit,user,exclude,filesystem\n"
+ "
l=task,exit,user,exclude,filesystem,uring\n"
" a=never,always\n"
" -D Delete all rules and watches\n"
" -e [0..2] Set enabled flag\n"
@@ -132,6 +133,7 @@ static void usage(void)
" -S syscall Build rule: syscall name or
number\n"
" --signal <signal> Send the specified signal to the
daemon\n"
" -t Trim directory watches\n"
+ " -U uringop Build rule: uring op name or
number\n"
" -v Version\n"
" -w <path> Insert watch at <path>\n"
" -W <path> Remove watch at <path>\n"
@@ -164,6 +166,8 @@ static int lookup_filter(const char *str, int *filter)
exclude = 1;
} else if (strcmp(str, "filesystem") == 0)
*filter = AUDIT_FILTER_FS;
+ else if (strcmp(str, "uring") == 0)
+ *filter = AUDIT_FILTER_URING_EXIT;
else
return 2;
return 0;
@@ -541,6 +545,36 @@ static int parse_syscall(const char *optarg)
return audit_rule_syscallbyname_data(rule_new, optarg);
}
+static int parse_uringop(const char *optarg)
+{
+ int retval = 0;
+ char *saved;
+
+ if (strchr(optarg, ',')) {
+ char *ptr, *tmp = strdup(optarg);
+ if (tmp == NULL)
+ return -1;
+ ptr = strtok_r(tmp, ",", &saved);
+ while (ptr) {
+ retval = audit_rule_uringopbyname_data(rule_new, ptr);
+ if (retval != 0) {
+ if (retval == -1) {
+ audit_msg(LOG_ERR,
+ "Uring op name unknown: %s",
+ ptr);
+ retval = -3; // error reported
+ }
+ break;
+ }
+ ptr = strtok_r(NULL, ",", &saved);
+ }
+ free(tmp);
+ return retval;
+ }
+
+ return audit_rule_uringopbyname_data(rule_new, optarg);
+}
+
static struct option long_opts[] =
{
#if HAVE_DECL_AUDIT_FEATURE_VERSION == 1
@@ -576,7 +610,7 @@ static int setopt(int count, int lineno, char *vars[])
keylen = AUDIT_MAX_KEY_LEN;
while ((retval >= 0) && (c = getopt_long(count, vars,
- "hicslDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:",
+ "hicslDvtC:e:f:r:b:a:A:d:S:U:F:m:R:w:W:k:p:q:",
long_opts, &lidx)) != EOF) {
int flags = AUDIT_FILTER_UNSET;
rc = 10; // Init to something impossible to see if unused.
@@ -715,9 +749,10 @@ static int setopt(int count, int lineno, char *vars[])
retval = -1;
break;
case 'a':
- if (strstr(optarg, "task") && _audit_syscalladded) {
+ if (strstr(optarg, "task") && (_audit_syscalladded ||
+ _audit_uringopadded)) {
audit_msg(LOG_ERR,
- "Syscall auditing requested for task list");
+ "Syscall or uring op auditing requested for
task list");
retval = -1;
} else {
rc = audit_rule_setup(optarg, &add, &action);
@@ -739,9 +774,10 @@ static int setopt(int count, int lineno, char *vars[])
}
break;
case 'A':
- if (strstr(optarg, "task") && _audit_syscalladded) {
- audit_msg(LOG_ERR,
- "Error: syscall auditing requested for task list");
+ if (strstr(optarg, "task") && (_audit_syscalladded ||
+ _audit_uringopadded)) {
+ audit_msg(LOG_ERR,
+ "Syscall or uring op auditing requested for
task list");
retval = -1;
} else {
rc = audit_rule_setup(optarg, &add, &action);
@@ -809,6 +845,10 @@ static int setopt(int count, int lineno, char *vars[])
audit_msg(LOG_ERR,
"Error: syscall auditing cannot be put on exclude list");
return -1;
+ } else if (((add | del) & AUDIT_FILTER_MASK) ==
AUDIT_FILTER_URING_EXIT) {
+ audit_msg(LOG_ERR,
+ "Error: syscall auditing cannot be put on uringop list");
+ return -1;
} else {
if (unknown_arch) {
int machine;
@@ -853,14 +893,63 @@ static int setopt(int count, int lineno, char *vars[])
break;
}}
break;
+ case 'U':
+ /* Do some checking to make sure that we are not adding a
+ * uring op rule to a list that does not make sense. */
+ if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_TASK || (del &
+ (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_TASK)) {
+ audit_msg(LOG_ERR,
+ "Error: uring op auditing being added to task list");
+ return -1;
+ } else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_USER || (del &
+ (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_USER)) {
+ audit_msg(LOG_ERR,
+ "Error: uring op auditing being added to user list");
+ return -1;
+ } else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_FS || (del &
+ (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
+ AUDIT_FILTER_FS)) {
+ audit_msg(LOG_ERR,
+ "Error: uring op auditing being added to filesystem
list");
+ return -1;
+ } else if (exclude) {
+ audit_msg(LOG_ERR,
+ "Error: uring op auditing cannot be put on exclude list");
+ return -1;
+ } else if (((add | del) & AUDIT_FILTER_MASK) ==
AUDIT_FILTER_EXIT) {
+ audit_msg(LOG_ERR,
+ "Error: uringop auditing cannot be put on syscall list");
+ return -1;
+ }
+ rc = parse_uringop(optarg);
+ switch (rc)
+ {
+ case 0:
+ _audit_uringopadded = 1;
+ break;
+ case -1:
+ audit_msg(LOG_ERR, "Uring op name unknown: %s",
+ optarg);
+ retval = -1;
+ break;
+ case -3: // Error reported - do nothing here
+ retval = -1;
+ break;
+ }
+ break;
case 'F':
if (add != AUDIT_FILTER_UNSET)
flags = add & AUDIT_FILTER_MASK;
else if (del != AUDIT_FILTER_UNSET)
flags = del & AUDIT_FILTER_MASK;
- // if the field is arch & there is a -t option...we
+ // if the field is arch & there is a -t option...we
// can allow it
- else if ((optind >= count) || (strstr(optarg, "arch=") == NULL)
+ else if ((optind >= count) || (strstr(optarg, "arch=") == NULL
&& _audit_uringopadded != 1)
|| (strcmp(vars[optind], "-t") != 0)) {
audit_msg(LOG_ERR, "List must be given before field");
retval = -1;
@@ -989,12 +1078,12 @@ static int setopt(int count, int lineno, char *vars[])
}
break;
case 'k':
- if (!(_audit_syscalladded || _audit_permadded ||
- _audit_exeadded ||
+ if (!(_audit_syscalladded || _audit_uringopadded ||
+ _audit_permadded || _audit_exeadded ||
_audit_filterfsadded) ||
(add==AUDIT_FILTER_UNSET && del==AUDIT_FILTER_UNSET)) {
audit_msg(LOG_ERR,
- "key option needs a watch or syscall given prior to it");
+ "key option needs a watch, syscall or uring op given prior
to it");
retval = -1;
break;
} else if (!optarg) {
@@ -1031,7 +1120,7 @@ process_keys:
retval = audit_setup_perms(rule_new, optarg);
break;
case 'q':
- if (_audit_syscalladded) {
+ if (_audit_syscalladded || _audit_uringopadded) {
audit_msg(LOG_ERR,
"Syscall auditing requested for make equivalent");
retval = -1;
@@ -1466,7 +1555,7 @@ int main(int argc, char *argv[])
static int handle_request(int status)
{
if (status == 0) {
- if (_audit_syscalladded) {
+ if (_audit_syscalladded || _audit_uringopadded) {
audit_msg(LOG_ERR, "Error - no list specified");
return -1;
}
@@ -1478,7 +1567,7 @@ static int handle_request(int status)
if (add != AUDIT_FILTER_UNSET) {
// if !task add syscall any if not specified
if ((add & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK &&
- _audit_syscalladded != 1) {
+ (_audit_syscalladded != 1 &&
_audit_uringopadded != 1)) {
audit_rule_syscallbyname_data(
rule_new, "all");
}
@@ -1502,7 +1591,7 @@ static int handle_request(int status)
}
else if (del != AUDIT_FILTER_UNSET) {
if ((del & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK &&
- _audit_syscalladded != 1) {
+ (_audit_syscalladded != 1 &&
_audit_uringopadded != 1)) {
audit_rule_syscallbyname_data(
rule_new, "all");
}
--
2.27.0
--
Linux-audit mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/linux-audit