public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Add uringop support
@ 2021-10-28 19:59 Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type Richard Guy Briggs
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Audit support for iouring went into the upstream kernel with commit
5bd2182d58e9 ("audit,io_uring,io-wq: add some basic audit support to io_uring")
and commit 67daf270cebc ("audit: add filtering for io_uring records").

Add userspace support for AUDIT_URINGOP records, uringop fields and the
AUDIT_FILTER_URING_EXIT filter list.

Changelog:
v3
- rebase on openat2                                                                                                                                                                                                                 
- re-factor and re-order patchset

v2
- check for watch before adding perm
- update manpage to include filesystem filter
- add support for the AUDIT_URINGOP record type
- update support for the uring filter list: doc, -U op, op names
- add uringop support to ausearch
- add uringop support to aureport
- lots of bug fixes

Richard Guy Briggs (7):
  add basic support for the AUDIT_URINGOP record type
  add support for the uring filter list
  add support for uringop names
  add field support for the AUDIT_URINGOP record type
  add ausearch --uringop option
  add aureport --uringop option
  add iouring support to the normalizer

 audisp/plugins/ids/model_behavior.c |   1 +
 auparse/auparse-defs.h              |   2 +-
 auparse/auparse-idata.h             |   1 +
 auparse/ellist.c                    |   7 ++
 auparse/interpret.c                 |  21 ++++-
 auparse/normalize.c                 |   1 +
 auparse/normalize_record_map.h      |   1 +
 auparse/rnode.h                     |   1 +
 auparse/typetab.h                   |   1 +
 bindings/python/auparse_python.c    |   1 +
 contrib/plugin/audisp-example.c     |   1 +
 docs/audit.rules.7                  |  19 +++--
 docs/audit_add_rule_data.3          |   4 +
 docs/auditctl.8                     |  10 ++-
 docs/aureport.8                     |   3 +
 docs/ausearch.8                     |   3 +
 lib/Makefile.am                     |  17 +++-
 lib/flagtab.h                       |  11 +--
 lib/libaudit.c                      |  50 ++++++++---
 lib/libaudit.h                      |  11 +++
 lib/lookup_table.c                  |  21 +++++
 lib/msg_typetab.h                   |   1 +
 lib/private.h                       |   1 +
 lib/test/lookup_test.c              |  17 ++++
 lib/uringop_table.h                 |  62 ++++++++++++++
 src/auditctl-listing.c              |  52 ++++++++----
 src/auditctl.c                      | 121 +++++++++++++++++++++++----
 src/auditd-event.c                  |   1 +
 src/aureport-options.c              |  19 ++++-
 src/aureport-options.h              |   2 +-
 src/aureport-output.c               |  37 +++++++++
 src/aureport-scan.c                 |  26 ++++++
 src/aureport-scan.h                 |   2 +
 src/aureport.c                      |   3 +-
 src/ausearch-common.h               |   1 +
 src/ausearch-llist.c                |   2 +
 src/ausearch-llist.h                |   1 +
 src/ausearch-lookup.c               |  25 ++++++
 src/ausearch-lookup.h               |   1 +
 src/ausearch-match.c                |   6 +-
 src/ausearch-options.c              |  36 +++++++-
 src/ausearch-parse.c                | 123 +++++++++++++++++++++++++++-
 src/ausearch-report.c               |  21 ++++-
 43 files changed, 677 insertions(+), 70 deletions(-)
 create mode 100644 lib/uringop_table.h

-- 
2.27.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-28 21:19   ` Steve Grubb
  2021-10-28 19:59 ` [PATCH v3 2/7] add support for the uring filter list Richard Guy Briggs
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Kernel support to audit io_uring operations was added with commit
5bd2182d58e9 ("audit,io_uring,io-wq: add some basic audit support to
io_uring").  Add basic support to recognize the "AUDIT_URINGOP" record.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 lib/libaudit.h    | 4 ++++
 lib/msg_typetab.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/lib/libaudit.h b/lib/libaudit.h
index 4e532177aa11..08b7d22678aa 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -307,6 +307,10 @@ extern "C" {
 #define AUDIT_EVENT_LISTENER	1335 /* audit mcast sock join/part */
 #endif
 
+#ifndef AUDIT_URINGOP
+#define AUDIT_URINGOP		1336 /* io_uring operations */
+#endif
+
 #ifndef AUDIT_OPENAT2
 #define AUDIT_OPENAT2		1337 /* openat2 open_how flags */
 #endif
diff --git a/lib/msg_typetab.h b/lib/msg_typetab.h
index 030b1952f2cb..f8ae4514893b 100644
--- a/lib/msg_typetab.h
+++ b/lib/msg_typetab.h
@@ -127,6 +127,7 @@ _S(AUDIT_TIME_INJOFFSET,             "TIME_INJOFFSET"                )
 _S(AUDIT_TIME_ADJNTPVAL,             "TIME_ADJNTPVAL"                )
 _S(AUDIT_BPF,                        "BPF"                           )
 _S(AUDIT_EVENT_LISTENER,             "EVENT_LISTENER"                )
+_S(AUDIT_URINGOP,                    "URINGOP"                       )
 _S(AUDIT_OPENAT2,                    "OPENAT2"                       )
 _S(AUDIT_AVC,                        "AVC"                           )
 _S(AUDIT_SELINUX_ERR,                "SELINUX_ERR"                   )
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 2/7] add support for the uring filter list
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-29 18:39   ` Steve Grubb
  2021-10-28 19:59 ` [PATCH v3 3/7] add support for uringop names Richard Guy Briggs
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 3/7] add support for uringop names
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 2/7] add support for the uring filter list Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 4/7] add field support for the AUDIT_URINGOP record type Richard Guy Briggs
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 lib/Makefile.am        | 17 ++++++++++--
 lib/lookup_table.c     |  5 ++--
 lib/test/lookup_test.c | 17 ++++++++++++
 lib/uringop_table.h    | 62 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 4 deletions(-)
 create mode 100644 lib/uringop_table.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index f1107afabee6..7926ba50a78f 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -47,7 +47,7 @@ nodist_libaudit_la_SOURCES = $(BUILT_SOURCES)
 BUILT_SOURCES = actiontabs.h errtabs.h fieldtabs.h flagtabs.h \
 	fstypetabs.h ftypetabs.h i386_tables.h machinetabs.h \
 	msg_typetabs.h optabs.h ppc_tables.h s390_tables.h \
-	s390x_tables.h x86_64_tables.h
+	s390x_tables.h x86_64_tables.h uringop_tables.h
 if USE_ARM
 BUILT_SOURCES += arm_tables.h
 endif
@@ -58,7 +58,7 @@ noinst_PROGRAMS = gen_actiontabs_h gen_errtabs_h gen_fieldtabs_h \
 	gen_flagtabs_h gen_fstypetabs_h gen_ftypetabs_h gen_i386_tables_h \
 	gen_machinetabs_h gen_msg_typetabs_h \
 	gen_optabs_h gen_ppc_tables_h gen_s390_tables_h \
-	gen_s390x_tables_h gen_x86_64_tables_h
+	gen_s390x_tables_h gen_x86_64_tables_h gen_uringop_tables_h
 if USE_ARM
 noinst_PROGRAMS += gen_arm_tables_h
 endif
@@ -266,6 +266,19 @@ gen_s390x_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD)
 s390x_tables.h: gen_s390x_tables_h Makefile
 	./gen_s390x_tables_h --lowercase --i2s --s2i s390x_syscall > $@
 
+gen_uringop_tables_h_SOURCES = gen_tables.c gen_tables.h uringop_table.h
+gen_uringop_tables_h_CFLAGS = '-DTABLE_H="uringop_table.h"'
+$(gen_uringop_tables_h_OBJECTS): CC=$(CC_FOR_BUILD)
+$(gen_uringop_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD)
+$(gen_uringop_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD)
+$(gen_uringop_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD)
+gen_uringop_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD)
+gen_uringop_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD)
+gen_uringop_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD)
+gen_uringop_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD)
+uringop_tables.h: gen_uringop_tables_h Makefile
+	./gen_uringop_tables_h --lowercase --i2s --s2i uringop > $@
+
 gen_x86_64_tables_h_SOURCES = gen_tables.c gen_tables.h x86_64_table.h
 gen_x86_64_tables_h_CFLAGS = '-DTABLE_H="x86_64_table.h"'
 $(gen_x86_64_tables_h_OBJECTS): CC=$(CC_FOR_BUILD)
diff --git a/lib/lookup_table.c b/lib/lookup_table.c
index ca619fba930d..d895b1ffe530 100644
--- a/lib/lookup_table.c
+++ b/lib/lookup_table.c
@@ -46,6 +46,7 @@
 #include "s390_tables.h"
 #include "s390x_tables.h"
 #include "x86_64_tables.h"
+#include "uringop_tables.h"
 #include "errtabs.h"
 #include "fstypetabs.h"
 #include "ftypetabs.h"
@@ -147,7 +148,7 @@ int audit_name_to_uringop(const char *uringop)
 	int res = -1, found = 0;
 
 #ifndef NO_TABLES
-	//found = uringop_s2i(uringop, &res);
+	found = uringop_s2i(uringop, &res);
 #endif
 	if (found)
 		return res;
@@ -187,7 +188,7 @@ const char *audit_syscall_to_name(int sc, int machine)
 const char *audit_uringop_to_name(int uringop)
 {
 #ifndef NO_TABLES
-	//return uringop_i2s(uringop);
+	return uringop_i2s(uringop);
 #endif
 	return NULL;
 }
diff --git a/lib/test/lookup_test.c b/lib/test/lookup_test.c
index 03f40aaf0899..f58d9dde65dd 100644
--- a/lib/test/lookup_test.c
+++ b/lib/test/lookup_test.c
@@ -234,6 +234,22 @@ test_x86_64_table(void)
 #undef S2I
 }
 
+static void
+test_uringop_table(void)
+{
+	static const struct entry t[] = {
+#include "../uringop_table.h"
+	};
+
+	printf("Testing uringop_table...\n");
+#define I2S(I) audit_uringop_to_name((I))
+#define S2I(S) audit_name_to_uringop((S))
+	TEST_I2S(0);
+	TEST_S2I(-1);
+#undef I2S
+#undef S2I
+}
+
 static void
 test_actiontab(void)
 {
@@ -395,6 +411,7 @@ main(void)
 	test_s390_table();
 	test_s390x_table();
 	test_x86_64_table();
+	test_uringop_table();
 	test_actiontab();
 	test_errtab();
 	test_fieldtab();
diff --git a/lib/uringop_table.h b/lib/uringop_table.h
new file mode 100644
index 000000000000..241828efc654
--- /dev/null
+++ b/lib/uringop_table.h
@@ -0,0 +1,62 @@
+/* uringop_table.h --
+ * Copyright 2005-21 Red Hat Inc.
+ * All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *      Richard Guy Briggs <[email protected]>
+ */
+
+/* from /usr/include/linux/io_uring.h */
+
+_S(0,	"nop")
+_S(1,	"readv")
+_S(2,	"writev")
+_S(3,	"fsync")
+_S(4,	"read_fixed")
+_S(5,	"write_fixed")
+_S(6,	"poll_add")
+_S(7,	"poll_remove")
+_S(8,	"sync_file_range")
+_S(9,	"sendmsg")
+_S(10,	"recvmsg")
+_S(11,	"timeout")
+_S(12,	"timeout_remove")
+_S(13,	"accept")
+_S(14,	"async_cancel")
+_S(15,	"link_timeout")
+_S(16,	"connect")
+_S(17,	"fallocate")
+_S(18,	"openat")
+_S(19,	"close")
+_S(20,	"files_update")
+_S(21,	"statx")
+_S(22,	"read")
+_S(23,	"write")
+_S(24,	"fadvise")
+_S(25,	"madvise")
+_S(26,	"send")
+_S(27,	"recv")
+_S(28,	"openat2")
+_S(29,	"epoll_ctl")
+_S(30,	"splice")
+_S(31,	"provide_bufers")
+_S(32,	"remove_bufers")
+_S(33,	"tee")
+_S(34,	"shutdown")
+_S(35,	"renameat")
+_S(36,	"unlinkat")
+
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 4/7] add field support for the AUDIT_URINGOP record type
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
                   ` (2 preceding siblings ...)
  2021-10-28 19:59 ` [PATCH v3 3/7] add support for uringop names Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 5/7] add ausearch --uringop option Richard Guy Briggs
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Kernel support to audit io_uring operations was added with commit 5bd2182d58e9
("audit,io_uring,io-wq: add some basic audit support to io_uring").  Add
support to interpret the "uringop" record field.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 audisp/plugins/ids/model_behavior.c |  1 +
 auparse/auparse-defs.h              |  2 +-
 auparse/auparse-idata.h             |  1 +
 auparse/ellist.c                    |  7 +++++++
 auparse/interpret.c                 | 21 ++++++++++++++++++++-
 auparse/rnode.h                     |  1 +
 auparse/typetab.h                   |  1 +
 bindings/python/auparse_python.c    |  1 +
 contrib/plugin/audisp-example.c     |  1 +
 src/auditd-event.c                  |  1 +
 10 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/audisp/plugins/ids/model_behavior.c b/audisp/plugins/ids/model_behavior.c
index df94fcaf4b0e..09c7017569b9 100644
--- a/audisp/plugins/ids/model_behavior.c
+++ b/audisp/plugins/ids/model_behavior.c
@@ -80,6 +80,7 @@ void process_behavior_model(auparse_state_t *au, struct ids_conf *config)
 	/* Now we can branch based on what the first record type we find. */
 	switch (type) {
 		case AUDIT_SYSCALL:
+		case AUDIT_URINGOP:
 			process_plain_syscalls(au);
 			break;
 		//case SECCOMP:
diff --git a/auparse/auparse-defs.h b/auparse/auparse-defs.h
index 7c0ac76c84cc..7e17d3306b4e 100644
--- a/auparse/auparse-defs.h
+++ b/auparse/auparse-defs.h
@@ -88,7 +88,7 @@ typedef enum {  AUPARSE_TYPE_UNCLASSIFIED,  AUPARSE_TYPE_UID, AUPARSE_TYPE_GID,
 	AUPARSE_TYPE_NETACTION, AUPARSE_TYPE_MACPROTO,
 	AUPARSE_TYPE_IOCTL_REQ, AUPARSE_TYPE_ESCAPED_KEY,
 	AUPARSE_TYPE_ESCAPED_FILE, AUPARSE_TYPE_FANOTIFY,
-	AUPARSE_TYPE_NLMCGRP, AUPARSE_TYPE_RESOLVE
+	AUPARSE_TYPE_NLMCGRP, AUPARSE_TYPE_URINGOP, AUPARSE_TYPE_RESOLVE
 } auparse_type_t;
 
 /* This type determines what escaping if any gets applied to interpreted fields */
diff --git a/auparse/auparse-idata.h b/auparse/auparse-idata.h
index eaca86a3da24..42f65d35b65b 100644
--- a/auparse/auparse-idata.h
+++ b/auparse/auparse-idata.h
@@ -33,6 +33,7 @@ typedef struct _idata {
 	int syscall;		// The syscall for the event
 	unsigned long long a0;	// arg 0 to the syscall
 	unsigned long long a1;	// arg 1 to the syscall
+	int uringop;		// The uring op for the event
 	const char *cwd;	// The current working directory
 	const char *name;	// name of field being interpreted
 	const char *val;	// value of field being interpreted
diff --git a/auparse/ellist.c b/auparse/ellist.c
index ae85addbe52a..cac2a9f38d8e 100644
--- a/auparse/ellist.c
+++ b/auparse/ellist.c
@@ -278,6 +278,12 @@ static int parse_up_record(rnode* r)
 			} else if (r->type == AUDIT_CWD) {
 				if (strcmp(n.name, "cwd") == 0)
 					r->cwd = strdup(n.val);
+			} else if (r->nv.cnt == (3 + offset) &&
+					strcmp(n.name, "uringop") == 0){
+				errno = 0;
+				r->uringop = strtoul(n.val, NULL, 10);
+				if (errno)
+					r->uringop = -1;
 			}
 		} else if (r->type == AUDIT_AVC || r->type == AUDIT_USER_AVC) {
 			// We special case these 2 fields because selinux
@@ -362,6 +368,7 @@ int aup_list_append(event_list_t *l, char *record, int list_idx,
 	r->a1 = 0LL;
 	r->machine = -1;
 	r->syscall = -1;
+	r->uringop = -1;
 	r->item = l->cnt; 
 	r->list_idx = list_idx;
 	r->line_number = line_number;
diff --git a/auparse/interpret.c b/auparse/interpret.c
index 92b95b6a6dc8..8b5150638c4d 100644
--- a/auparse/interpret.c
+++ b/auparse/interpret.c
@@ -501,7 +501,7 @@ const char *_auparse_lookup_interpretation(const char *name)
 	if (nvlist_find_name(&il, name)) {
 		n = nvlist_get_cur(&il);
 		// This is only called from src/ausearch-lookup.c
-		// it only looks up auid and syscall. One needs
+		// it only looks up auid and syscall/uringop. One needs
 		// escape, the other does not.
 		if (strstr(name, "id"))
 			return print_escaped(n->interp_val);
@@ -817,6 +817,21 @@ static const char *print_syscall(const idata *id)
 	return out;
 }
 
+static const char *print_uringop(const idata *id)
+{
+	const char *uring;
+	char *out;
+	int uringop = id->uringop;
+
+	uring = audit_uringop_to_name(uringop);
+	if (uring) {
+		return strdup(uring);
+	}
+	if (asprintf(&out, "unknown-uringop(%d)", uringop) < 0)
+		out = NULL;
+	return out;
+}
+
 static const char *print_exit(const char *val)
 {
         long long ival;
@@ -3049,6 +3064,7 @@ const char *do_interpret(const rnode *r, auparse_esc_t escape_mode)
 
 	id.machine = r->machine;
 	id.syscall = r->syscall;
+	id.uringop = r->uringop;
 	id.a0 = r->a0;
 	id.a1 = r->a1;
 	id.cwd = r->cwd;
@@ -3164,6 +3180,9 @@ unknown:
 		case AUPARSE_TYPE_ARCH:
 			out = print_arch(id->val, id->machine);
 			break;
+		case AUPARSE_TYPE_URINGOP:
+			out = print_uringop(id);
+			break;
 		case AUPARSE_TYPE_EXIT:
 			out = print_exit(id->val);
 			break;
diff --git a/auparse/rnode.h b/auparse/rnode.h
index 69f084369523..69e89170cdf6 100644
--- a/auparse/rnode.h
+++ b/auparse/rnode.h
@@ -55,6 +55,7 @@ typedef struct _rnode{
 	int syscall;            // The syscall for the event
 	unsigned long long a0;  // arg 0 to the syscall
 	unsigned long long a1;  // arg 1 to the syscall
+	int uringop;            // The uring op for the event
 	nvlist nv;              // name-value linked list of parsed elements
 	unsigned int item;      // Which item of the same event
 	int list_idx;		// The index into the source list, points to where record was found
diff --git a/auparse/typetab.h b/auparse/typetab.h
index 4a3027957072..ced0ce47fcaf 100644
--- a/auparse/typetab.h
+++ b/auparse/typetab.h
@@ -44,6 +44,7 @@ _S(AUPARSE_TYPE_GID,		"igid"		)
 _S(AUPARSE_TYPE_GID,		"inode_gid"	)
 _S(AUPARSE_TYPE_GID,		"new_gid"	)
 _S(AUPARSE_TYPE_SYSCALL,	"syscall"	)
+_S(AUPARSE_TYPE_URINGOP,	"uringop"	)
 _S(AUPARSE_TYPE_ARCH,		"arch"		)
 _S(AUPARSE_TYPE_EXIT,		"exit"		)
 _S(AUPARSE_TYPE_ESCAPED,	"path"		)
diff --git a/bindings/python/auparse_python.c b/bindings/python/auparse_python.c
index 77dd8615cf50..f924fb269a53 100644
--- a/bindings/python/auparse_python.c
+++ b/bindings/python/auparse_python.c
@@ -2356,6 +2356,7 @@ initauparse(void)
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_UID",     AUPARSE_TYPE_UID);
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_GID",     AUPARSE_TYPE_GID);
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_SYSCALL", AUPARSE_TYPE_SYSCALL);
+    PyModule_AddIntConstant(m, "AUPARSE_TYPE_URINGOP", AUPARSE_TYPE_URINGOP);
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_ARCH",    AUPARSE_TYPE_ARCH);
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_EXIT",    AUPARSE_TYPE_EXIT);
     PyModule_AddIntConstant(m, "AUPARSE_TYPE_ESCAPED", AUPARSE_TYPE_ESCAPED);
diff --git a/contrib/plugin/audisp-example.c b/contrib/plugin/audisp-example.c
index c523c0a19804..6907d2036fb7 100644
--- a/contrib/plugin/audisp-example.c
+++ b/contrib/plugin/audisp-example.c
@@ -225,6 +225,7 @@ static void handle_event(auparse_state_t *au,
 				dump_fields_of_record(au);
 				break;
 			case AUDIT_SYSCALL:
+			case AUDIT_URINGOP:
 				dump_whole_record(au); 
 				break;
 			case AUDIT_USER_LOGIN:
diff --git a/src/auditd-event.c b/src/auditd-event.c
index 788c44a08197..68369fae81ab 100644
--- a/src/auditd-event.c
+++ b/src/auditd-event.c
@@ -456,6 +456,7 @@ static const char *format_enrich(const struct audit_reply *rep)
 					len -= vlen;
 					break;
 				case AUPARSE_TYPE_SYSCALL:
+				case AUPARSE_TYPE_URINGOP:
 				case AUPARSE_TYPE_ARCH:
 				case AUPARSE_TYPE_SOCKADDR:
 					if (add_separator(len))
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 5/7] add ausearch --uringop option
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
                   ` (3 preceding siblings ...)
  2021-10-28 19:59 ` [PATCH v3 4/7] add field support for the AUDIT_URINGOP record type Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 6/7] add aureport " Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 7/7] add iouring support to the normalizer Richard Guy Briggs
  6 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 docs/ausearch.8        |   3 +
 src/ausearch-common.h  |   1 +
 src/ausearch-llist.c   |   2 +
 src/ausearch-llist.h   |   1 +
 src/ausearch-lookup.c  |  25 +++++++++
 src/ausearch-lookup.h  |   1 +
 src/ausearch-match.c   |   6 +-
 src/ausearch-options.c |  36 +++++++++++-
 src/ausearch-parse.c   | 123 +++++++++++++++++++++++++++++++++++++++--
 src/ausearch-report.c  |  21 ++++++-
 10 files changed, 211 insertions(+), 8 deletions(-)

diff --git a/docs/ausearch.8 b/docs/ausearch.8
index dbd6beadeda4..e99911009053 100644
--- a/docs/ausearch.8
+++ b/docs/ausearch.8
@@ -130,6 +130,9 @@ Output is completely unformatted. This is useful for extracting records to a fil
 .BR \-sc ,\  \-\-syscall \ \fIsyscall-name-or-value\fP
 Search for an event matching the given \fIsyscall\fP. You may either give the numeric syscall value or the syscall name. If you give the syscall name, it will use the syscall table for the machine that you are using. 
 .TP
+.BR \-uo ,\  \-\-uringop \ \fIuringop-name-or-value\fP
+Search for an event matching the given \fIuring operation\fP. You may either give the numeric uring operation value or the uring operation name.
+.TP
 .BR \-se ,\  \-\-context \ \fISE-Linux-context-string\fP
 Search for event with either \fIscontext\fP/subject or \fItcontext\fP/object matching the string.
 .TP
diff --git a/src/ausearch-common.h b/src/ausearch-common.h
index 3040547afe95..f20e8570ce9b 100644
--- a/src/ausearch-common.h
+++ b/src/ausearch-common.h
@@ -56,6 +56,7 @@ extern const char *event_filename;
 extern const char *event_hostname;
 extern const char *event_terminal;
 extern int event_syscall;
+extern int event_uringop;
 extern int event_machine;
 extern const char *event_exe;
 extern int event_ua, event_ga;
diff --git a/src/ausearch-llist.c b/src/ausearch-llist.c
index ef5503c34fd9..98d446009865 100644
--- a/src/ausearch-llist.c
+++ b/src/ausearch-llist.c
@@ -59,6 +59,7 @@ void list_create(llist *l)
 	l->s.acct = NULL;
 	l->s.arch = 0;
 	l->s.syscall = 0;
+	l->s.uringop = 0;
 	l->s.session_id = -2;
 	l->s.uuid = NULL;
 	l->s.vmname = NULL;
@@ -210,6 +211,7 @@ void list_clear(llist* l)
 	l->s.acct = NULL;
 	l->s.arch = 0;
 	l->s.syscall = 0;
+	l->s.uringop = 0;
 	l->s.session_id = -2;
 	free(l->s.uuid);
 	l->s.uuid = NULL;
diff --git a/src/ausearch-llist.h b/src/ausearch-llist.h
index 56a2e7da4934..4ef60a0c93e5 100644
--- a/src/ausearch-llist.h
+++ b/src/ausearch-llist.h
@@ -55,6 +55,7 @@ typedef struct
   success_t success;    // success flag, 1 = yes, 0 = no, -1 = unset
   int arch;             // arch
   int syscall;          // syscall
+  int uringop;          // io_uring operation code
   uint32_t session_id;  // Login session id
   long long exit;       // Syscall exit code
   int exit_is_set;      // Syscall exit code is valid
diff --git a/src/ausearch-lookup.c b/src/ausearch-lookup.c
index dd58c36ad8bd..fdf036eccf37 100644
--- a/src/ausearch-lookup.c
+++ b/src/ausearch-lookup.c
@@ -109,6 +109,31 @@ const char *aulookup_syscall(llist *l, char *buf, size_t size)
 	return buf;
 }
 
+const char *aulookup_uringop(llist *l, char *buf, size_t size)
+{
+	const char *uringop;
+
+	if (report_format <= RPT_DEFAULT) {
+		snprintf(buf, size, "%d", l->s.uringop);
+		return buf;
+	}
+
+	uringop = _auparse_lookup_interpretation("uringop");
+	if (uringop) {
+		snprintf(buf, size, "%s", uringop);
+		free((void *)uringop);
+		return buf;
+	}
+
+	uringop = audit_uringop_to_name(l->s.uringop);
+	if (uringop) {
+		snprintf(buf, size, "%s", uringop);
+		return buf;
+	}
+	snprintf(buf, size, "%d", l->s.uringop);
+	return buf;
+}
+
 // See include/linux/net.h
 static struct nv_pair socktab[] = {
 	{SYS_SOCKET, "socket"},
diff --git a/src/ausearch-lookup.h b/src/ausearch-lookup.h
index d1c670147ecd..7f6a793738eb 100644
--- a/src/ausearch-lookup.h
+++ b/src/ausearch-lookup.h
@@ -35,6 +35,7 @@
 const char *aulookup_result(avc_t result);
 const char *aulookup_success(int s);
 const char *aulookup_syscall(llist *l, char *buf, size_t size);
+const char *aulookup_uringop(llist *l, char *buf, size_t size);
 const char *aulookup_uid(uid_t uid, char *buf, size_t size);
 void aulookup_destroy_uid_list(void);
 char *unescape(const char *buf);
diff --git a/src/ausearch-match.c b/src/ausearch-match.c
index 61a11d30a09b..ca3e56e2f4b5 100644
--- a/src/ausearch-match.c
+++ b/src/ausearch-match.c
@@ -45,7 +45,8 @@ static void load_interpretations(const llist *l)
 		return;
 
 	// If there is only 1 record load it, or load just the syscall one
-	if ((l->cnt == 1) || (l->head && l->head->type == AUDIT_SYSCALL))
+	if ((l->cnt == 1) || (l->head && l->head->type == AUDIT_SYSCALL) ||
+			     (l->head && l->head->type == AUDIT_URINGOP))
 		ausearch_load_interpretations(l->head);
 }
 
@@ -110,6 +111,9 @@ int match(llist *l)
 				if ((event_syscall != -1) && 
 					(event_syscall != l->s.syscall))
 						return 0;
+				if ((event_uringop != -1) &&
+					(event_uringop != l->s.uringop))
+						return 0;
 				if ((event_session_id != -2) &&
 					(event_session_id != l->s.session_id))
 					return 0;
diff --git a/src/ausearch-options.c b/src/ausearch-options.c
index a57de79b183b..ab9748f9f95e 100644
--- a/src/ausearch-options.c
+++ b/src/ausearch-options.c
@@ -56,7 +56,7 @@ auparse_esc_t escape_mode = AUPARSE_ESC_TTY;
 int event_exact_match = 0;
 uid_t event_uid = -1, event_euid = -1, event_loginuid = -2;
 const char *event_tuid = NULL, *event_teuid = NULL, *event_tauid = NULL;
-int event_syscall = -1, event_machine = -1;
+int event_syscall = -1, event_machine = -1, event_uringop = -1;
 int event_ua = 0, event_ga = 0, event_se = 0;
 int just_one = 0;
 uint32_t event_session_id = -2;
@@ -93,7 +93,8 @@ S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID,
 S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT,
 S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT,
 S_LINEBUFFERED, S_UUID, S_VMNAME, S_DEBUG, S_CHECKPOINT, S_ARCH, S_FORMAT,
-S_EXTRA_TIME, S_EXTRA_LABELS, S_EXTRA_KEYS, S_EXTRA_OBJ2, S_ESCAPE, S_EOE_TMO };
+S_EXTRA_TIME, S_EXTRA_LABELS, S_EXTRA_KEYS, S_EXTRA_OBJ2, S_ESCAPE, S_EOE_TMO,
+S_URINGOP };
 
 static struct nv_pair optiontab[] = {
 	{ S_EVENT, "-a" },
@@ -148,6 +149,8 @@ static struct nv_pair optiontab[] = {
 	{ S_RAW, "--raw" },
 	{ S_SYSCALL, "-sc" },
 	{ S_SYSCALL, "--syscall" },
+	{ S_URINGOP, "-uo" },
+	{ S_URINGOP, "--uringop" },
 	{ S_CONTEXT, "-se" },
 	{ S_CONTEXT, "--context" },
 	{ S_SESSION, "--session" },
@@ -239,6 +242,7 @@ static void usage(void)
 	"\t-ue,--uid-effective <effective User id>  search based on Effective\n\t\t\t\t\tuser id\n"
 	"\t-ui,--uid <User Id>\t\tsearch based on user id\n"
 	"\t-ul,--loginuid <login id>\tsearch based on the User's Login id\n"
+	"\t-uo,--uringop <SysCall name>\tsearch based on syscall name or number\n"
 	"\t-uu,--uuid <guest UUID>\t\tsearch for events related to the virtual\n"
 	"\t\t\t\t\tmachine with the given UUID.\n"
 	"\t-v,--version\t\t\tversion\n"
@@ -826,6 +830,34 @@ int check_params(int count, char *vars[])
                         }
 			c++;
 			break;
+		case S_URINGOP:
+			if (!optarg) {
+				fprintf(stderr,
+					"Argument is required for %s\n",
+					vars[c]);
+				retval = -1;
+				break;
+			}
+			if (isdigit(optarg[0])) {
+				errno = 0;
+				event_uringop = (int)strtoul(optarg, NULL, 10);
+				if (errno) {
+					fprintf(stderr,
+			"Uring operation numeric conversion error (%s) for %s\n",
+						strerror(errno), optarg);
+					retval = -1;
+				}
+			} else {
+				event_uringop = audit_name_to_uringop(optarg);
+				if (event_uringop == -1) {
+					fprintf(stderr,
+						"Uring operation %s not found\n",
+						optarg);
+					retval = -1;
+				}
+			}
+			c++;
+			break;
 		case S_CONTEXT:
 			if (!optarg) {
 				fprintf(stderr, 
diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c
index 39fb7cf51be0..4c6b3c954178 100644
--- a/src/ausearch-parse.c
+++ b/src/ausearch-parse.c
@@ -46,6 +46,7 @@ static const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 };
 
 static int parse_task_info(lnode *n, search_items *s);
 static int parse_syscall(lnode *n, search_items *s);
+static int parse_uringop(lnode *n, search_items *s);
 static int parse_dir(const lnode *n, search_items *s);
 static int common_path_parser(search_items *s, char *path);
 static int avc_parse_path(const lnode *n, search_items *s);
@@ -94,6 +95,9 @@ int extract_search_items(llist *l)
 			case AUDIT_SYSCALL:
 				ret = parse_syscall(n, s);
 				break;
+			case AUDIT_URINGOP:
+				ret = parse_uringop(n, s);
+				break;
 			case AUDIT_CWD:
 				ret = parse_dir(n, s);
 				break;
@@ -384,7 +388,7 @@ try_again:
 		*term = ' ';
 	}
 
-	if (event_terminal) {
+	if (event_terminal && !s->uringop) {
 		// dont do this search unless needed
 		str = strstr(term, "tty=");
 		if (str) {
@@ -416,7 +420,7 @@ try_again:
 		}
 	}
 
-	if (event_comm) {
+	if (event_comm && !s->uringop) {
 		// dont do this search unless needed
 		str = strstr(term, "comm=");
 		if (str) {
@@ -439,7 +443,7 @@ try_again:
 		} else
 			return 38;
 	}
-	if (event_exe) {
+	if (event_exe && !s->uringop) {
 		// dont do this search unless needed
 		str = strstr(n->message, "exe=");
 		if (str) {
@@ -480,7 +484,7 @@ try_again:
 		}
 	}
 	// success
-	if (event_success != S_UNSET) {
+	if (event_success != S_UNSET && !s->uringop) {
 		if (term == NULL)
 			term = n->message;
 		str = strstr(term, "res=");
@@ -602,6 +606,117 @@ static int parse_syscall(lnode *n, search_items *s)
 		return 13;
 	*term = ' ';
 
+	ret = parse_task_info(n, s);
+	if (ret)
+		return ret;
+
+	if (event_key) {
+		str = strstr(term, "key=");
+		if (str) {
+			if (!s->key) {
+				//create
+				s->key = malloc(sizeof(slist));
+				if (s->key == NULL)
+					return 43;
+				slist_create(s->key);
+			}
+			str += 4;
+			if (*str == '"') {
+				str++;
+				term = strchr(str, '"');
+				if (term == NULL)
+					return 44;
+				*term = 0;
+				if (s->key) {
+					// append
+					snode sn;
+					sn.str = strdup(str);
+					sn.key = NULL;
+					sn.hits = 1;
+					slist_append(s->key, &sn);
+				}
+				*term = '"';
+			} else {
+				if (s->key) {
+					char *saved;
+					char *keyptr = unescape(str);
+					if (keyptr == NULL)
+						return 45;
+					char *kptr = strtok_r(keyptr,
+							key_sep, &saved);
+					while (kptr) {
+						snode sn;
+						// append
+						sn.str = strdup(kptr);
+						sn.key = NULL;
+						sn.hits = 1;
+						slist_append(s->key, &sn);
+						kptr = strtok_r(NULL,
+							key_sep, &saved);
+					}
+					free(keyptr);
+
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int parse_uringop(lnode *n, search_items *s)
+{
+	char *ptr, *str, *term;
+	extern int event_machine;
+	int ret;
+
+	term = n->message;
+	// get uring_op
+	str = strstr(term, "uring_op=");
+	if (str == NULL)
+		return 4;
+	ptr = str + 9;
+	term = strchr(ptr, ' ');
+	if (term == NULL)
+		return 5;
+	*term = 0;
+	errno = 0;
+	s->uringop = (int)strtoul(ptr, NULL, 10);
+	if (errno)
+		return 6;
+	*term = ' ';
+	// get success
+	if (event_success != S_UNSET) {
+		str = strstr(term, "success=");
+		if (str) { // exit_group does not set success !?!
+			ptr = str + 8;
+			term = strchr(ptr, ' ');
+			if (term == NULL)
+				return 7;
+			*term = 0;
+			if (strcmp(ptr, "yes") == 0)
+				s->success = S_SUCCESS;
+			else
+				s->success = S_FAILED;
+			*term = ' ';
+		}
+	}
+	// get exit
+	if (event_exit_is_set) {
+		str = strstr(term, "exit=");
+		if (str == NULL)
+			return 8;
+		ptr = str + 5;
+		term = strchr(ptr, ' ');
+		if (term == NULL)
+			return 9;
+		*term = 0;
+		errno = 0;
+		s->exit = strtoll(ptr, NULL, 0);
+		if (errno)
+			return 10;
+		s->exit_is_set = 1;
+		*term = ' ';
+	}
 	ret = parse_task_info(n, s);
 	if (ret)
 		return ret;
diff --git a/src/ausearch-report.c b/src/ausearch-report.c
index 9f91f9c864e0..733852e5c9e3 100644
--- a/src/ausearch-report.c
+++ b/src/ausearch-report.c
@@ -52,6 +52,7 @@ extern time_t lol_get_eoe_timeout(void);
 /* The machine based on elf type */
 static unsigned long machine = -1;
 static int cur_syscall = -1;
+static int cur_uringop = -1;
 
 /* The first syscall argument */
 static unsigned long long a0, a1;
@@ -185,6 +186,7 @@ static void output_interpreted_record(const lnode *n, const event *e)
 	// Reset these because each record could be different
 	machine = -1;
 	cur_syscall = -1;
+	cur_uringop = -1;
 
 	/* Check and see if we start with a node
  	 * If we do, and there is a space in the line
@@ -368,8 +370,25 @@ static void report_interpret(char *name, char *val, int comma, int rtype)
 			cur_syscall = ival;
 		}
 		id.syscall = cur_syscall;
-	} else
+		id.uringop = 0;
+	} else if (rtype == AUDIT_URINGOP) {
+		if (cur_uringop < 0 && *name == 'u' &&
+				strcmp(name, "uringop") == 0) {
+			unsigned long ival;
+			errno = 0;
+			ival = strtoul(val, NULL, 10);
+			if (errno) {
+				printf("uring op conversion error(%s) ", val);
+				return;
+			}
+			cur_uringop = ival;
+		}
+		id.uringop = cur_uringop;
 		id.syscall = 0;
+	} else {
+		id.syscall = 0;
+		id.uringop = 0;
+	}
 	id.machine = machine;
 	id.a0 = a0;
 	id.a1 = a1;
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 6/7] add aureport --uringop option
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
                   ` (4 preceding siblings ...)
  2021-10-28 19:59 ` [PATCH v3 5/7] add ausearch --uringop option Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  2021-10-28 19:59 ` [PATCH v3 7/7] add iouring support to the normalizer Richard Guy Briggs
  6 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 docs/aureport.8        |  3 +++
 src/aureport-options.c | 19 ++++++++++++++++++-
 src/aureport-options.h |  2 +-
 src/aureport-output.c  | 37 +++++++++++++++++++++++++++++++++++++
 src/aureport-scan.c    | 26 ++++++++++++++++++++++++++
 src/aureport-scan.h    |  2 ++
 src/aureport.c         |  3 ++-
 7 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/docs/aureport.8 b/docs/aureport.8
index c4ceb09e2f7d..187fd495bea7 100644
--- a/docs/aureport.8
+++ b/docs/aureport.8
@@ -90,6 +90,9 @@ Report about responses to anomaly events
 .BR \-s ,\  \-\-syscall
 Report about syscalls
 .TP
+.BR \-U ,\  \-\-uringop
+Report about uringops
+.TP
 .B \-\-success
 Only select successful events for processing in the reports. The default is both success and failed events.
 .TP
diff --git a/src/aureport-options.c b/src/aureport-options.c
index 93621e250630..b8ab55192d08 100644
--- a/src/aureport-options.c
+++ b/src/aureport-options.c
@@ -83,7 +83,7 @@ struct nv_pair {
 
 enum {  R_INFILE, R_TIME_END, R_TIME_START, R_VERSION, R_SUMMARY, R_LOG_TIMES,
 	R_CONFIGS, R_LOGINS, R_USERS, R_TERMINALS, R_HOSTS, R_EXES, R_FILES,
-	R_AVCS, R_SYSCALLS, R_PIDS, R_EVENTS, R_ACCT_MODS,  
+	R_AVCS, R_SYSCALLS, R_URINGOPS, R_PIDS, R_EVENTS, R_ACCT_MODS,
 	R_INTERPRET, R_HELP, R_ANOMALY, R_RESPONSE, R_SUMMARY_DET, R_CRYPTO,
 	R_MAC, R_FAILED, R_SUCCESS, R_ADD, R_DEL, R_AUTH, R_NODE, R_IN_LOGS,
 	R_KEYS, R_TTY, R_NO_CONFIG, R_COMM, R_VIRT, R_INTEG, R_ESCAPE,
@@ -148,6 +148,8 @@ static struct nv_pair optiontab[] = {
 	{ R_TIME_START, "-ts" },
 	{ R_TTY, "--tty" },
 	{ R_TIME_START, "--start" },
+	{ R_URINGOPS, "-U" },
+	{ R_URINGOPS, "--uringop" },
 	{ R_USERS, "-u" },
 	{ R_USERS, "--user" },
 	{ R_VERSION, "-v" },
@@ -206,6 +208,7 @@ static void usage(void)
 	"\t-tm,--terminal\t\t\tTerMinal name report\n"
 	"\t-ts,--start [start date] [start time]\tstarting data & time for reports\n"
 	"\t--tty\t\t\t\tReport about tty keystrokes\n"
+	"\t-U,--uringop\t\t\tUring op report\n"
 	"\t-u,--user\t\t\tUser name report\n"
 	"\t-v,--version\t\t\tVersion\n"
 	"\t--virt\t\t\t\tVirtualization report\n"
@@ -485,6 +488,20 @@ int check_params(int count, char *vars[])
 				}
 			}
 			break;
+		case R_URINGOPS:
+			if (set_report(RPT_URINGOP))
+				retval = -1;
+			else {
+				if (!optarg) {
+					set_detail(D_DETAILED);
+					event_comm = dummy;
+					event_loginuid = 1;
+					event_tauid = dummy;
+				} else {
+					UNIMPLEMENTED;
+				}
+			}
+			break;
 		case R_USERS:
 			if (set_report(RPT_USER))
 				retval = -1;
diff --git a/src/aureport-options.h b/src/aureport-options.h
index a559f64546be..5d9ac2ba5dbf 100644
--- a/src/aureport-options.h
+++ b/src/aureport-options.h
@@ -36,7 +36,7 @@ typedef enum { RPT_UNSET, RPT_TIME, RPT_SUMMARY, RPT_AVC, RPT_MAC,
 	RPT_ACCT_MOD, RPT_PID, RPT_SYSCALL, RPT_TERM, RPT_USER,
 	RPT_EXE, RPT_ANOMALY, RPT_RESPONSE, RPT_CRYPTO, 
 	RPT_AUTH, RPT_KEY, RPT_TTY, RPT_COMM, RPT_VIRT,
-	RPT_INTEG } report_type_t;
+	RPT_INTEG, RPT_URINGOP } report_type_t;
 
 typedef enum { D_UNSET, D_SUM, D_DETAILED, D_SPECIFIC } report_det_t;
 
diff --git a/src/aureport-output.c b/src/aureport-output.c
index a635d536f8b3..7e92c5fab1a5 100644
--- a/src/aureport-output.c
+++ b/src/aureport-output.c
@@ -160,6 +160,12 @@ static void print_title_summary(void)
 			printf("total  terminal\n");
 			printf("===============================\n");
 			break;
+		case RPT_URINGOP:
+			printf("IO URING ops Summary Report\n");
+			printf("==========================\n");
+			printf("total  uringop\n");
+			printf("==========================\n");
+			break;
 		case RPT_USER:
 			printf("User Summary Report\n");
 			printf("===========================\n");
@@ -338,6 +344,21 @@ static void print_title_detailed(void)
 				printf("========================\n");
 			}
 			break;
+		case RPT_URINGOP:
+			if (report_detail == D_DETAILED) {
+				printf("URING op Report\n");
+				printf(
+				  "=======================================\n");
+				printf(
+				  //"# date time uringop pid comm auid event\n");
+				  "# date time syscall pid auid event\n");
+				printf(
+				  "=======================================\n");
+			} else {
+				printf("Specific Uring op Report\n");
+				printf("=======================\n");
+			}
+			break;
 		case RPT_USER:
 			if (report_detail == D_DETAILED) {
 				printf("User ID Report\n");
@@ -636,6 +657,17 @@ void print_per_event_item(llist *l)
 				sizeof(name)), 0);
 			printf(" %lu\n", l->e.serial);
 			break;
+		case RPT_URINGOP:	// report_detail == D_DETAILED
+			// uringop, pid, comm, who, event
+			// uringop, pid, who, event
+			printf("%s %u ", aulookup_uringop(l,buf,sizeof(buf)),
+				l->s.pid);
+			//safe_print_string(l->s.comm ? l->s.comm : "?", 0);
+			//putchar(' ');
+			safe_print_string(aulookup_uid(l->s.loginuid, name,
+				sizeof(name)), 0);
+			printf(" %lu\n", l->e.serial);
+			break;
 		case RPT_USER:	// report_detail == D_DETAILED
 			// who, terminal, host, exe, event
 			safe_print_string(aulookup_uid(l->s.loginuid, name,
@@ -807,6 +839,10 @@ void print_wrap_up(void)
 			slist_sort_by_hits(&sd.terms);
 			do_string_summary_output(&sd.terms);
 			break;
+		case RPT_URINGOP:
+			slist_sort_by_hits(&sd.uringop_list);
+			do_syscall_summary_output(&sd.uringop_list);
+			break;
 		case RPT_USER:
 			slist_sort_by_hits(&sd.users);
 			do_user_summary_output(&sd.users);
@@ -918,6 +954,7 @@ static void do_summary_output(void)
 	printf("Number of AVC's: %lu\n", sd.avcs);
 	printf("Number of MAC events: %lu\n", sd.mac);
 	printf("Number of failed syscalls: %lu\n", sd.failed_syscalls);
+	printf("Number of failed uring ops: %lu\n", sd.failed_uringops);
 	printf("Number of anomaly events: %lu\n", sd.anomalies);
 	printf("Number of responses to anomaly events: %lu\n", sd.responses);
 	printf("Number of crypto events: %lu\n", sd.crypto);
diff --git a/src/aureport-scan.c b/src/aureport-scan.c
index 4095e8686a05..5b2d81047e1d 100644
--- a/src/aureport-scan.c
+++ b/src/aureport-scan.c
@@ -53,6 +53,7 @@ void reset_counters(void)
 	sd.avcs = 0UL;
 	sd.mac = 0UL;
 	sd.failed_syscalls = 0UL;
+	sd.failed_uringops = 0UL;
 	sd.anomalies = 0UL;
 	sd.responses = 0UL;
 	sd.virt = 0UL;
@@ -67,6 +68,7 @@ void reset_counters(void)
 	slist_create(&sd.keys);
 	ilist_create(&sd.pids);
 	slist_create(&sd.sys_list);
+	slist_create(&sd.uringop_list);
 	ilist_create(&sd.anom_list);
 	ilist_create(&sd.mac_list);
 	ilist_create(&sd.resp_list);
@@ -89,6 +91,7 @@ void destroy_counters(void)
 	sd.avcs = 0UL;
 	sd.mac = 0UL;
 	sd.failed_syscalls = 0UL;
+	sd.failed_uringops = 0UL;
 	sd.anomalies = 0UL;
 	sd.responses = 0UL;
 	sd.virt = 0UL;
@@ -103,6 +106,7 @@ void destroy_counters(void)
 	slist_clear(&sd.keys);
 	ilist_clear(&sd.pids);
 	slist_clear(&sd.sys_list);
+	slist_clear(&sd.uringop_list);
 	ilist_clear(&sd.anom_list);
 	ilist_create(&sd.mac_list);
 	ilist_clear(&sd.resp_list);
@@ -430,6 +434,13 @@ static int per_event_summary(llist *l)
 			if (l->s.terminal)
 				slist_add_if_uniq(&sd.terms, l->s.terminal);
 			break;
+		case RPT_URINGOP:
+			if (l->s.uringop > 0) {
+				char tmp[32];
+				aulookup_uringop(l, tmp, 32);
+				slist_add_if_uniq(&sd.uringop_list, tmp);
+			}
+			break;
 		case RPT_USER:
 			if (l->s.loginuid != -2) {
 				char tmp[32];
@@ -688,6 +699,17 @@ static int per_event_detailed(llist *l)
 				UNIMPLEMENTED;
 			}
 			break;
+		case RPT_URINGOP:
+			list_first(l);
+			if (report_detail == D_DETAILED) {
+				if (l->s.uringop) {
+					print_per_event_item(l);
+					rc = 1;
+				}
+			} else { //  specific uring op report
+				UNIMPLEMENTED;
+			}
+			break;
 		case RPT_USER:
 			list_first(l);
 			if (report_detail == D_DETAILED) {
@@ -938,6 +960,10 @@ static void do_summary_total(llist *l)
 	if (l->s.success == S_FAILED && l->s.syscall > 0)
 		sd.failed_syscalls++;
 
+	// add failed uring ops
+	if (l->s.success == S_FAILED && l->s.uringop > 0)
+		sd.failed_uringops++;
+
 	// add pids
 	if (l->s.pid != -1) {
 		ilist_add_if_uniq(&sd.pids, l->s.pid, 0);
diff --git a/src/aureport-scan.h b/src/aureport-scan.h
index 76cc81874874..b974bc4d70ab 100644
--- a/src/aureport-scan.h
+++ b/src/aureport-scan.h
@@ -38,6 +38,7 @@ typedef struct sdata {
 	slist keys;
 	ilist pids;
 	slist sys_list;
+	slist uringop_list;
 	ilist anom_list;
 	ilist resp_list;
 	ilist mac_list;
@@ -55,6 +56,7 @@ typedef struct sdata {
 	unsigned long avcs;
 	unsigned long mac;
 	unsigned long failed_syscalls;
+	unsigned long failed_uringops;
 	unsigned long anomalies;
 	unsigned long responses;
 	unsigned long virt;
diff --git a/src/aureport.c b/src/aureport.c
index 22618f02346a..48d69b493f80 100644
--- a/src/aureport.c
+++ b/src/aureport.c
@@ -236,7 +236,8 @@ static void process_event(llist *entries)
 	if (scan(entries)) {
 		// If its a single event or SYSCALL load interpretations
 		if ((entries->cnt == 1) || 
-				(entries->head->type == AUDIT_SYSCALL))
+		    (entries->head->type == AUDIT_SYSCALL) ||
+		    (entries->head->type == AUDIT_URINGOP))
 			_auparse_load_interpretations(entries->head->interp);
 		// This is the per entry action item
 		if (per_event_processing(entries))
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 7/7] add iouring support to the normalizer
  2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
                   ` (5 preceding siblings ...)
  2021-10-28 19:59 ` [PATCH v3 6/7] add aureport " Richard Guy Briggs
@ 2021-10-28 19:59 ` Richard Guy Briggs
  6 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-10-28 19:59 UTC (permalink / raw)
  To: Linux-Audit Mailing List; +Cc: io-uring, Steve Grubb, Richard Guy Briggs

Signed-off-by: Richard Guy Briggs <[email protected]>
---
 auparse/normalize.c            | 1 +
 auparse/normalize_record_map.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/auparse/normalize.c b/auparse/normalize.c
index 0ccabc5e397e..55943263f4a4 100644
--- a/auparse/normalize.c
+++ b/auparse/normalize.c
@@ -1037,6 +1037,7 @@ static const char *normalize_determine_evkind(int type)
 		case AUDIT_SOCKADDR ... AUDIT_MQ_GETSETATTR:
 		case AUDIT_FD_PAIR ... AUDIT_OBJ_PID:
 		case AUDIT_BPRM_FCAPS ... AUDIT_NETFILTER_PKT:
+		case AUDIT_URINGOP:
 			kind = NORM_EVTYPE_AUDIT_RULE;
 			break;
 		case AUDIT_FANOTIFY:
diff --git a/auparse/normalize_record_map.h b/auparse/normalize_record_map.h
index 395eac05e0e3..75f555f2b612 100644
--- a/auparse/normalize_record_map.h
+++ b/auparse/normalize_record_map.h
@@ -87,6 +87,7 @@ _S(AUDIT_FANOTIFY, "accessed-policy-controlled-file")
 //_S(AUDIT_BPF, "")
 //_S(AUDIT_EVENT_LISTENER, "")
 //_S(AUDIT_OPENAT2, "")
+_S(AUDIT_URINGOP, "io_uring-operation")
 _S(AUDIT_AVC, "accessed-mac-policy-controlled-object")
 _S(AUDIT_MAC_POLICY_LOAD, "loaded-selinux-policy")
 _S(AUDIT_MAC_STATUS, "changed-selinux-enforcement-to")
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type
  2021-10-28 19:59 ` [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type Richard Guy Briggs
@ 2021-10-28 21:19   ` Steve Grubb
  0 siblings, 0 replies; 13+ messages in thread
From: Steve Grubb @ 2021-10-28 21:19 UTC (permalink / raw)
  To: Linux-Audit Mailing List, Richard Guy Briggs; +Cc: io-uring

On Thursday, October 28, 2021 3:59:33 PM EDT Richard Guy Briggs wrote:
> Kernel support to audit io_uring operations was added with commit
> 5bd2182d58e9 ("audit,io_uring,io-wq: add some basic audit support to
> io_uring").  Add basic support to recognize the "AUDIT_URINGOP" record.

Thanks! Applied.

-Steve



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/7] add support for the uring filter list
  2021-10-28 19:59 ` [PATCH v3 2/7] add support for the uring filter list Richard Guy Briggs
@ 2021-10-29 18:39   ` Steve Grubb
  2021-11-01 15:05     ` Richard Guy Briggs
  0 siblings, 1 reply; 13+ messages in thread
From: Steve Grubb @ 2021-10-29 18:39 UTC (permalink / raw)
  To: Linux-Audit Mailing List, Richard Guy Briggs; +Cc: io-uring

On Thursday, October 28, 2021 3:59:34 PM EDT Richard Guy Briggs wrote:
> 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.

Might have been good to show what the resulting auditctl command looks like. 
I think it would be:

auditctl -a always,io_ring  -U  open -F uid!=0 -F key=io_ring

But I wonder, why the choice of  -U rather than -S? That would make 
remembering the syntax easier.

auditctl -a always,io_ring  -S  open -F uid!=0 -F key=io_ring


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


<snip a whole lot of documentation> 


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

This is in the session_id code. Looking at the example audit event:

https://listman.redhat.com/archives/linux-audit/2021-September/msg00058.html

session_id is not in the record.


>  				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:

^^^ Can you audit by devmajor, devminor, or inode in io_ring?

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

Why are we creating commented out function calls? It seems like this belongs 
in another patch and not here. But let's save everyone some iterations and 
overlook that.


Review complete...

-Steve



> +#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");
>  			}





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/7] add support for the uring filter list
  2021-10-29 18:39   ` Steve Grubb
@ 2021-11-01 15:05     ` Richard Guy Briggs
  2021-11-01 15:58       ` Steve Grubb
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Guy Briggs @ 2021-11-01 15:05 UTC (permalink / raw)
  To: Steve Grubb; +Cc: Linux-Audit Mailing List, io-uring

On 2021-10-29 14:39, Steve Grubb wrote:
> On Thursday, October 28, 2021 3:59:34 PM EDT Richard Guy Briggs wrote:
> > 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.
> 
> Might have been good to show what the resulting auditctl command looks like. 
> I think it would be:
> 
> auditctl -a always,io_ring  -U  open -F uid!=0 -F key=io_ring
> 
> But I wonder, why the choice of  -U rather than -S? That would make 
> remembering the syntax easier.
> 
> auditctl -a always,io_ring  -S  open -F uid!=0 -F key=io_ring

Well, I keep seeing the same what I assume is a typo in your
communications about io_uring where the "u" is missing, which might help
trigger your memory about the syntax.

The io_uring operations name list is different than the syscall list, so
it needs to use a different lookup table.

Have I misunderstood something?

> > 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(-)
> 
> 
> <snip a whole lot of documentation> 
> 
> 
> > 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)
> 
> This is in the session_id code. Looking at the example audit event:
> 
> https://listman.redhat.com/archives/linux-audit/2021-September/msg00058.html
> 
> session_id is not in the record.

Fair enough.  It can be re-added if we are able to reliably report it.

> >  				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:
> 
> ^^^ Can you audit by devmajor, devminor, or inode in io_ring?

Should be able to monitor files.  The old "-w" syntax is not supported
but path= and dir= should be.

> >  		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);
> 
> Why are we creating commented out function calls? It seems like this belongs 
> in another patch and not here. But let's save everyone some iterations and 
> overlook that.

That's a placeholder for the following patch that could be squashed in
with this one, or it might belong in another if things are re-ordered.

> Review complete...
> 
> -Steve
> 
> > +#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");
> >  			}
> 
> 
> 
> 

- RGB

--
Richard Guy Briggs <[email protected]>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/7] add support for the uring filter list
  2021-11-01 15:05     ` Richard Guy Briggs
@ 2021-11-01 15:58       ` Steve Grubb
  2021-11-02 16:32         ` Richard Guy Briggs
  0 siblings, 1 reply; 13+ messages in thread
From: Steve Grubb @ 2021-11-01 15:58 UTC (permalink / raw)
  To: Richard Guy Briggs; +Cc: Linux-Audit Mailing List, io-uring

Hello Richard,

On Monday, November 1, 2021 11:05:49 AM EDT Richard Guy Briggs wrote:
> On 2021-10-29 14:39, Steve Grubb wrote:
> > On Thursday, October 28, 2021 3:59:34 PM EDT Richard Guy Briggs wrote:
> > > 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.
> > 
> > Might have been good to show what the resulting auditctl command looks
> > like. I think it would be:
> > 
> > auditctl -a always,io_uring  -U  open -F uid!=0 -F key=io_uring
> > 
> > But I wonder, why the choice of  -U rather than -S? That would make
> > remembering the syntax easier.
> > 
> > auditctl -a always,io_uring  -S  open -F uid!=0 -F key=io_uring
> 
> Well, I keep seeing the same what I assume is a typo in your
> communications about io_uring where the "u" is missing, which might help
> trigger your memory about the syntax.

Yeah, but I'm thinking that we can abstract that technicality away and keep 
the syntax the same.

> The io_uring operations name list is different than the syscall list, so
> it needs to use a different lookup table.

Right. So, if you choose an operation that is not supported, you get an 
error. But to help people know what is supported, we can add the lookup to 
ausyscall where  --io_uring could direct it to the right lookup table.

> Have I misunderstood something?

No, but I'm thinking of aesthetics and usability. You already have to specify 
a filter. We don't really need to have completely different syntax in 
addition. Especially since the operations map to the equivalent of a syscall.
 

> > > 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(-)
> > 
> > <snip a whole lot of documentation>
> > 
> > > 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)
> > 
> > This is in the session_id code. Looking at the example audit event:
> > 
> > https://listman.redhat.com/archives/linux-audit/2021-September/msg00058.h
> > tml
> > 
> > session_id is not in the record.
> 
> Fair enough.  It can be re-added if we are able to reliably report it.

Thanks.

> > > 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:
> > ^^^ Can you audit by devmajor, devminor, or inode in io_ring?
> 
> Should be able to monitor files.  The old "-w" syntax is not supported
> but path= and dir= should be.

But that's not what this is. These is for:
 -F dev_major=
 -F dev_minor=
 -F inode=

It dates back to before watches were possible. In any event, this is being 
allowed when I suspect it shouldn't.

-Steve




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/7] add support for the uring filter list
  2021-11-01 15:58       ` Steve Grubb
@ 2021-11-02 16:32         ` Richard Guy Briggs
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Guy Briggs @ 2021-11-02 16:32 UTC (permalink / raw)
  To: Steve Grubb; +Cc: Linux-Audit Mailing List, io-uring, Paul Moore

On 2021-11-01 11:58, Steve Grubb wrote:
> Hello Richard,
> 
> On Monday, November 1, 2021 11:05:49 AM EDT Richard Guy Briggs wrote:
> > On 2021-10-29 14:39, Steve Grubb wrote:
> > > On Thursday, October 28, 2021 3:59:34 PM EDT Richard Guy Briggs wrote:
> > > > 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.
> > > 
> > > Might have been good to show what the resulting auditctl command looks
> > > like. I think it would be:
> > > 
> > > auditctl -a always,io_uring  -U  open -F uid!=0 -F key=io_uring
> > > 
> > > But I wonder, why the choice of  -U rather than -S? That would make
> > > remembering the syntax easier.
> > > 
> > > auditctl -a always,io_uring  -S  open -F uid!=0 -F key=io_uring
> > 
> > Well, I keep seeing the same what I assume is a typo in your
> > communications about io_uring where the "u" is missing, which might help
> > trigger your memory about the syntax.
> 
> Yeah, but I'm thinking that we can abstract that technicality away and keep 
> the syntax the same.

They do use the same mechanism to get the data into the kernel, but this
is not user-visible.

> > The io_uring operations name list is different than the syscall list, so
> > it needs to use a different lookup table.
> 
> Right. So, if you choose an operation that is not supported, you get an 
> error. But to help people know what is supported, we can add the lookup to 
> ausyscall where  --io_uring could direct it to the right lookup table.
> 
> > Have I misunderstood something?
> 
> No, but I'm thinking of aesthetics and usability. You already have to specify 
> a filter. We don't really need to have completely different syntax in 
> addition. Especially since the operations map to the equivalent of a syscall.

In terms of usibility, it is a different lookup table and the operations
don't map exactly to each other.  I'd *expect* to use a different
command line option to specify io_uring ops than I did for syscalls
since they are not the same since if I changed a rule text from one list
to another, I'd also need to change the list of ops and which list they
came from.  I'd want it to throw an error if I used the wrong argument
type.

> > > > 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(-)
> > > 
> > > <snip a whole lot of documentation>
> > > 
> > > > 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)
> > > 
> > > This is in the session_id code. Looking at the example audit event:
> > > 
> > > https://listman.redhat.com/archives/linux-audit/2021-September/msg00058.h
> > > tml
> > > 
> > > session_id is not in the record.
> > 
> > Fair enough.  It can be re-added if we are able to reliably report it.
> 
> Thanks.
> 
> > > > 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:
> > > ^^^ Can you audit by devmajor, devminor, or inode in io_ring?
> > 
> > Should be able to monitor files.  The old "-w" syntax is not supported
> > but path= and dir= should be.
> 
> But that's not what this is. These is for:
>  -F dev_major=
>  -F dev_minor=
>  -F inode=
> 
> It dates back to before watches were possible. In any event, this is being 
> allowed when I suspect it shouldn't.

Why shouldn't it be allowed?

> -Steve

- RGB

--
Richard Guy Briggs <[email protected]>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-11-02 16:36 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-10-28 19:59 [PATCH v3 0/7] Add uringop support Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 1/7] add basic support for the AUDIT_URINGOP record type Richard Guy Briggs
2021-10-28 21:19   ` Steve Grubb
2021-10-28 19:59 ` [PATCH v3 2/7] add support for the uring filter list Richard Guy Briggs
2021-10-29 18:39   ` Steve Grubb
2021-11-01 15:05     ` Richard Guy Briggs
2021-11-01 15:58       ` Steve Grubb
2021-11-02 16:32         ` Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 3/7] add support for uringop names Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 4/7] add field support for the AUDIT_URINGOP record type Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 5/7] add ausearch --uringop option Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 6/7] add aureport " Richard Guy Briggs
2021-10-28 19:59 ` [PATCH v3 7/7] add iouring support to the normalizer Richard Guy Briggs

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox