io-uring.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
@ 2021-08-11 20:48 Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 1/9] audit: prepare audit_context for use in calling contexts beyond syscalls Paul Moore
                   ` (9 more replies)
  0 siblings, 10 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

Draft #2 of the patchset which brings auditing and proper LSM access
controls to the io_uring subsystem.  The original patchset was posted
in late May and can be found via lore using the link below:

https://lore.kernel.org/linux-security-module/162163367115.8379.8459012634106035341.stgit@sifl/

This draft should incorporate all of the feedback from the original
posting as well as a few smaller things I noticed while playing
further with the code.  The big change is of course the selective
auditing in the io_uring op servicing, but that has already been
discussed quite a bit in the original thread so I won't go into
detail here; the important part is that we found a way to move
forward and this draft captures that.  For those of you looking to
play with these patches, they are based on Linus' v5.14-rc5 tag and
on my test system they boot and appear to function without problem;
they pass the selinux-testsuite and audit-testsuite and I have not
noticed any regressions in the normal use of the system.  If you want
to get a copy of these patches straight from git you can use the
"working-io_uring" branch in the repo below:

git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git

Beyond the existing test suite tests mentioned above, I've cobbled
together some very basic, very crude tests to exercise some of the
things I care about from a LSM/audit perspective.  These tests are
pretty awful (I'm not kidding), but they might be helpful for the
other LSM/audit developers who want to test things:

https://drop.paul-moore.com/90.kUgq

There are currently two tests: 'iouring.2' and 'iouring.3';
'iouring.1' was lost in a misguided and overzealous 'rm' command.
The first test is standalone and basically tests the SQPOLL
functionality while the second tests sharing io_urings across process
boundaries and the credential/personality sharing mechanism.  The
console output of both tests isn't particularly useful, the more
interesting bits are in the audit and LSM specific logs.  The
'iouring.2' command requires no special arguments to run but the
'iouring.3' test is split into a "server" and "client"; the server
should be run without argument:

  % ./iouring.3s
  >>> server started, pid = 11678
  >>> memfd created, fd = 3
  >>> io_uring created; fd = 5, creds = 1

... while the client should be run with two arguments: the first is
the PID of the server process, the second is the "memfd" fd number:

  % ./iouring.3c 11678 3
  >>> client started, server_pid = 11678 server_memfd = 3
  >>> io_urings = 5 (server) / 5 (client)
  >>> io_uring ops using creds = 1
  >>> async op result: 36
  >>> async op result: 36
  >>> async op result: 36
  >>> async op result: 36
  >>> START file contents
  What is this life if, full of care,
  we have no time to stand and stare.
  >>> END file contents

The tests were hacked together from various sources online,
attribution and links to additional info can be found in the test
sources, but I expect these tests to die a fiery death in the not
to distant future as I work to add some proper tests to the SELinux
and audit test suites.

As I believe these patches should spend a full -rcX cycle in
linux-next, my current plan is to continue to solicit feedback on
these patches while they undergo additional testing (next up is
verification of the audit filter code for io_uring).  Assuming no
critical issues are found on the mailing lists or during testing, I
will post a proper patchset later with the idea of merging it into
selinux/next after the upcoming merge window closes.

Any comments, feedback, etc. are welcome.

---

Casey Schaufler (1):
      Smack: Brutalist io_uring support with debug

Paul Moore (8):
      audit: prepare audit_context for use in calling contexts beyond
             syscalls
      audit,io_uring,io-wq: add some basic audit support to io_uring
      audit: dev/test patch to force io_uring auditing
      audit: add filtering for io_uring records
      fs: add anon_inode_getfile_secure() similar to
          anon_inode_getfd_secure()
      io_uring: convert io_uring to the secure anon inode interface
      lsm,io_uring: add LSM hooks to io_uring
      selinux: add support for the io_uring access controls


 fs/anon_inodes.c                    |  29 ++
 fs/io-wq.c                          |   4 +
 fs/io_uring.c                       |  69 +++-
 include/linux/anon_inodes.h         |   4 +
 include/linux/audit.h               |  26 ++
 include/linux/lsm_hook_defs.h       |   5 +
 include/linux/lsm_hooks.h           |  13 +
 include/linux/security.h            |  16 +
 include/uapi/linux/audit.h          |   4 +-
 kernel/audit.h                      |   7 +-
 kernel/audit_tree.c                 |   3 +-
 kernel/audit_watch.c                |   3 +-
 kernel/auditfilter.c                |  15 +-
 kernel/auditsc.c                    | 483 +++++++++++++++++++-----
 security/security.c                 |  12 +
 security/selinux/hooks.c            |  34 ++
 security/selinux/include/classmap.h |   2 +
 security/smack/smack_lsm.c          |  64 ++++
 18 files changed, 678 insertions(+), 115 deletions(-)

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

* [RFC PATCH v2 1/9] audit: prepare audit_context for use in calling contexts beyond syscalls
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 2/9] audit,io_uring,io-wq: add some basic audit support to io_uring Paul Moore
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This is a work in progress and should not be merged
anywhere important.  It is almost surely not complete, and while it
probably compiles it likely hasn't been booted and will do terrible
things.  You have been warned.

This patch cleans up some of our audit_context handling by
abstracting out the reset and return code fixup handling to dedicated
functions.  Not only does this help make things easier to read and
inspect, it allows for easier reuse be future patches.  We also
convert the simple audit_context->in_syscall flag into an enum which
can be used to by future patches to indicate a calling context other
than the syscall context.

Thanks to Richard Guy Briggs for review and feedback.

Acked-by: Richard Guy Briggs <rgb@redhat.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- no change
v1:
- initial draft
---
 kernel/audit.h   |    5 +
 kernel/auditsc.c |  256 ++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 167 insertions(+), 94 deletions(-)

diff --git a/kernel/audit.h b/kernel/audit.h
index b565ea16c0a5..268a13a1c983 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -97,7 +97,10 @@ struct audit_proctitle {
 /* The per-task audit context. */
 struct audit_context {
 	int		    dummy;	/* must be the first element */
-	int		    in_syscall;	/* 1 if task is in a syscall */
+	enum {
+		AUDIT_CTX_UNUSED,	/* audit_context is currently unused */
+		AUDIT_CTX_SYSCALL,	/* in use by syscall */
+	} context;
 	enum audit_state    state, current_state;
 	unsigned int	    serial;     /* serial number for record */
 	int		    major;      /* syscall number */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8dd73a64f921..c0383d554e61 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -915,10 +915,80 @@ static inline void audit_free_aux(struct audit_context *context)
 		context->aux = aux->next;
 		kfree(aux);
 	}
+	context->aux = NULL;
 	while ((aux = context->aux_pids)) {
 		context->aux_pids = aux->next;
 		kfree(aux);
 	}
+	context->aux_pids = NULL;
+}
+
+/**
+ * audit_reset_context - reset a audit_context structure
+ * @ctx: the audit_context to reset
+ *
+ * All fields in the audit_context will be reset to an initial state, all
+ * references held by fields will be dropped, and private memory will be
+ * released.  When this function returns the audit_context will be suitable
+ * for reuse, so long as the passed context is not NULL or a dummy context.
+ */
+static void audit_reset_context(struct audit_context *ctx)
+{
+	if (!ctx)
+		return;
+
+	/* if ctx is non-null, reset the "ctx->state" regardless */
+	ctx->context = AUDIT_CTX_UNUSED;
+	if (ctx->dummy)
+		return;
+
+	/*
+	 * NOTE: It shouldn't matter in what order we release the fields, so
+	 *       release them in the order in which they appear in the struct;
+	 *       this gives us some hope of quickly making sure we are
+	 *       resetting the audit_context properly.
+	 *
+	 *       Other things worth mentioning:
+	 *       - we don't reset "dummy"
+	 *       - we don't reset "state", we do reset "current_state"
+	 *       - we preserver "filterkey" if "state" is AUDIT_STATE_RECORD
+	 *       - much of this is likely overkill, but play it safe for now
+	 *       - we really need to work on improving the audit_context struct
+	 */
+
+	ctx->current_state = ctx->state;
+	ctx->serial = 0;
+	ctx->major = 0;
+	ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
+	memset(ctx->argv, 0, sizeof(ctx->argv));
+	ctx->return_code = 0;
+	ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0);
+	ctx->return_valid = AUDITSC_INVALID;
+	audit_free_names(ctx);
+	if (ctx->state != AUDIT_STATE_RECORD) {
+		kfree(ctx->filterkey);
+		ctx->filterkey = NULL;
+	}
+	audit_free_aux(ctx);
+	kfree(ctx->sockaddr);
+	ctx->sockaddr = NULL;
+	ctx->sockaddr_len = 0;
+	ctx->pid = ctx->ppid = 0;
+	ctx->uid = ctx->euid = ctx->suid = ctx->fsuid = KUIDT_INIT(0);
+	ctx->gid = ctx->egid = ctx->sgid = ctx->fsgid = KGIDT_INIT(0);
+	ctx->personality = 0;
+	ctx->arch = 0;
+	ctx->target_pid = 0;
+	ctx->target_auid = ctx->target_uid = KUIDT_INIT(0);
+	ctx->target_sessionid = 0;
+	ctx->target_sid = 0;
+	ctx->target_comm[0] = '\0';
+	unroll_tree_refs(ctx, NULL, 0);
+	WARN_ON(!list_empty(&ctx->killed_trees));
+	ctx->type = 0;
+	audit_free_module(ctx);
+	ctx->fds[0] = -1;
+	audit_proctitle_free(ctx);
 }
 
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -928,6 +998,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
 	context = kzalloc(sizeof(*context), GFP_KERNEL);
 	if (!context)
 		return NULL;
+	context->context = AUDIT_CTX_UNUSED;
 	context->state = state;
 	context->prio = state == AUDIT_STATE_RECORD ? ~0ULL : 0;
 	INIT_LIST_HEAD(&context->killed_trees);
@@ -953,7 +1024,7 @@ int audit_alloc(struct task_struct *tsk)
 	char *key = NULL;
 
 	if (likely(!audit_ever_enabled))
-		return 0; /* Return if not auditing. */
+		return 0;
 
 	state = audit_filter_task(tsk, &key);
 	if (state == AUDIT_STATE_DISABLED) {
@@ -975,14 +1046,10 @@ int audit_alloc(struct task_struct *tsk)
 
 static inline void audit_free_context(struct audit_context *context)
 {
-	audit_free_module(context);
-	audit_free_names(context);
-	unroll_tree_refs(context, NULL, 0);
+	/* resetting is extra work, but it is likely just noise */
+	audit_reset_context(context);
 	free_tree_refs(context);
-	audit_free_aux(context);
 	kfree(context->filterkey);
-	kfree(context->sockaddr);
-	audit_proctitle_free(context);
 	kfree(context);
 }
 
@@ -1489,29 +1556,35 @@ static void audit_log_exit(void)
 
 	context->personality = current->personality;
 
-	ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
-	if (!ab)
-		return;		/* audit_panic has been called */
-	audit_log_format(ab, "arch=%x syscall=%d",
-			 context->arch, context->major);
-	if (context->personality != PER_LINUX)
-		audit_log_format(ab, " per=%lx", context->personality);
-	if (context->return_valid != AUDITSC_INVALID)
-		audit_log_format(ab, " success=%s exit=%ld",
-				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
-				 context->return_code);
-
-	audit_log_format(ab,
-			 " a0=%lx a1=%lx a2=%lx a3=%lx items=%d",
-			 context->argv[0],
-			 context->argv[1],
-			 context->argv[2],
-			 context->argv[3],
-			 context->name_count);
-
-	audit_log_task_info(ab);
-	audit_log_key(ab, context->filterkey);
-	audit_log_end(ab);
+	switch (context->context) {
+	case AUDIT_CTX_SYSCALL:
+		ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
+		if (!ab)
+			return;
+		audit_log_format(ab, "arch=%x syscall=%d",
+				 context->arch, context->major);
+		if (context->personality != PER_LINUX)
+			audit_log_format(ab, " per=%lx", context->personality);
+		if (context->return_valid != AUDITSC_INVALID)
+			audit_log_format(ab, " success=%s exit=%ld",
+					 (context->return_valid == AUDITSC_SUCCESS ?
+					  "yes" : "no"),
+					 context->return_code);
+		audit_log_format(ab,
+				 " a0=%lx a1=%lx a2=%lx a3=%lx items=%d",
+				 context->argv[0],
+				 context->argv[1],
+				 context->argv[2],
+				 context->argv[3],
+				 context->name_count);
+		audit_log_task_info(ab);
+		audit_log_key(ab, context->filterkey);
+		audit_log_end(ab);
+		break;
+	default:
+		BUG();
+		break;
+	}
 
 	for (aux = context->aux; aux; aux = aux->next) {
 
@@ -1602,14 +1675,15 @@ static void audit_log_exit(void)
 		audit_log_name(context, n, NULL, i++, &call_panic);
 	}
 
-	audit_log_proctitle();
+	if (context->context == AUDIT_CTX_SYSCALL)
+		audit_log_proctitle();
 
 	/* Send end of event record to help user space know we are finished */
 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
 	if (ab)
 		audit_log_end(ab);
 	if (call_panic)
-		audit_panic("error converting sid to string");
+		audit_panic("error in audit_log_exit()");
 }
 
 /**
@@ -1625,6 +1699,7 @@ void __audit_free(struct task_struct *tsk)
 	if (!context)
 		return;
 
+	/* this may generate CONFIG_CHANGE records */
 	if (!list_empty(&context->killed_trees))
 		audit_kill_trees(context);
 
@@ -1633,7 +1708,8 @@ void __audit_free(struct task_struct *tsk)
 	 * random task_struct that doesn't doesn't have any meaningful data we
 	 * need to log via audit_log_exit().
 	 */
-	if (tsk == current && !context->dummy && context->in_syscall) {
+	if (tsk == current && !context->dummy &&
+	    context->context == AUDIT_CTX_SYSCALL) {
 		context->return_valid = AUDITSC_INVALID;
 		context->return_code = 0;
 
@@ -1647,6 +1723,34 @@ void __audit_free(struct task_struct *tsk)
 	audit_free_context(context);
 }
 
+/**
+ * audit_return_fixup - fixup the return codes in the audit_context
+ * @ctx: the audit_context
+ * @success: true/false value to indicate if the operation succeeded or not
+ * @code: operation return code
+ *
+ * We need to fixup the return code in the audit logs if the actual return
+ * codes are later going to be fixed by the arch specific signal handlers.
+ */
+static void audit_return_fixup(struct audit_context *ctx,
+			       int success, long code)
+{
+	/*
+	 * This is actually a test for:
+	 * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
+	 * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
+	 *
+	 * but is faster than a bunch of ||
+	 */
+	if (unlikely(code <= -ERESTARTSYS) &&
+	    (code >= -ERESTART_RESTARTBLOCK) &&
+	    (code != -ENOIOCTLCMD))
+		ctx->return_code = -EINTR;
+	else
+		ctx->return_code  = code;
+	ctx->return_valid = (success ? AUDITSC_SUCCESS : AUDITSC_FAILURE);
+}
+
 /**
  * __audit_syscall_entry - fill in an audit record at syscall entry
  * @major: major syscall type (function)
@@ -1672,7 +1776,12 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
 	if (!audit_enabled || !context)
 		return;
 
-	BUG_ON(context->in_syscall || context->name_count);
+	WARN_ON(context->context != AUDIT_CTX_UNUSED);
+	WARN_ON(context->name_count);
+	if (context->context != AUDIT_CTX_UNUSED || context->name_count) {
+		audit_panic("unrecoverable error in audit_syscall_entry()");
+		return;
+	}
 
 	state = context->state;
 	if (state == AUDIT_STATE_DISABLED)
@@ -1691,10 +1800,8 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
 	context->argv[1]    = a2;
 	context->argv[2]    = a3;
 	context->argv[3]    = a4;
-	context->serial     = 0;
-	context->in_syscall = 1;
+	context->context = AUDIT_CTX_SYSCALL;
 	context->current_state  = state;
-	context->ppid       = 0;
 	ktime_get_coarse_real_ts64(&context->ctime);
 }
 
@@ -1711,63 +1818,27 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
  */
 void __audit_syscall_exit(int success, long return_code)
 {
-	struct audit_context *context;
+	struct audit_context *context = audit_context();
 
-	context = audit_context();
-	if (!context)
-		return;
+	if (!context || context->dummy ||
+	    context->context != AUDIT_CTX_SYSCALL)
+		goto out;
 
+	/* this may generate CONFIG_CHANGE records */
 	if (!list_empty(&context->killed_trees))
 		audit_kill_trees(context);
 
-	if (!context->dummy && context->in_syscall) {
-		if (success)
-			context->return_valid = AUDITSC_SUCCESS;
-		else
-			context->return_valid = AUDITSC_FAILURE;
-
-		/*
-		 * we need to fix up the return code in the audit logs if the
-		 * actual return codes are later going to be fixed up by the
-		 * arch specific signal handlers
-		 *
-		 * This is actually a test for:
-		 * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
-		 * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
-		 *
-		 * but is faster than a bunch of ||
-		 */
-		if (unlikely(return_code <= -ERESTARTSYS) &&
-		    (return_code >= -ERESTART_RESTARTBLOCK) &&
-		    (return_code != -ENOIOCTLCMD))
-			context->return_code = -EINTR;
-		else
-			context->return_code  = return_code;
-
-		audit_filter_syscall(current, context);
-		audit_filter_inodes(current, context);
-		if (context->current_state == AUDIT_STATE_RECORD)
-			audit_log_exit();
-	}
+	/* run through both filters to ensure we set the filterkey properly */
+	audit_filter_syscall(current, context);
+	audit_filter_inodes(current, context);
+	if (context->current_state < AUDIT_STATE_RECORD)
+		goto out;
 
-	context->in_syscall = 0;
-	context->prio = context->state == AUDIT_STATE_RECORD ? ~0ULL : 0;
+	audit_return_fixup(context, success, return_code);
+	audit_log_exit();
 
-	audit_free_module(context);
-	audit_free_names(context);
-	unroll_tree_refs(context, NULL, 0);
-	audit_free_aux(context);
-	context->aux = NULL;
-	context->aux_pids = NULL;
-	context->target_pid = 0;
-	context->target_sid = 0;
-	context->sockaddr_len = 0;
-	context->type = 0;
-	context->fds[0] = -1;
-	if (context->state != AUDIT_STATE_RECORD) {
-		kfree(context->filterkey);
-		context->filterkey = NULL;
-	}
+out:
+	audit_reset_context(context);
 }
 
 static inline void handle_one(const struct inode *inode)
@@ -1919,7 +1990,7 @@ void __audit_getname(struct filename *name)
 	struct audit_context *context = audit_context();
 	struct audit_names *n;
 
-	if (!context->in_syscall)
+	if (context->context == AUDIT_CTX_UNUSED)
 		return;
 
 	n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
@@ -1991,7 +2062,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
 	struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
 	int i;
 
-	if (!context->in_syscall)
+	if (context->context == AUDIT_CTX_UNUSED)
 		return;
 
 	rcu_read_lock();
@@ -2109,7 +2180,7 @@ void __audit_inode_child(struct inode *parent,
 	struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
 	int i;
 
-	if (!context->in_syscall)
+	if (context->context == AUDIT_CTX_UNUSED)
 		return;
 
 	rcu_read_lock();
@@ -2208,7 +2279,7 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
 int auditsc_get_stamp(struct audit_context *ctx,
 		       struct timespec64 *t, unsigned int *serial)
 {
-	if (!ctx->in_syscall)
+	if (ctx->context == AUDIT_CTX_UNUSED)
 		return 0;
 	if (!ctx->serial)
 		ctx->serial = audit_serial();
@@ -2706,8 +2777,7 @@ void audit_seccomp_actions_logged(const char *names, const char *old_names,
 struct list_head *audit_killed_trees(void)
 {
 	struct audit_context *ctx = audit_context();
-
-	if (likely(!ctx || !ctx->in_syscall))
+	if (likely(!ctx || ctx->context == AUDIT_CTX_UNUSED))
 		return NULL;
 	return &ctx->killed_trees;
 }


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

* [RFC PATCH v2 2/9] audit,io_uring,io-wq: add some basic audit support to io_uring
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 1/9] audit: prepare audit_context for use in calling contexts beyond syscalls Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 3/9] audit: dev/test patch to force io_uring auditing Paul Moore
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This is a work in progress and should not be merged
anywhere important.  It is almost surely not complete, and while it
probably compiles it likely hasn't been booted and will do terrible
things.  You have been warned.

This patch adds basic auditing to io_uring operations, regardless of
their context.  This is accomplished by allocating audit_context
structures for the io-wq worker and io_uring SQPOLL kernel threads
as well as explicitly auditing the io_uring operations in
io_issue_sqe().  The io_uring operations are audited using a new
AUDIT_URINGOP record, an example is shown below:

  % <TODO - insert AUDIT_URINGOP record example>

Thanks to Richard Guy Briggs for review and feedback.

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- added dummy funcs for audit_uring_{entry,exit}()
- replaced opcode checks in io_issue_sqe() with audit_skip checks
- moved fastpath checks into audit_uring_{entry,exit}()
- audit_log_uring() uses GFP_ATOMIC
- don't record the arch in __audit_uring_entry()
v1:
- initial draft
---
 fs/io-wq.c                 |    4 +
 fs/io_uring.c              |   55 ++++++++++++--
 include/linux/audit.h      |   26 +++++++
 include/uapi/linux/audit.h |    1 
 kernel/audit.h             |    2 +
 kernel/auditsc.c           |  174 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 256 insertions(+), 6 deletions(-)

diff --git a/fs/io-wq.c b/fs/io-wq.c
index 12fc19353bb0..fb928bac0bf2 100644
--- a/fs/io-wq.c
+++ b/fs/io-wq.c
@@ -14,6 +14,7 @@
 #include <linux/rculist_nulls.h>
 #include <linux/cpu.h>
 #include <linux/tracehook.h>
+#include <linux/audit.h>
 
 #include "io-wq.h"
 
@@ -552,6 +553,8 @@ static int io_wqe_worker(void *data)
 	snprintf(buf, sizeof(buf), "iou-wrk-%d", wq->task->pid);
 	set_task_comm(current, buf);
 
+	audit_alloc_kernel(current);
+
 	while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
 		long ret;
 
@@ -586,6 +589,7 @@ static int io_wqe_worker(void *data)
 		io_worker_handle_work(worker);
 	}
 
+	audit_free(current);
 	io_worker_exit(worker);
 	return 0;
 }
diff --git a/fs/io_uring.c b/fs/io_uring.c
index bf548af0426c..b407a6ea1779 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -78,6 +78,7 @@
 #include <linux/task_work.h>
 #include <linux/pagemap.h>
 #include <linux/io_uring.h>
+#include <linux/audit.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/io_uring.h>
@@ -896,6 +897,8 @@ struct io_op_def {
 	unsigned		needs_async_setup : 1;
 	/* should block plug */
 	unsigned		plug : 1;
+	/* skip auditing */
+	unsigned		audit_skip : 1;
 	/* size of async data needed, if any */
 	unsigned short		async_size;
 };
@@ -909,6 +912,7 @@ static const struct io_op_def io_op_defs[] = {
 		.buffer_select		= 1,
 		.needs_async_setup	= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_WRITEV] = {
@@ -918,16 +922,19 @@ static const struct io_op_def io_op_defs[] = {
 		.pollout		= 1,
 		.needs_async_setup	= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_FSYNC] = {
 		.needs_file		= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_READ_FIXED] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
 		.pollin			= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_WRITE_FIXED] = {
@@ -936,15 +943,20 @@ static const struct io_op_def io_op_defs[] = {
 		.unbound_nonreg_file	= 1,
 		.pollout		= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_POLL_ADD] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
+		.audit_skip		= 1,
+	},
+	[IORING_OP_POLL_REMOVE] = {
+		.audit_skip		= 1,
 	},
-	[IORING_OP_POLL_REMOVE] = {},
 	[IORING_OP_SYNC_FILE_RANGE] = {
 		.needs_file		= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_SENDMSG] = {
 		.needs_file		= 1,
@@ -962,18 +974,23 @@ static const struct io_op_def io_op_defs[] = {
 		.async_size		= sizeof(struct io_async_msghdr),
 	},
 	[IORING_OP_TIMEOUT] = {
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_timeout_data),
 	},
 	[IORING_OP_TIMEOUT_REMOVE] = {
 		/* used by timeout updates' prep() */
+		.audit_skip		= 1,
 	},
 	[IORING_OP_ACCEPT] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
 		.pollin			= 1,
 	},
-	[IORING_OP_ASYNC_CANCEL] = {},
+	[IORING_OP_ASYNC_CANCEL] = {
+		.audit_skip		= 1,
+	},
 	[IORING_OP_LINK_TIMEOUT] = {
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_timeout_data),
 	},
 	[IORING_OP_CONNECT] = {
@@ -988,14 +1005,19 @@ static const struct io_op_def io_op_defs[] = {
 	},
 	[IORING_OP_OPENAT] = {},
 	[IORING_OP_CLOSE] = {},
-	[IORING_OP_FILES_UPDATE] = {},
-	[IORING_OP_STATX] = {},
+	[IORING_OP_FILES_UPDATE] = {
+		.audit_skip		= 1,
+	},
+	[IORING_OP_STATX] = {
+		.audit_skip		= 1,
+	},
 	[IORING_OP_READ] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
 		.pollin			= 1,
 		.buffer_select		= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_WRITE] = {
@@ -1003,39 +1025,50 @@ static const struct io_op_def io_op_defs[] = {
 		.unbound_nonreg_file	= 1,
 		.pollout		= 1,
 		.plug			= 1,
+		.audit_skip		= 1,
 		.async_size		= sizeof(struct io_async_rw),
 	},
 	[IORING_OP_FADVISE] = {
 		.needs_file		= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_MADVISE] = {},
 	[IORING_OP_SEND] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
 		.pollout		= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_RECV] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
 		.pollin			= 1,
 		.buffer_select		= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_OPENAT2] = {
 	},
 	[IORING_OP_EPOLL_CTL] = {
 		.unbound_nonreg_file	= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_SPLICE] = {
 		.needs_file		= 1,
 		.hash_reg_file		= 1,
 		.unbound_nonreg_file	= 1,
+		.audit_skip		= 1,
+	},
+	[IORING_OP_PROVIDE_BUFFERS] = {
+		.audit_skip		= 1,
+	},
+	[IORING_OP_REMOVE_BUFFERS] = {
+		.audit_skip		= 1,
 	},
-	[IORING_OP_PROVIDE_BUFFERS] = {},
-	[IORING_OP_REMOVE_BUFFERS] = {},
 	[IORING_OP_TEE] = {
 		.needs_file		= 1,
 		.hash_reg_file		= 1,
 		.unbound_nonreg_file	= 1,
+		.audit_skip		= 1,
 	},
 	[IORING_OP_SHUTDOWN] = {
 		.needs_file		= 1,
@@ -6166,6 +6199,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
 	if ((req->flags & REQ_F_CREDS) && req->creds != current_cred())
 		creds = override_creds(req->creds);
 
+	if (!io_op_defs[req->opcode].audit_skip)
+		audit_uring_entry(req->opcode);
+
 	switch (req->opcode) {
 	case IORING_OP_NOP:
 		ret = io_nop(req, issue_flags);
@@ -6272,6 +6308,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
 		break;
 	}
 
+	if (!io_op_defs[req->opcode].audit_skip)
+		audit_uring_exit(!ret, ret);
+
 	if (creds)
 		revert_creds(creds);
 	if (ret)
@@ -6896,6 +6935,8 @@ static int io_sq_thread(void *data)
 		set_cpus_allowed_ptr(current, cpu_online_mask);
 	current->flags |= PF_NO_SETAFFINITY;
 
+	audit_alloc_kernel(current);
+
 	mutex_lock(&sqd->lock);
 	while (1) {
 		bool cap_entries, sqt_spin = false;
@@ -6961,6 +7002,8 @@ static int io_sq_thread(void *data)
 	io_run_task_work();
 	mutex_unlock(&sqd->lock);
 
+	audit_free(current);
+
 	complete(&sqd->exited);
 	do_exit(0);
 }
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 82b7c1116a85..d656a06dd909 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -286,7 +286,10 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
 /* These are defined in auditsc.c */
 				/* Public API */
 extern int  audit_alloc(struct task_struct *task);
+extern int  audit_alloc_kernel(struct task_struct *task);
 extern void __audit_free(struct task_struct *task);
+extern void __audit_uring_entry(u8 op);
+extern void __audit_uring_exit(int success, long code);
 extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
 				  unsigned long a2, unsigned long a3);
 extern void __audit_syscall_exit(int ret_success, long ret_value);
@@ -323,6 +326,21 @@ static inline void audit_free(struct task_struct *task)
 	if (unlikely(task->audit_context))
 		__audit_free(task);
 }
+static inline void audit_uring_entry(u8 op)
+{
+	/*
+	 * We intentionally check audit_context() before audit_enabled as most
+	 * Linux systems (as of ~2021) rely on systemd which forces audit to
+	 * be enabled regardless of the user's audit configuration.
+	 */
+	if (unlikely(audit_context() && audit_enabled))
+		__audit_uring_entry(op);
+}
+static inline void audit_uring_exit(int success, long code)
+{
+	if (unlikely(!audit_dummy_context()))
+		__audit_uring_exit(success, code);
+}
 static inline void audit_syscall_entry(int major, unsigned long a0,
 				       unsigned long a1, unsigned long a2,
 				       unsigned long a3)
@@ -554,8 +572,16 @@ static inline int audit_alloc(struct task_struct *task)
 {
 	return 0;
 }
+static inline int audit_alloc_kernel(struct task_struct *task)
+{
+	return 0;
+}
 static inline void audit_free(struct task_struct *task)
 { }
+static inline void audit_uring_entry(u8 op)
+{ }
+static inline void audit_uring_exit(int success, long code)
+{ }
 static inline void audit_syscall_entry(int major, unsigned long a0,
 				       unsigned long a1, unsigned long a2,
 				       unsigned long a3)
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index daa481729e9b..a1997697c8b1 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -118,6 +118,7 @@
 #define AUDIT_TIME_ADJNTPVAL	1333	/* NTP value adjustment */
 #define AUDIT_BPF		1334	/* BPF subsystem */
 #define AUDIT_EVENT_LISTENER	1335	/* Task joined multicast read socket */
+#define AUDIT_URINGOP		1336	/* io_uring operation */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
diff --git a/kernel/audit.h b/kernel/audit.h
index 268a13a1c983..834fa18fd6ca 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -100,10 +100,12 @@ struct audit_context {
 	enum {
 		AUDIT_CTX_UNUSED,	/* audit_context is currently unused */
 		AUDIT_CTX_SYSCALL,	/* in use by syscall */
+		AUDIT_CTX_URING,	/* in use by io_uring */
 	} context;
 	enum audit_state    state, current_state;
 	unsigned int	    serial;     /* serial number for record */
 	int		    major;      /* syscall number */
+	int		    uring_op;   /* uring operation */
 	struct timespec64   ctime;      /* time of syscall entry */
 	unsigned long	    argv[4];    /* syscall arguments */
 	long		    return_code;/* syscall return code */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index c0383d554e61..62fb502da3fc 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -959,6 +959,7 @@ static void audit_reset_context(struct audit_context *ctx)
 	ctx->current_state = ctx->state;
 	ctx->serial = 0;
 	ctx->major = 0;
+	ctx->uring_op = 0;
 	ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
 	memset(ctx->argv, 0, sizeof(ctx->argv));
 	ctx->return_code = 0;
@@ -1044,6 +1045,31 @@ int audit_alloc(struct task_struct *tsk)
 	return 0;
 }
 
+/**
+ * audit_alloc_kernel - allocate an audit_context for a kernel task
+ * @tsk: the kernel task
+ *
+ * Similar to the audit_alloc() function, but intended for kernel private
+ * threads.  Returns zero on success, negative values on failure.
+ */
+int audit_alloc_kernel(struct task_struct *tsk)
+{
+	/*
+	 * At the moment we are just going to call into audit_alloc() to
+	 * simplify the code, but there two things to keep in mind with this
+	 * approach:
+	 *
+	 * 1. Filtering internal kernel tasks is a bit laughable in almost all
+	 * cases, but there is at least one case where there is a benefit:
+	 * the '-a task,never' case allows the admin to effectively disable
+	 * task auditing at runtime.
+	 *
+	 * 2. The {set,clear}_task_syscall_work() ops likely have zero effect
+	 * on these internal kernel tasks, but they probably don't hurt either.
+	 */
+	return audit_alloc(tsk);
+}
+
 static inline void audit_free_context(struct audit_context *context)
 {
 	/* resetting is extra work, but it is likely just noise */
@@ -1546,6 +1572,52 @@ static void audit_log_proctitle(void)
 	audit_log_end(ab);
 }
 
+/**
+ * audit_log_uring - generate a AUDIT_URINGOP record
+ * @ctx: the audit context
+ */
+static void audit_log_uring(struct audit_context *ctx)
+{
+	struct audit_buffer *ab;
+	const struct cred *cred;
+
+	/*
+	 * TODO: What do we log here?  I'm tossing in a few things to start the
+	 *       conversation, but additional thought needs to go into this.
+	 */
+
+	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_URINGOP);
+	if (!ab)
+		return;
+	cred = current_cred();
+	audit_log_format(ab, "uring_op=%d", ctx->uring_op);
+	if (ctx->return_valid != AUDITSC_INVALID)
+		audit_log_format(ab, " success=%s exit=%ld",
+				 (ctx->return_valid == AUDITSC_SUCCESS ?
+				  "yes" : "no"),
+				 ctx->return_code);
+	audit_log_format(ab,
+			 " items=%d"
+			 " ppid=%d pid=%d auid=%u uid=%u gid=%u"
+			 " euid=%u suid=%u fsuid=%u"
+			 " egid=%u sgid=%u fsgid=%u",
+			 ctx->name_count,
+			 task_ppid_nr(current),
+			 task_tgid_nr(current),
+			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
+			 from_kuid(&init_user_ns, cred->uid),
+			 from_kgid(&init_user_ns, cred->gid),
+			 from_kuid(&init_user_ns, cred->euid),
+			 from_kuid(&init_user_ns, cred->suid),
+			 from_kuid(&init_user_ns, cred->fsuid),
+			 from_kgid(&init_user_ns, cred->egid),
+			 from_kgid(&init_user_ns, cred->sgid),
+			 from_kgid(&init_user_ns, cred->fsgid));
+	audit_log_task_context(ab);
+	audit_log_key(ab, ctx->filterkey);
+	audit_log_end(ab);
+}
+
 static void audit_log_exit(void)
 {
 	int i, call_panic = 0;
@@ -1581,6 +1653,9 @@ static void audit_log_exit(void)
 		audit_log_key(ab, context->filterkey);
 		audit_log_end(ab);
 		break;
+	case AUDIT_CTX_URING:
+		audit_log_uring(context);
+		break;
 	default:
 		BUG();
 		break;
@@ -1751,6 +1826,105 @@ static void audit_return_fixup(struct audit_context *ctx,
 	ctx->return_valid = (success ? AUDITSC_SUCCESS : AUDITSC_FAILURE);
 }
 
+/**
+ * __audit_uring_entry - prepare the kernel task's audit context for io_uring
+ * @op: the io_uring opcode
+ *
+ * This is similar to audit_syscall_entry() but is intended for use by io_uring
+ * operations.  This function should only ever be called from
+ * audit_uring_entry() as we rely on the audit context checking present in that
+ * function.
+ */
+void __audit_uring_entry(u8 op)
+{
+	struct audit_context *ctx = audit_context();
+
+	if (ctx->state == AUDIT_STATE_DISABLED)
+		return;
+
+	/*
+	 * NOTE: It's possible that we can be called from the process' context
+	 *       before it returns to userspace, and before audit_syscall_exit()
+	 *       is called.  In this case there is not much to do, just record
+	 *       the io_uring details and return.
+	 */
+	ctx->uring_op = op;
+	if (ctx->context == AUDIT_CTX_SYSCALL)
+		return;
+
+	ctx->dummy = !audit_n_rules;
+	if (!ctx->dummy && ctx->state == AUDIT_STATE_BUILD)
+		ctx->prio = 0;
+
+	ctx->context = AUDIT_CTX_URING;
+	ctx->current_state = ctx->state;
+	ktime_get_coarse_real_ts64(&ctx->ctime);
+}
+
+/**
+ * __audit_uring_exit - wrap up the kernel task's audit context after io_uring
+ * @success: true/false value to indicate if the operation succeeded or not
+ * @code: operation return code
+ *
+ * This is similar to audit_syscall_exit() but is intended for use by io_uring
+ * operations.  This function should only ever be called from
+ * audit_uring_exit() as we rely on the audit context checking present in that
+ * function.
+ */
+void __audit_uring_exit(int success, long code)
+{
+	struct audit_context *ctx = audit_context();
+
+	/*
+	 * TODO: At some point we will likely want to filter on io_uring ops
+	 *       and other things similar to what we do for syscalls, but that
+	 *       is something for another day; just record what we can here.
+	 */
+
+	if (ctx->context == AUDIT_CTX_SYSCALL) {
+		/*
+		 * NOTE: See the note in __audit_uring_entry() about the case
+		 *       where we may be called from process context before we
+		 *       return to userspace via audit_syscall_exit().  In this
+		 *       case we simply emit a URINGOP record and bail, the
+		 *       normal syscall exit handling will take care of
+		 *       everything else.
+		 *       It is also worth mentioning that when we are called,
+		 *       the current process creds may differ from the creds
+		 *       used during the normal syscall processing; keep that
+		 *       in mind if/when we move the record generation code.
+		 */
+
+		/*
+		 * We need to filter on the syscall info here to decide if we
+		 * should emit a URINGOP record.  I know it seems odd but this
+		 * solves the problem where users have a filter to block *all*
+		 * syscall records in the "exit" filter; we want to preserve
+		 * the behavior here.
+		 */
+		audit_filter_syscall(current, ctx);
+		audit_filter_inodes(current, ctx);
+		if (ctx->current_state != AUDIT_STATE_RECORD)
+			return;
+
+		audit_log_uring(ctx);
+		return;
+	}
+
+	/* this may generate CONFIG_CHANGE records */
+	if (!list_empty(&ctx->killed_trees))
+		audit_kill_trees(ctx);
+
+	audit_filter_inodes(current, ctx);
+	if (ctx->current_state != AUDIT_STATE_RECORD)
+		goto out;
+	audit_return_fixup(ctx, success, code);
+	audit_log_exit();
+
+out:
+	audit_reset_context(ctx);
+}
+
 /**
  * __audit_syscall_entry - fill in an audit record at syscall entry
  * @major: major syscall type (function)


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

* [RFC PATCH v2 3/9] audit: dev/test patch to force io_uring auditing
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 1/9] audit: prepare audit_context for use in calling contexts beyond syscalls Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 2/9] audit,io_uring,io-wq: add some basic audit support to io_uring Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 4/9] audit: add filtering for io_uring records Paul Moore
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This patch is intended only to aid in the initial dev/test
of the audit/io_uring support, it is not intended to be merged.

With this patch, you can emit io_uring operation audit records with
the following commands (the first clears any blocking rules):

  % auditctl -D
  % auditctl -a exit,always -S io_uring_enter

Signed-off-by: DO NOT COMMIT
---
 kernel/auditsc.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 62fb502da3fc..928f1dd12460 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1910,6 +1910,10 @@ void __audit_uring_exit(int success, long code)
 		audit_log_uring(ctx);
 		return;
 	}
+#if 1
+	/* XXX - temporary hack to force record generation */
+	ctx->current_state = AUDIT_STATE_RECORD;
+#endif
 
 	/* this may generate CONFIG_CHANGE records */
 	if (!list_empty(&ctx->killed_trees))


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

* [RFC PATCH v2 4/9] audit: add filtering for io_uring records
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (2 preceding siblings ...)
  2021-08-11 20:48 ` [RFC PATCH v2 3/9] audit: dev/test patch to force io_uring auditing Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure() Paul Moore
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This is a work in progress and should not be merged
anywhere important.  It is almost surely not complete, and while it
probably compiles it likely hasn't been booted and will do terrible
things.  You have been warned.

This patch adds basic audit io_uring filtering, using as much of the
existing audit filtering infrastructure as possible.  In order to do
this we reuse the audit filter rule's syscall mask for the io_uring
operation and we create a new filter for io_uring operations as
AUDIT_FILTER_URING_EXIT/audit_filter_list[7].

<TODO - provide some additional guidance for the userspace tools>

Thanks to Richard Guy Briggs for his review and feedback.

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- incorporate feedback from Richard
v1:
- initial draft
---
 include/uapi/linux/audit.h |    3 +-
 kernel/audit_tree.c        |    3 +-
 kernel/audit_watch.c       |    3 +-
 kernel/auditfilter.c       |   15 ++++++++--
 kernel/auditsc.c           |   65 ++++++++++++++++++++++++++++++++++----------
 5 files changed, 68 insertions(+), 21 deletions(-)

diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index a1997697c8b1..ecf1edd2affa 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -167,8 +167,9 @@
 #define AUDIT_FILTER_EXCLUDE	0x05	/* Apply rule before record creation */
 #define AUDIT_FILTER_TYPE	AUDIT_FILTER_EXCLUDE /* obsolete misleading naming */
 #define AUDIT_FILTER_FS		0x06	/* Apply rule at __audit_inode_child */
+#define AUDIT_FILTER_URING_EXIT	0x07	/* Apply rule at io_uring op exit */
 
-#define AUDIT_NR_FILTERS	7
+#define AUDIT_NR_FILTERS	8
 
 #define AUDIT_FILTER_PREPEND	0x10	/* Prepend to front of list */
 
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index b2be4e978ba3..31bf34844546 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -726,7 +726,8 @@ int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
 {
 
 	if (pathname[0] != '/' ||
-	    rule->listnr != AUDIT_FILTER_EXIT ||
+	    (rule->listnr != AUDIT_FILTER_EXIT &&
+	     rule->listnr != AUDIT_FILTER_URING_EXIT) ||
 	    op != Audit_equal ||
 	    rule->inode_f || rule->watch || rule->tree)
 		return -EINVAL;
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 2acf7ca49154..698b62b4a2ec 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -183,7 +183,8 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
 		return -EOPNOTSUPP;
 
 	if (path[0] != '/' || path[len-1] == '/' ||
-	    krule->listnr != AUDIT_FILTER_EXIT ||
+	    (krule->listnr != AUDIT_FILTER_EXIT &&
+	     krule->listnr != AUDIT_FILTER_URING_EXIT) ||
 	    op != Audit_equal ||
 	    krule->inode_f || krule->watch || krule->tree)
 		return -EINVAL;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index db2c6b59dfc3..d75acb014ccd 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -44,7 +44,8 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
 	LIST_HEAD_INIT(audit_filter_list[4]),
 	LIST_HEAD_INIT(audit_filter_list[5]),
 	LIST_HEAD_INIT(audit_filter_list[6]),
-#if AUDIT_NR_FILTERS != 7
+	LIST_HEAD_INIT(audit_filter_list[7]),
+#if AUDIT_NR_FILTERS != 8
 #error Fix audit_filter_list initialiser
 #endif
 };
@@ -56,6 +57,7 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
 	LIST_HEAD_INIT(audit_rules_list[4]),
 	LIST_HEAD_INIT(audit_rules_list[5]),
 	LIST_HEAD_INIT(audit_rules_list[6]),
+	LIST_HEAD_INIT(audit_rules_list[7]),
 };
 
 DEFINE_MUTEX(audit_filter_mutex);
@@ -151,7 +153,8 @@ char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
 static inline int audit_to_inode(struct audit_krule *krule,
 				 struct audit_field *f)
 {
-	if (krule->listnr != AUDIT_FILTER_EXIT ||
+	if ((krule->listnr != AUDIT_FILTER_EXIT &&
+	     krule->listnr != AUDIT_FILTER_URING_EXIT) ||
 	    krule->inode_f || krule->watch || krule->tree ||
 	    (f->op != Audit_equal && f->op != Audit_not_equal))
 		return -EINVAL;
@@ -248,6 +251,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
 		pr_err("AUDIT_FILTER_ENTRY is deprecated\n");
 		goto exit_err;
 	case AUDIT_FILTER_EXIT:
+	case AUDIT_FILTER_URING_EXIT:
 	case AUDIT_FILTER_TASK:
 #endif
 	case AUDIT_FILTER_USER:
@@ -332,6 +336,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
 		if (entry->rule.listnr != AUDIT_FILTER_FS)
 			return -EINVAL;
 		break;
+	case AUDIT_PERM:
+		if (entry->rule.listnr == AUDIT_FILTER_URING_EXIT)
+			return -EINVAL;
+		break;
 	}
 
 	switch (entry->rule.listnr) {
@@ -980,7 +988,8 @@ static inline int audit_add_rule(struct audit_entry *entry)
 	}
 
 	entry->rule.prio = ~0ULL;
-	if (entry->rule.listnr == AUDIT_FILTER_EXIT) {
+	if (entry->rule.listnr == AUDIT_FILTER_EXIT ||
+	    entry->rule.listnr == AUDIT_FILTER_URING_EXIT) {
 		if (entry->rule.flags & AUDIT_FILTER_PREPEND)
 			entry->rule.prio = ++prio_high;
 		else
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 928f1dd12460..f4a2ca496cac 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -805,6 +805,35 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
 	return rule->mask[word] & bit;
 }
 
+/**
+ * audit_filter_uring - apply filters to an io_uring operation
+ * @tsk: associated task
+ * @ctx: audit context
+ */
+static void audit_filter_uring(struct task_struct *tsk,
+			       struct audit_context *ctx)
+{
+	struct audit_entry *e;
+	enum audit_state state;
+
+	if (auditd_test_task(tsk))
+		return;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
+				list) {
+		if (audit_in_mask(&e->rule, ctx->uring_op) &&
+		    audit_filter_rules(tsk, &e->rule, ctx, NULL, &state,
+				       false)) {
+			rcu_read_unlock();
+			ctx->current_state = state;
+			return;
+		}
+	}
+	rcu_read_unlock();
+	return;
+}
+
 /* At syscall exit time, this filter is called if the audit_state is
  * not low enough that auditing cannot take place, but is also not
  * high enough that we already know we have to write an audit record
@@ -1765,7 +1794,7 @@ static void audit_log_exit(void)
  * __audit_free - free a per-task audit context
  * @tsk: task whose audit context block to free
  *
- * Called from copy_process and do_exit
+ * Called from copy_process, do_exit, and the io_uring code
  */
 void __audit_free(struct task_struct *tsk)
 {
@@ -1783,15 +1812,21 @@ void __audit_free(struct task_struct *tsk)
 	 * random task_struct that doesn't doesn't have any meaningful data we
 	 * need to log via audit_log_exit().
 	 */
-	if (tsk == current && !context->dummy &&
-	    context->context == AUDIT_CTX_SYSCALL) {
+	if (tsk == current && !context->dummy) {
 		context->return_valid = AUDITSC_INVALID;
 		context->return_code = 0;
-
-		audit_filter_syscall(tsk, context);
-		audit_filter_inodes(tsk, context);
-		if (context->current_state == AUDIT_STATE_RECORD)
-			audit_log_exit();
+		if (context->context == AUDIT_CTX_SYSCALL) {
+			audit_filter_syscall(tsk, context);
+			audit_filter_inodes(tsk, context);
+			if (context->current_state == AUDIT_STATE_RECORD)
+				audit_log_exit();
+		} else if (context->context == AUDIT_CTX_URING) {
+			/* TODO: verify this case is real and valid */
+			audit_filter_uring(tsk, context);
+			audit_filter_inodes(tsk, context);
+			if (context->current_state == AUDIT_STATE_RECORD)
+				audit_log_uring(context);
+		}
 	}
 
 	audit_set_context(tsk, NULL);
@@ -1875,12 +1910,6 @@ void __audit_uring_exit(int success, long code)
 {
 	struct audit_context *ctx = audit_context();
 
-	/*
-	 * TODO: At some point we will likely want to filter on io_uring ops
-	 *       and other things similar to what we do for syscalls, but that
-	 *       is something for another day; just record what we can here.
-	 */
-
 	if (ctx->context == AUDIT_CTX_SYSCALL) {
 		/*
 		 * NOTE: See the note in __audit_uring_entry() about the case
@@ -1903,6 +1932,8 @@ void __audit_uring_exit(int success, long code)
 		 * the behavior here.
 		 */
 		audit_filter_syscall(current, ctx);
+		if (ctx->current_state != AUDIT_STATE_RECORD)
+			audit_filter_uring(current, ctx);
 		audit_filter_inodes(current, ctx);
 		if (ctx->current_state != AUDIT_STATE_RECORD)
 			return;
@@ -1911,7 +1942,9 @@ void __audit_uring_exit(int success, long code)
 		return;
 	}
 #if 1
-	/* XXX - temporary hack to force record generation */
+	/* XXX - temporary hack to force record generation, we are leaving this
+	 *       enabled, but if you want to actually test the filtering you
+	 *       need to disable this #if/#endif block */
 	ctx->current_state = AUDIT_STATE_RECORD;
 #endif
 
@@ -1919,6 +1952,8 @@ void __audit_uring_exit(int success, long code)
 	if (!list_empty(&ctx->killed_trees))
 		audit_kill_trees(ctx);
 
+	/* run through both filters to ensure we set the filterkey properly */
+	audit_filter_uring(current, ctx);
 	audit_filter_inodes(current, ctx);
 	if (ctx->current_state != AUDIT_STATE_RECORD)
 		goto out;


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

* [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure()
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (3 preceding siblings ...)
  2021-08-11 20:48 ` [RFC PATCH v2 4/9] audit: add filtering for io_uring records Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-12  9:32   ` Mickaël Salaün
  2021-08-11 20:48 ` [RFC PATCH v2 6/9] io_uring: convert io_uring to the secure anon inode interface Paul Moore
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

Extending the secure anonymous inode support to other subsystems
requires that we have a secure anon_inode_getfile() variant in
addition to the existing secure anon_inode_getfd() variant.

Thankfully we can reuse the existing __anon_inode_getfile() function
and just wrap it with the proper arguments.

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- no change
v1:
- initial draft
---
 fs/anon_inodes.c            |   29 +++++++++++++++++++++++++++++
 include/linux/anon_inodes.h |    4 ++++
 2 files changed, 33 insertions(+)

diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index a280156138ed..e0c3e33c4177 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -148,6 +148,35 @@ struct file *anon_inode_getfile(const char *name,
 }
 EXPORT_SYMBOL_GPL(anon_inode_getfile);
 
+/**
+ * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new
+ *                             !S_PRIVATE anon inode rather than reuse the
+ *                             singleton anon inode and calls the
+ *                             inode_init_security_anon() LSM hook.  This
+ *                             allows for both the inode to have its own
+ *                             security context and for the LSM to enforce
+ *                             policy on the inode's creation.
+ *
+ * @name:    [in]    name of the "class" of the new file
+ * @fops:    [in]    file operations for the new file
+ * @priv:    [in]    private data for the new file (will be file's private_data)
+ * @flags:   [in]    flags
+ * @context_inode:
+ *           [in]    the logical relationship with the new inode (optional)
+ *
+ * The LSM may use @context_inode in inode_init_security_anon(), but a
+ * reference to it is not held.  Returns the newly created file* or an error
+ * pointer.  See the anon_inode_getfile() documentation for more information.
+ */
+struct file *anon_inode_getfile_secure(const char *name,
+				       const struct file_operations *fops,
+				       void *priv, int flags,
+				       const struct inode *context_inode)
+{
+	return __anon_inode_getfile(name, fops, priv, flags,
+				    context_inode, true);
+}
+
 static int __anon_inode_getfd(const char *name,
 			      const struct file_operations *fops,
 			      void *priv, int flags,
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index 71881a2b6f78..5deaddbd7927 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -15,6 +15,10 @@ struct inode;
 struct file *anon_inode_getfile(const char *name,
 				const struct file_operations *fops,
 				void *priv, int flags);
+struct file *anon_inode_getfile_secure(const char *name,
+				       const struct file_operations *fops,
+				       void *priv, int flags,
+				       const struct inode *context_inode);
 int anon_inode_getfd(const char *name, const struct file_operations *fops,
 		     void *priv, int flags);
 int anon_inode_getfd_secure(const char *name,


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

* [RFC PATCH v2 6/9] io_uring: convert io_uring to the secure anon inode interface
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (4 preceding siblings ...)
  2021-08-11 20:48 ` [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure() Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:48 ` [RFC PATCH v2 7/9] lsm,io_uring: add LSM hooks to io_uring Paul Moore
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

Converting io_uring's anonymous inode to the secure anon inode API
enables LSMs to enforce policy on the io_uring anonymous inodes if
they chose to do so.  This is an important first step towards
providing the necessary mechanisms so that LSMs can apply security
policy to io_uring operations.

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- no change
v1:
- initial draft
---
 fs/io_uring.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index b407a6ea1779..ea396f5fe735 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -9662,8 +9662,8 @@ static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
 		return ERR_PTR(ret);
 #endif
 
-	file = anon_inode_getfile("[io_uring]", &io_uring_fops, ctx,
-					O_RDWR | O_CLOEXEC);
+	file = anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
+					 O_RDWR | O_CLOEXEC, NULL);
 #if defined(CONFIG_UNIX)
 	if (IS_ERR(file)) {
 		sock_release(ctx->ring_sock);


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

* [RFC PATCH v2 7/9] lsm,io_uring: add LSM hooks to io_uring
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (5 preceding siblings ...)
  2021-08-11 20:48 ` [RFC PATCH v2 6/9] io_uring: convert io_uring to the secure anon inode interface Paul Moore
@ 2021-08-11 20:48 ` Paul Moore
  2021-08-11 20:49 ` [RFC PATCH v2 8/9] selinux: add support for the io_uring access controls Paul Moore
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:48 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This is a work in progress, this patch, including the
description, may be incomplete or even incorrect.  You have been
warned.

A full expalantion of io_uring is beyond the scope of this commit
description, but in summary it is an asynchronous I/O mechanism
which allows for I/O requests and the resulting data to be queued
in memory mapped "rings" which are shared between the kernel and
userspace.  Optionally, io_uring offers the ability for applications
to spawn kernel threads to dequeue I/O requests from the ring and
submit the requests in the kernel, helping to minimize the syscall
overhead.  Rings are accessed in userspace by memory mapping a file
descriptor provided by the io_uring_setup(2), and can be shared
between applications as one might do with any open file descriptor.
Finally, process credentials can be registered with a given ring
and any process with access to that ring can submit I/O requests
using any of the registered credentials.

While the io_uring functionality is widely recognized as offering a
vastly improved, and high performing asynchronous I/O mechanism, its
ability to allow processes to submit I/O requests with credentials
other than its own presents a challenge to LSMs.  When a process
creates a new io_uring ring the ring's credentials are inhertied
from the calling process; if this ring is shared with another
process operating with different credentials there is the potential
to bypass the LSMs security policy.  Similarly, registering
credentials with a given ring allows any process with access to that
ring to submit I/O requests with those credentials.

In an effort to allow LSMs to apply security policy to io_uring I/O
operations, this patch adds two new LSM hooks.  These hooks, in
conjunction with the LSM anonymous inode support previously
submitted, allow an LSM to apply access control policy to the
sharing of io_uring rings as well as any io_uring credential changes
requested by a process.

The new LSM hooks are described below:

 * int security_uring_override_creds(cred)
   Controls if the current task, executing an io_uring operation,
   is allowed to override it's credentials with @cred.  In cases
   where the current task is a user application, the current
   credentials will be those of the user application.  In cases
   where the current task is a kernel thread servicing io_uring
   requests the current credentials will be those of the io_uring
   ring (inherited from the process that created the ring).

 * int security_uring_sqpoll(void)
   Controls if the current task is allowed to create an io_uring
   polling thread (IORING_SETUP_SQPOLL).  Without a SQPOLL thread
   in the kernel processes must submit I/O requests via
   io_uring_enter(2) which allows us to compare any requested
   credential changes against the application making the request.
   With a SQPOLL thread, we can no longer compare requested
   credential changes against the application making the request,
   the comparison is made against the ring's credentials.

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- no change
v1:
- initial draft
---
 fs/io_uring.c                 |   10 ++++++++++
 include/linux/lsm_hook_defs.h |    5 +++++
 include/linux/lsm_hooks.h     |   13 +++++++++++++
 include/linux/security.h      |   16 ++++++++++++++++
 security/security.c           |   12 ++++++++++++
 5 files changed, 56 insertions(+)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index ea396f5fe735..78df778d329b 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -79,6 +79,7 @@
 #include <linux/pagemap.h>
 #include <linux/io_uring.h>
 #include <linux/audit.h>
+#include <linux/security.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/io_uring.h>
@@ -6617,6 +6618,11 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 		if (!req->creds)
 			return -EINVAL;
 		get_cred(req->creds);
+		ret = security_uring_override_creds(req->creds);
+		if (ret) {
+			put_cred(req->creds);
+			return ret;
+		}
 		req->flags |= REQ_F_CREDS;
 	}
 	state = &ctx->submit_state;
@@ -8080,6 +8086,10 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
 		struct io_sq_data *sqd;
 		bool attached;
 
+		ret = security_uring_sqpoll();
+		if (ret)
+			return ret;
+
 		sqd = io_get_sq_data(p, &attached);
 		if (IS_ERR(sqd)) {
 			ret = PTR_ERR(sqd);
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 2adeea44c0d5..b3c525353769 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -402,3 +402,8 @@ LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
 LSM_HOOK(int, 0, perf_event_read, struct perf_event *event)
 LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
 #endif /* CONFIG_PERF_EVENTS */
+
+#ifdef CONFIG_IO_URING
+LSM_HOOK(int, 0, uring_override_creds, const struct cred *new)
+LSM_HOOK(int, 0, uring_sqpoll, void)
+#endif /* CONFIG_IO_URING */
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 5c4c5c0602cb..0eb0ae95c4c4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1557,6 +1557,19 @@
  * 	Read perf_event security info if allowed.
  * @perf_event_write:
  * 	Write perf_event security info if allowed.
+ *
+ * Security hooks for io_uring
+ *
+ * @uring_override_creds:
+ *      Check if the current task, executing an io_uring operation, is allowed
+ *      to override it's credentials with @new.
+ *
+ *      @new: the new creds to use
+ *
+ * @uring_sqpoll:
+ *      Check whether the current task is allowed to spawn a io_uring polling
+ *      thread (IORING_SETUP_SQPOLL).
+ *
  */
 union security_list_options {
 	#define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
diff --git a/include/linux/security.h b/include/linux/security.h
index 24eda04221e9..3928d80b6f76 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2037,4 +2037,20 @@ static inline int security_perf_event_write(struct perf_event *event)
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_PERF_EVENTS */
 
+#ifdef CONFIG_IO_URING
+#ifdef CONFIG_SECURITY
+extern int security_uring_override_creds(const struct cred *new);
+extern int security_uring_sqpoll(void);
+#else
+static inline int security_uring_override_creds(const struct cred *new)
+{
+	return 0;
+}
+static inline int security_uring_sqpoll(void)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY */
+#endif /* CONFIG_IO_URING */
+
 #endif /* ! __LINUX_SECURITY_H */
diff --git a/security/security.c b/security/security.c
index 09533cbb7221..a54544e61bd1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2624,3 +2624,15 @@ int security_perf_event_write(struct perf_event *event)
 	return call_int_hook(perf_event_write, 0, event);
 }
 #endif /* CONFIG_PERF_EVENTS */
+
+#ifdef CONFIG_IO_URING
+int security_uring_override_creds(const struct cred *new)
+{
+	return call_int_hook(uring_override_creds, 0, new);
+}
+
+int security_uring_sqpoll(void)
+{
+	return call_int_hook(uring_sqpoll, 0);
+}
+#endif /* CONFIG_IO_URING */


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

* [RFC PATCH v2 8/9] selinux: add support for the io_uring access controls
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (6 preceding siblings ...)
  2021-08-11 20:48 ` [RFC PATCH v2 7/9] lsm,io_uring: add LSM hooks to io_uring Paul Moore
@ 2021-08-11 20:49 ` Paul Moore
  2021-08-11 20:49 ` [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug Paul Moore
  2021-08-24 20:57 ` [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Richard Guy Briggs
  9 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:49 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

WARNING - This is a work in progress, this patch, including the
description, may be incomplete or even incorrect.  You have been
warned.

This patch implements two new io_uring access controls, specifically
support for controlling the io_uring "personalities" and
IORING_SETUP_SQPOLL.  Controlling the sharing of io_urings themselves
is handled via the normal file/inode labeling and sharing mechanisms.

The io_uring { override_creds } permission restricts which domains
the subject domain can use to override it's own credentials.
Granting a domain the io_uring { override_creds } permission allows
it to impersonate another domain in io_uring operations.

The io_uring { sqpoll } permission restricts which domains can create
asynchronous io_uring polling threads.  This is important from a
security perspective as operations queued by this asynchronous thread
inherit the credentials of the thread creator by default; if an
io_uring is shared across process/domain boundaries this could result
in one domain impersonating another.  Controlling the creation of
sqpoll threads, and the sharing of io_urings across processes, allow
policy authors to restrict the ability of one domain to impersonate
another via io_uring.

As a quick summary, this patch adds a new object class with two
permissions:

 io_uring { override_creds sqpoll }

These permissions can be seen in the two simple policy statements
below:

  allow domA_t domB_t : io_uring { override_creds };
  allow domA_t self : io_uring { sqpoll };

Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- made the selinux_uring_* funcs static
- removed the debugging code
v1:
- initial draft
---
 security/selinux/hooks.c            |   34 ++++++++++++++++++++++++++++++++++
 security/selinux/include/classmap.h |    2 ++
 2 files changed, 36 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b0032c42333e..1fb0c76deff2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7105,6 +7105,35 @@ static int selinux_perf_event_write(struct perf_event *event)
 }
 #endif
 
+#ifdef CONFIG_IO_URING
+/**
+ * selinux_uring_override_creds - check the requested cred override
+ * @new: the target creds
+ *
+ * Check to see if the current task is allowed to override it's credentials
+ * to service an io_uring operation.
+ */
+static int selinux_uring_override_creds(const struct cred *new)
+{
+	return avc_has_perm(&selinux_state, current_sid(), cred_sid(new),
+			    SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
+}
+
+/**
+ * selinux_uring_sqpoll - check if a io_uring polling thread can be created
+ *
+ * Check to see if the current task is allowed to create a new io_uring
+ * kernel polling thread.
+ */
+static int selinux_uring_sqpoll(void)
+{
+	int sid = current_sid();
+
+	return avc_has_perm(&selinux_state, sid, sid,
+			    SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
+}
+#endif /* CONFIG_IO_URING */
+
 /*
  * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
  * 1. any hooks that don't belong to (2.) or (3.) below,
@@ -7343,6 +7372,11 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
 #endif
 
+#ifdef CONFIG_IO_URING
+	LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
+	LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
+#endif
+
 	LSM_HOOK_INIT(locked_down, selinux_lockdown),
 
 	/*
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 62d19bccf3de..3314ad72279d 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -252,6 +252,8 @@ struct security_class_mapping secclass_map[] = {
 	  { "integrity", "confidentiality", NULL } },
 	{ "anon_inode",
 	  { COMMON_FILE_PERMS, NULL } },
+	{ "io_uring",
+	  { "override_creds", "sqpoll", NULL } },
 	{ NULL }
   };
 


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

* [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (7 preceding siblings ...)
  2021-08-11 20:49 ` [RFC PATCH v2 8/9] selinux: add support for the io_uring access controls Paul Moore
@ 2021-08-11 20:49 ` Paul Moore
  2021-08-31 14:44   ` Paul Moore
  2021-08-24 20:57 ` [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Richard Guy Briggs
  9 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-11 20:49 UTC (permalink / raw)
  To: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

From: Casey Schaufler <casey@schaufler-ca.com>

Add Smack privilege checks for io_uring. Use CAP_MAC_OVERRIDE
for the override_creds case and CAP_MAC_ADMIN for creating a
polling thread. These choices are based on conjecture regarding
the intent of the surrounding code.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
[PM: make the smack_uring_* funcs static]
Signed-off-by: Paul Moore <paul@paul-moore.com>

---
v2:
- made the smack_uring_* funcs static
v1:
- initial draft
---
 security/smack/smack_lsm.c |   64 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 223a6da0e6dc..7fb094098f38 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4691,6 +4691,66 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
 	return 0;
 }
 
+#ifdef CONFIG_IO_URING
+/**
+ * smack_uring_override_creds - Is io_uring cred override allowed?
+ * @new: the target creds
+ *
+ * Check to see if the current task is allowed to override it's credentials
+ * to service an io_uring operation.
+ */
+static int smack_uring_override_creds(const struct cred *new)
+{
+	struct task_smack *tsp = smack_cred(current_cred());
+	struct task_smack *nsp = smack_cred(new);
+
+#if 1
+	if (tsp->smk_task == nsp->smk_task)
+		pr_info("%s: Smack matches %s\n", __func__,
+			tsp->smk_task->smk_known);
+	else
+		pr_info("%s: Smack override check %s to %s\n", __func__,
+			tsp->smk_task->smk_known, nsp->smk_task->smk_known);
+#endif
+	/*
+	 * Allow the degenerate case where the new Smack value is
+	 * the same as the current Smack value.
+	 */
+	if (tsp->smk_task == nsp->smk_task)
+		return 0;
+
+#if 1
+	pr_info("%s: Smack sqpoll %s\n", __func__,
+		smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred()) ?
+		"ok by Smack" : "disallowed (No CAP_MAC_OVERRIDE)");
+#endif
+	if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred()))
+		return 0;
+
+	return -EPERM;
+}
+
+/**
+ * smack_uring_sqpoll - check if a io_uring polling thread can be created
+ *
+ * Check to see if the current task is allowed to create a new io_uring
+ * kernel polling thread.
+ */
+static int smack_uring_sqpoll(void)
+{
+#if 1
+	pr_info("%s: Smack new ring %s\n", __func__,
+		smack_privileged_cred(CAP_MAC_ADMIN, current_cred()) ?
+		"ok by Smack" : "disallowed (No CAP_MAC_ADMIN)");
+#endif
+	if (smack_privileged_cred(CAP_MAC_ADMIN, current_cred()))
+		return 0;
+
+	return -EPERM;
+}
+
+#endif /* CONFIG_IO_URING */
+
 struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
 	.lbs_cred = sizeof(struct task_smack),
 	.lbs_file = sizeof(struct smack_known *),
@@ -4843,6 +4903,10 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up),
 	LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr),
 	LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as),
+#ifdef CONFIG_IO_URING
+	LSM_HOOK_INIT(uring_override_creds, smack_uring_override_creds),
+	LSM_HOOK_INIT(uring_sqpoll, smack_uring_sqpoll),
+#endif
 };
 
 


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

* Re: [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure()
  2021-08-11 20:48 ` [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure() Paul Moore
@ 2021-08-12  9:32   ` Mickaël Salaün
  2021-08-12 14:32     ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Mickaël Salaün @ 2021-08-12  9:32 UTC (permalink / raw)
  To: Paul Moore, linux-security-module, selinux, linux-audit,
	io-uring, linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov


On 11/08/2021 22:48, Paul Moore wrote:
> Extending the secure anonymous inode support to other subsystems
> requires that we have a secure anon_inode_getfile() variant in
> addition to the existing secure anon_inode_getfd() variant.
> 
> Thankfully we can reuse the existing __anon_inode_getfile() function
> and just wrap it with the proper arguments.
> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> 
> ---
> v2:
> - no change
> v1:
> - initial draft
> ---
>  fs/anon_inodes.c            |   29 +++++++++++++++++++++++++++++
>  include/linux/anon_inodes.h |    4 ++++
>  2 files changed, 33 insertions(+)
> 
> diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
> index a280156138ed..e0c3e33c4177 100644
> --- a/fs/anon_inodes.c
> +++ b/fs/anon_inodes.c
> @@ -148,6 +148,35 @@ struct file *anon_inode_getfile(const char *name,
>  }
>  EXPORT_SYMBOL_GPL(anon_inode_getfile);
>  
> +/**
> + * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new
> + *                             !S_PRIVATE anon inode rather than reuse the
> + *                             singleton anon inode and calls the
> + *                             inode_init_security_anon() LSM hook.  This
> + *                             allows for both the inode to have its own
> + *                             security context and for the LSM to enforce
> + *                             policy on the inode's creation.
> + *
> + * @name:    [in]    name of the "class" of the new file
> + * @fops:    [in]    file operations for the new file
> + * @priv:    [in]    private data for the new file (will be file's private_data)
> + * @flags:   [in]    flags
> + * @context_inode:
> + *           [in]    the logical relationship with the new inode (optional)
> + *
> + * The LSM may use @context_inode in inode_init_security_anon(), but a
> + * reference to it is not held.  Returns the newly created file* or an error
> + * pointer.  See the anon_inode_getfile() documentation for more information.
> + */
> +struct file *anon_inode_getfile_secure(const char *name,
> +				       const struct file_operations *fops,
> +				       void *priv, int flags,
> +				       const struct inode *context_inode)
> +{
> +	return __anon_inode_getfile(name, fops, priv, flags,
> +				    context_inode, true);

This is not directly related to this patch but why using the "secure"
boolean in __anon_inode_getfile() and __anon_inode_getfd() instead of
checking that context_inode is not NULL? This would simplify the code,
remove this anon_inode_getfile_secure() wrapper and avoid potential
inconsistencies.

> +}
> +
>  static int __anon_inode_getfd(const char *name,
>  			      const struct file_operations *fops,
>  			      void *priv, int flags,
> diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
> index 71881a2b6f78..5deaddbd7927 100644
> --- a/include/linux/anon_inodes.h
> +++ b/include/linux/anon_inodes.h
> @@ -15,6 +15,10 @@ struct inode;
>  struct file *anon_inode_getfile(const char *name,
>  				const struct file_operations *fops,
>  				void *priv, int flags);
> +struct file *anon_inode_getfile_secure(const char *name,
> +				       const struct file_operations *fops,
> +				       void *priv, int flags,
> +				       const struct inode *context_inode);
>  int anon_inode_getfd(const char *name, const struct file_operations *fops,
>  		     void *priv, int flags);
>  int anon_inode_getfd_secure(const char *name,
> 

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

* Re: [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure()
  2021-08-12  9:32   ` Mickaël Salaün
@ 2021-08-12 14:32     ` Paul Moore
  2021-08-12 15:35       ` Mickaël Salaün
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-12 14:32 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Thu, Aug 12, 2021 at 5:32 AM Mickaël Salaün <mic@digikod.net> wrote:
> On 11/08/2021 22:48, Paul Moore wrote:
> > Extending the secure anonymous inode support to other subsystems
> > requires that we have a secure anon_inode_getfile() variant in
> > addition to the existing secure anon_inode_getfd() variant.
> >
> > Thankfully we can reuse the existing __anon_inode_getfile() function
> > and just wrap it with the proper arguments.
> >
> > Signed-off-by: Paul Moore <paul@paul-moore.com>
> >
> > ---
> > v2:
> > - no change
> > v1:
> > - initial draft
> > ---
> >  fs/anon_inodes.c            |   29 +++++++++++++++++++++++++++++
> >  include/linux/anon_inodes.h |    4 ++++
> >  2 files changed, 33 insertions(+)
> >
> > diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
> > index a280156138ed..e0c3e33c4177 100644
> > --- a/fs/anon_inodes.c
> > +++ b/fs/anon_inodes.c
> > @@ -148,6 +148,35 @@ struct file *anon_inode_getfile(const char *name,
> >  }
> >  EXPORT_SYMBOL_GPL(anon_inode_getfile);
> >
> > +/**
> > + * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new
> > + *                             !S_PRIVATE anon inode rather than reuse the
> > + *                             singleton anon inode and calls the
> > + *                             inode_init_security_anon() LSM hook.  This
> > + *                             allows for both the inode to have its own
> > + *                             security context and for the LSM to enforce
> > + *                             policy on the inode's creation.
> > + *
> > + * @name:    [in]    name of the "class" of the new file
> > + * @fops:    [in]    file operations for the new file
> > + * @priv:    [in]    private data for the new file (will be file's private_data)
> > + * @flags:   [in]    flags
> > + * @context_inode:
> > + *           [in]    the logical relationship with the new inode (optional)
> > + *
> > + * The LSM may use @context_inode in inode_init_security_anon(), but a
> > + * reference to it is not held.  Returns the newly created file* or an error
> > + * pointer.  See the anon_inode_getfile() documentation for more information.
> > + */
> > +struct file *anon_inode_getfile_secure(const char *name,
> > +                                    const struct file_operations *fops,
> > +                                    void *priv, int flags,
> > +                                    const struct inode *context_inode)
> > +{
> > +     return __anon_inode_getfile(name, fops, priv, flags,
> > +                                 context_inode, true);
>
> This is not directly related to this patch but why using the "secure"
> boolean in __anon_inode_getfile() and __anon_inode_getfd() instead of
> checking that context_inode is not NULL? This would simplify the code,
> remove this anon_inode_getfile_secure() wrapper and avoid potential
> inconsistencies.

The issue is that it is acceptable for the context_inode to be either
valid or NULL for callers who request the "secure" code path.

Look at the SELinux implementation of the anonymous inode hook in
selinux_inode_init_security_anon() and you will see that in cases
where the context_inode is valid we simply inherit the label from the
given inode, whereas if context_inode is NULL we do a type transition
using the requesting task and the anonymous inode's "name".

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure()
  2021-08-12 14:32     ` Paul Moore
@ 2021-08-12 15:35       ` Mickaël Salaün
  0 siblings, 0 replies; 35+ messages in thread
From: Mickaël Salaün @ 2021-08-12 15:35 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov


On 12/08/2021 16:32, Paul Moore wrote:
> On Thu, Aug 12, 2021 at 5:32 AM Mickaël Salaün <mic@digikod.net> wrote:
>> On 11/08/2021 22:48, Paul Moore wrote:
>>> Extending the secure anonymous inode support to other subsystems
>>> requires that we have a secure anon_inode_getfile() variant in
>>> addition to the existing secure anon_inode_getfd() variant.
>>>
>>> Thankfully we can reuse the existing __anon_inode_getfile() function
>>> and just wrap it with the proper arguments.
>>>
>>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>>>
>>> ---
>>> v2:
>>> - no change
>>> v1:
>>> - initial draft
>>> ---
>>>  fs/anon_inodes.c            |   29 +++++++++++++++++++++++++++++
>>>  include/linux/anon_inodes.h |    4 ++++
>>>  2 files changed, 33 insertions(+)
>>>
>>> diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
>>> index a280156138ed..e0c3e33c4177 100644
>>> --- a/fs/anon_inodes.c
>>> +++ b/fs/anon_inodes.c
>>> @@ -148,6 +148,35 @@ struct file *anon_inode_getfile(const char *name,
>>>  }
>>>  EXPORT_SYMBOL_GPL(anon_inode_getfile);
>>>
>>> +/**
>>> + * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new
>>> + *                             !S_PRIVATE anon inode rather than reuse the
>>> + *                             singleton anon inode and calls the
>>> + *                             inode_init_security_anon() LSM hook.  This
>>> + *                             allows for both the inode to have its own
>>> + *                             security context and for the LSM to enforce
>>> + *                             policy on the inode's creation.
>>> + *
>>> + * @name:    [in]    name of the "class" of the new file
>>> + * @fops:    [in]    file operations for the new file
>>> + * @priv:    [in]    private data for the new file (will be file's private_data)
>>> + * @flags:   [in]    flags
>>> + * @context_inode:
>>> + *           [in]    the logical relationship with the new inode (optional)
>>> + *
>>> + * The LSM may use @context_inode in inode_init_security_anon(), but a
>>> + * reference to it is not held.  Returns the newly created file* or an error
>>> + * pointer.  See the anon_inode_getfile() documentation for more information.
>>> + */
>>> +struct file *anon_inode_getfile_secure(const char *name,
>>> +                                    const struct file_operations *fops,
>>> +                                    void *priv, int flags,
>>> +                                    const struct inode *context_inode)
>>> +{
>>> +     return __anon_inode_getfile(name, fops, priv, flags,
>>> +                                 context_inode, true);
>>
>> This is not directly related to this patch but why using the "secure"
>> boolean in __anon_inode_getfile() and __anon_inode_getfd() instead of
>> checking that context_inode is not NULL? This would simplify the code,
>> remove this anon_inode_getfile_secure() wrapper and avoid potential
>> inconsistencies.
> 
> The issue is that it is acceptable for the context_inode to be either
> valid or NULL for callers who request the "secure" code path.
> 
> Look at the SELinux implementation of the anonymous inode hook in
> selinux_inode_init_security_anon() and you will see that in cases
> where the context_inode is valid we simply inherit the label from the
> given inode, whereas if context_inode is NULL we do a type transition
> using the requesting task and the anonymous inode's "name".
> 

Indeed.

Acked-by: Mickaël Salaün <mic@linux.microsoft.com>

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
                   ` (8 preceding siblings ...)
  2021-08-11 20:49 ` [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug Paul Moore
@ 2021-08-24 20:57 ` Richard Guy Briggs
  2021-08-24 22:27   ` Paul Moore
  2021-08-26  1:16   ` Richard Guy Briggs
  9 siblings, 2 replies; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-24 20:57 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-08-11 16:48, Paul Moore wrote:
> Draft #2 of the patchset which brings auditing and proper LSM access
> controls to the io_uring subsystem.  The original patchset was posted
> in late May and can be found via lore using the link below:
> 
> https://lore.kernel.org/linux-security-module/162163367115.8379.8459012634106035341.stgit@sifl/
> 
> This draft should incorporate all of the feedback from the original
> posting as well as a few smaller things I noticed while playing
> further with the code.  The big change is of course the selective
> auditing in the io_uring op servicing, but that has already been
> discussed quite a bit in the original thread so I won't go into
> detail here; the important part is that we found a way to move
> forward and this draft captures that.  For those of you looking to
> play with these patches, they are based on Linus' v5.14-rc5 tag and
> on my test system they boot and appear to function without problem;
> they pass the selinux-testsuite and audit-testsuite and I have not
> noticed any regressions in the normal use of the system.  If you want
> to get a copy of these patches straight from git you can use the
> "working-io_uring" branch in the repo below:
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> 
> Beyond the existing test suite tests mentioned above, I've cobbled
> together some very basic, very crude tests to exercise some of the
> things I care about from a LSM/audit perspective.  These tests are
> pretty awful (I'm not kidding), but they might be helpful for the
> other LSM/audit developers who want to test things:
> 
> https://drop.paul-moore.com/90.kUgq
> 
> There are currently two tests: 'iouring.2' and 'iouring.3';
> 'iouring.1' was lost in a misguided and overzealous 'rm' command.
> The first test is standalone and basically tests the SQPOLL
> functionality while the second tests sharing io_urings across process
> boundaries and the credential/personality sharing mechanism.  The
> console output of both tests isn't particularly useful, the more
> interesting bits are in the audit and LSM specific logs.  The
> 'iouring.2' command requires no special arguments to run but the
> 'iouring.3' test is split into a "server" and "client"; the server
> should be run without argument:
> 
>   % ./iouring.3s
>   >>> server started, pid = 11678
>   >>> memfd created, fd = 3
>   >>> io_uring created; fd = 5, creds = 1
> 
> ... while the client should be run with two arguments: the first is
> the PID of the server process, the second is the "memfd" fd number:
> 
>   % ./iouring.3c 11678 3
>   >>> client started, server_pid = 11678 server_memfd = 3
>   >>> io_urings = 5 (server) / 5 (client)
>   >>> io_uring ops using creds = 1
>   >>> async op result: 36
>   >>> async op result: 36
>   >>> async op result: 36
>   >>> async op result: 36
>   >>> START file contents
>   What is this life if, full of care,
>   we have no time to stand and stare.
>   >>> END file contents
> 
> The tests were hacked together from various sources online,
> attribution and links to additional info can be found in the test
> sources, but I expect these tests to die a fiery death in the not
> to distant future as I work to add some proper tests to the SELinux
> and audit test suites.
> 
> As I believe these patches should spend a full -rcX cycle in
> linux-next, my current plan is to continue to solicit feedback on
> these patches while they undergo additional testing (next up is
> verification of the audit filter code for io_uring).  Assuming no
> critical issues are found on the mailing lists or during testing, I
> will post a proper patchset later with the idea of merging it into
> selinux/next after the upcoming merge window closes.
> 
> Any comments, feedback, etc. are welcome.

Thanks for the tests.  I have a bunch of userspace patches to add to the
last set I posted and these tests will help exercise them.  I also have
one more kernel patch to post...  I'll dive back into that now.  I had
wanted to post them before now but got distracted with AUDIT_TRIM
breakage.

> ---
> 
> Casey Schaufler (1):
>       Smack: Brutalist io_uring support with debug
> 
> Paul Moore (8):
>       audit: prepare audit_context for use in calling contexts beyond
>              syscalls
>       audit,io_uring,io-wq: add some basic audit support to io_uring
>       audit: dev/test patch to force io_uring auditing
>       audit: add filtering for io_uring records
>       fs: add anon_inode_getfile_secure() similar to
>           anon_inode_getfd_secure()
>       io_uring: convert io_uring to the secure anon inode interface
>       lsm,io_uring: add LSM hooks to io_uring
>       selinux: add support for the io_uring access controls
> 
> 
>  fs/anon_inodes.c                    |  29 ++
>  fs/io-wq.c                          |   4 +
>  fs/io_uring.c                       |  69 +++-
>  include/linux/anon_inodes.h         |   4 +
>  include/linux/audit.h               |  26 ++
>  include/linux/lsm_hook_defs.h       |   5 +
>  include/linux/lsm_hooks.h           |  13 +
>  include/linux/security.h            |  16 +
>  include/uapi/linux/audit.h          |   4 +-
>  kernel/audit.h                      |   7 +-
>  kernel/audit_tree.c                 |   3 +-
>  kernel/audit_watch.c                |   3 +-
>  kernel/auditfilter.c                |  15 +-
>  kernel/auditsc.c                    | 483 +++++++++++++++++++-----
>  security/security.c                 |  12 +
>  security/selinux/hooks.c            |  34 ++
>  security/selinux/include/classmap.h |   2 +
>  security/smack/smack_lsm.c          |  64 ++++
>  18 files changed, 678 insertions(+), 115 deletions(-)
> 

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-24 20:57 ` [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Richard Guy Briggs
@ 2021-08-24 22:27   ` Paul Moore
  2021-08-25  1:36     ` Richard Guy Briggs
  2021-08-26  1:16   ` Richard Guy Briggs
  1 sibling, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-24 22:27 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

[-- Attachment #1: Type: text/plain, Size: 1345 bytes --]

On Tue, Aug 24, 2021 at 4:57 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> Thanks for the tests.  I have a bunch of userspace patches to add to the
> last set I posted and these tests will help exercise them.  I also have
> one more kernel patch to post...  I'll dive back into that now.  I had
> wanted to post them before now but got distracted with AUDIT_TRIM
> breakage.

If it helps, last week I started working on a little test tool for the
audit-testsuite and selinux-testsuite (see attached).  It may not be
final, but I don't expect too many changes to it before I post the
test suite patches; it is definitely usable now.  It's inspired by the
previous tests, but it uses a much more test suite friendly fork/exec
model for testing the sharing of io_urings across process boundaries.

Would you mind sharing your latest userspace patches, if not publicly
I would be okay with privately off-list; I'm putting together the test
suite patches this week and it would be good to make sure I'm using
your latest take on the userspace changes.

Also, what is the kernel patch?  Did you find a bug or is this some
new functionality you think might be useful?  Both can be important,
but the bug is *really* important; even if you don't have a fix for
that, just a description of the problem would be good.

-- 
paul moore
www.paul-moore.com

[-- Attachment #2: iouring.4.c --]
[-- Type: text/x-csrc, Size: 15303 bytes --]

/*
 * io_uring test tool to exercise LSM/SELinux and audit kernel code paths
 * Author: Paul Moore <paul@paul-moore.com>
 *
 * Copyright 2021 Microsoft Corporation
 *
 * At the time this code was written the best, and most current, source of info
 * on io_uring seemed to be the liburing sources themselves (link below).  The
 * code below is based on the lessons learned from looking at the liburing
 * code.
 *
 * -> https://github.com/axboe/liburing
 *
 * The liburing LICENSE file contains the following:
 *
 * Copyright 2020 Jens Axboe
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

/*
 * BUILDING:
 *
 * gcc -o <binary> -g -O0 -luring -lrt <source>
 *
 * RUNNING:
 *
 * The program can be run using the following command lines:
 *
 *  % prog sqpoll
 * ... this invocation runs the io_uring SQPOLL test.
 *
 *  % prog t1
 * ... this invocation runs the parent/child io_uring sharing test.
 *
 *  % prog t1 <domain>
 * ... this invocation runs the parent/child io_uring sharing test with the
 * child process run in the specified SELinux domain.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <liburing.h>

struct urt_config {
	struct io_uring ring;
	struct io_uring_params ring_params;
	int ring_creds;
};

#define URING_ENTRIES				8
#define URING_SHM_NAME				"/iouring_test_4"

int selinux_state = -1;
#define SELINUX_CTX_MAX				512
char selinux_ctx[SELINUX_CTX_MAX] = "\0";

/**
 * Display an error message and exit
 * @param msg the error message
 *
 * Output @msg to stderr and exit with errno as the exit value.
 */
void fatal(const char *msg)
{
	const char *str = (msg ? msg : "unknown");

	if (!errno) {
		errno = 1;
		fprintf(stderr, "%s: unknown error\n", msg);
	} else
		perror(str);

	if (errno < 0)
		exit(-errno);
	exit(errno);
}

/**
 * Determine if SELinux is enabled and set the internal state
 *
 * Attempt to read from /proc/self/attr/current and determine if SELinux is
 * enabled, store the current context/domain in @selinux_ctx if SELinux is
 * enabled.  We avoid using the libselinux API in order to increase portability
 * and make it easier for other LSMs to adopt this test.
 */
int selinux_enabled(void)
{
	int fd = -1;
	ssize_t ctx_len;
	char ctx[SELINUX_CTX_MAX];

	if (selinux_state >= 0)
		return selinux_state;

	/* attempt to get the current context */
	fd = open("/proc/self/attr/current", O_RDONLY);
	if (fd < 0)
		goto err;
	ctx_len = read(fd, ctx, SELINUX_CTX_MAX - 1);
	if (ctx_len <= 0)
		goto err;
	close(fd);

	/* save the current context */
	ctx[ctx_len] = '\0';
	strcpy(selinux_ctx, ctx);

	selinux_state = 1;
	return selinux_state;

err:
	if (fd >= 0)
		close(fd);

	selinux_state = 0;
	return selinux_state;
}

/**
 * Return the current SELinux domain or "DISABLED" if SELinux is not enabled
 *
 * The returned string should not be free()'d.
 */
const char *selinux_current(void)
{
	int rc;

	rc = selinux_enabled();
	if (!rc)
		return "DISABLED";

	return selinux_ctx;
}

/**
 * Set the SELinux domain for the next exec()'d process
 * @param ctx the SELinux domain
 *
 * This is similar to the setexeccon() libselinux API but we do it manually to
 * help increase portability and make it easier for other LSMs to adopt this
 * test.
 */
int selinux_exec(const char *ctx)
{
	int fd = -1;
	ssize_t len;

	if (!ctx)
		return -EINVAL;

	fd = open("/proc/self/attr/exec", O_WRONLY);
	if (fd < 0)
		return -errno;
	len = write(fd, ctx, strlen(ctx) + 1);
	close(fd);

	return len;
}

/**
 * Setup the io_uring
 * @param ring the io_uring pointer
 * @param params the io_uring parameters
 * @param creds pointer to the current process' registered io_uring personality
 *
 * Create a new io_uring using @params and return it in @ring with the
 * registered personality returned in @creds.  Returns 0 on success, negative
 * values on failure.
 */
int uring_setup(struct io_uring *ring,
		struct io_uring_params *params, int *creds)
{
	int rc;

	/* call into liburing to do the setup heavy lifting */
	rc = io_uring_queue_init_params(URING_ENTRIES, ring, params);
	if (rc < 0)
		fatal("io_uring_queue_init_params");

	/* register our creds/personality */
	rc = io_uring_register_personality(ring);
	if (rc < 0)
		fatal("io_uring_register_personality()");
	*creds = rc;
	rc = 0;

	printf(">>> io_uring created; fd = %d, personality = %d\n",
	       ring->ring_fd, *creds);

	return rc;
}

/**
 * Import an existing io_uring based on the given file descriptor
 * @param fd the io_uring's file descriptor
 * @param ring the io_uring pointer
 * @param params the io_uring parameters
 *
 * This function takes an io_uring file descriptor in @fd as well as the
 * io_uring parameters in @params and creates a valid io_uring in @ring.
 * Returns 0 on success, negative values on failure.
 */
int uring_import(int fd, struct io_uring *ring, struct io_uring_params *params)
{
	int rc;

	memset(ring, 0, sizeof(*ring));
	ring->flags = params->flags;
	ring->features = params->features;
	ring->ring_fd = fd;

	ring->sq.ring_sz = params->sq_off.array +
			   params->sq_entries * sizeof(unsigned);
	ring->cq.ring_sz = params->cq_off.cqes +
			   params->cq_entries * sizeof(struct io_uring_cqe);

	ring->sq.ring_ptr = mmap(NULL, ring->sq.ring_sz, PROT_READ | PROT_WRITE,
				 MAP_SHARED | MAP_POPULATE, fd,
				 IORING_OFF_SQ_RING);
	if (ring->sq.ring_ptr == MAP_FAILED)
		fatal("import mmap(ring)");

	ring->cq.ring_ptr = mmap(0, ring->cq.ring_sz, PROT_READ | PROT_WRITE,
				 MAP_SHARED | MAP_POPULATE,
				 fd, IORING_OFF_CQ_RING);
	if (ring->cq.ring_ptr == MAP_FAILED) {
		ring->cq.ring_ptr = NULL;
		goto err;
	}

	ring->sq.khead = ring->sq.ring_ptr + params->sq_off.head;
	ring->sq.ktail = ring->sq.ring_ptr + params->sq_off.tail;
	ring->sq.kring_mask = ring->sq.ring_ptr + params->sq_off.ring_mask;
	ring->sq.kring_entries = ring->sq.ring_ptr +
				 params->sq_off.ring_entries;
	ring->sq.kflags = ring->sq.ring_ptr + params->sq_off.flags;
	ring->sq.kdropped = ring->sq.ring_ptr + params->sq_off.dropped;
	ring->sq.array = ring->sq.ring_ptr + params->sq_off.array;

	ring->sq.sqes = mmap(NULL,
			     params->sq_entries * sizeof(struct io_uring_sqe),
			     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
			     fd, IORING_OFF_SQES);
	if (ring->sq.sqes == MAP_FAILED)
		goto err;

	ring->cq.khead = ring->cq.ring_ptr + params->cq_off.head;
	ring->cq.ktail = ring->cq.ring_ptr + params->cq_off.tail;
	ring->cq.kring_mask = ring->cq.ring_ptr + params->cq_off.ring_mask;
	ring->cq.kring_entries = ring->cq.ring_ptr +
				 params->cq_off.ring_entries;
	ring->cq.koverflow = ring->cq.ring_ptr + params->cq_off.overflow;
	ring->cq.cqes = ring->cq.ring_ptr + params->cq_off.cqes;
	if (params->cq_off.flags)
		ring->cq.kflags = ring->cq.ring_ptr + params->cq_off.flags;

	return 0;

err:
	if (ring->sq.ring_ptr)
		munmap(ring->sq.ring_ptr, ring->sq.ring_sz);
	if (ring->cq.ring_ptr);
		munmap(ring->cq.ring_ptr, ring->cq.ring_sz);
	fatal("import mmap");
}

void uring_shutdown(struct io_uring *ring)
{
	if (!ring)
		return;
	io_uring_queue_exit(ring);
}

/**
 * An io_uring test
 * @param ring the io_uring pointer
 * @param personality the registered personality to use or 0
 * @param path the file path to use for the test
 *
 * This function executes an io_uring test, see the function body for more
 * details.  Returns 0 on success, negative values on failure.
 */
int uring_op_a(struct io_uring *ring, int personality, const char *path)
{

#define __OP_A_BSIZE		512
#define __OP_A_STR		"Lorem ipsum dolor sit amet.\n"

	int rc;
	int fds[1];
	char buf1[__OP_A_BSIZE];
	char buf2[__OP_A_BSIZE];
	struct io_uring_sqe *sqe;
	struct io_uring_cqe *cqe;
	int str_sz = strlen(__OP_A_STR);

	memset(buf1, 0, __OP_A_BSIZE);
	memset(buf2, 0, __OP_A_BSIZE);
	strncpy(buf1, __OP_A_STR, str_sz);

	if (personality > 0)
		printf(">>> io_uring ops using personality = %d\n",
		       personality);

	/*
	 * open
	 */

	sqe = io_uring_get_sqe(ring);
	if (!sqe)
		fatal("io_uring_get_sqe(open)");
	io_uring_prep_openat(sqe, AT_FDCWD, path,
			     O_RDWR | O_TRUNC | O_CREAT, 0644);
	if (personality > 0)
		sqe->personality = personality;

	rc = io_uring_submit(ring);
	if (rc < 0)
		fatal("io_uring_submit(open)");

	rc = io_uring_wait_cqe(ring, &cqe);
	fds[0] = cqe->res;
	if (rc < 0)
		fatal("io_uring_wait_cqe(open)");
	if (fds[0] < 0)
		fatal("uring_open");
	io_uring_cqe_seen(ring, cqe);

	rc = io_uring_register_files(ring, fds, 1);
	if(rc)
		fatal("io_uring_register_files");

	printf(">>> io_uring open(): OK\n");

	/*
	 * write
	 */

	sqe = io_uring_get_sqe(ring);
	if (!sqe)
		fatal("io_uring_get_sqe(write1)");
	io_uring_prep_write(sqe, 0, buf1, str_sz, 0);
	io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
	if (personality > 0)
		sqe->personality = personality;

	rc = io_uring_submit(ring);
	if (rc < 0)
		fatal("io_uring_submit(write)");

	rc = io_uring_wait_cqe(ring, &cqe);
	if (rc < 0)
		fatal("io_uring_wait_cqe(write)");
	if (cqe->res < 0)
		fatal("uring_write");
	if (cqe->res != str_sz)
		fatal("uring_write(length)");
	io_uring_cqe_seen(ring, cqe);

	printf(">>> io_uring write(): OK\n");

	/*
	 * read
	 */

	sqe = io_uring_get_sqe(ring);
	if (!sqe)
		fatal("io_uring_get_sqe(read1)");
	io_uring_prep_read(sqe, 0, buf2,__OP_A_BSIZE, 0);
	io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
	if (personality > 0)
		sqe->personality = personality;

	rc = io_uring_submit(ring);
	if (rc < 0)
		fatal("io_uring_submit(read)");

	rc = io_uring_wait_cqe(ring, &cqe);
	if (rc < 0)
		fatal("io_uring_wait_cqe(read)");
	if (cqe->res < 0)
		fatal("uring_read");
	if (cqe->res != str_sz)
		fatal("uring_read(length)");
	io_uring_cqe_seen(ring, cqe);

	if (strncmp(buf1, buf2, str_sz))
		fatal("strncmp(buf1,buf2)");

	printf(">>> io_uring read(): OK\n");

	/*
	 * close
	 */

	sqe = io_uring_get_sqe(ring);
	if (!sqe)
		fatal("io_uring_get_sqe(close)");
	io_uring_prep_close(sqe, 0);
	if (personality > 0)
		sqe->personality = personality;

	rc = io_uring_submit(ring);
	if (rc < 0)
		fatal("io_uring_submit(close)");

	rc = io_uring_wait_cqe(ring, &cqe);
	if (rc < 0)
		fatal("io_uring_wait_cqe(close)");
	if (cqe->res < 0)
		fatal("uring_close");
	io_uring_cqe_seen(ring, cqe);

	rc = io_uring_unregister_files(ring);
	if (rc < 0)
		fatal("io_uring_unregister_files");

	printf(">>> io_uring close(): OK\n");

	return 0;
}

/**
 * The main entrypoint to the test program
 * @param argc number of command line options
 * @param argv the command line options array
 */
int main(int argc, char *argv[])
{
	int rc = 1;
	int ring_shm_fd;
	struct io_uring ring_storage, *ring;
	struct urt_config *cfg_p;

	enum { TST_UNKNOWN,
	       TST_SQPOLL,
	       TST_T1_PARENT, TST_T1_CHILD } tst_method;

	/* parse the command line and do some sanity checks */
	tst_method = TST_UNKNOWN;
	if (argc >= 2) {
		if (!strcmp(argv[1], "sqpoll"))
			tst_method = TST_SQPOLL;
		else if (!strcmp(argv[1], "t1") ||
			 !strcmp(argv[1], "t1_parent"))
			tst_method = TST_T1_PARENT;
		else if (!strcmp(argv[1], "t1_child"))
			tst_method = TST_T1_CHILD;
	}
	if (tst_method == TST_UNKNOWN) {
		fprintf(stderr, "usage: %s <method> ... \n", argv[0]);
		exit(EINVAL);
	}

	/* simple header */
	printf(">>> running as PID = %d\n", getpid());
	printf(">>> LSM/SELinux = %s\n", selinux_current());

	/*
	 * test setup (if necessary)
	 */
	if (tst_method == TST_SQPOLL || tst_method == TST_T1_PARENT) {
		 /* create an io_uring and prepare it for optional sharing */
		int flags;

		/* create a shm segment to hold the io_uring info */
		ring_shm_fd = shm_open(URING_SHM_NAME, O_CREAT | O_RDWR,
				       S_IRUSR | S_IWUSR);
		if (ring_shm_fd < 0)
			fatal("shm_open(create)");

		rc = ftruncate(ring_shm_fd, sizeof(struct urt_config));
		if (rc < 0)
			fatal("ftruncate(shm)");

		cfg_p = mmap(NULL, sizeof(*cfg_p), PROT_READ | PROT_WRITE,
			     MAP_SHARED, ring_shm_fd, 0);
		if (!cfg_p)
			fatal("mmap(shm)");

		/* create the io_uring */
		memset(&cfg_p->ring, 0, sizeof(cfg_p->ring));
		memset(&cfg_p->ring_params, 0, sizeof(cfg_p->ring_params));
		if (tst_method == TST_SQPOLL)
			cfg_p->ring_params.flags |= IORING_SETUP_SQPOLL;
		rc = uring_setup(&cfg_p->ring, &cfg_p->ring_params,
				 &cfg_p->ring_creds);
		if (rc)
			fatal("uring_setup");
		ring = &cfg_p->ring;

		/* explicitly clear FD_CLOEXEC on the io_uring */
		flags = fcntl(cfg_p->ring.ring_fd, F_GETFD, 0);
		if (flags < 0)
			fatal("fcntl(ring_shm_fd,getfd)");
		flags &= ~FD_CLOEXEC;
		rc = fcntl(cfg_p->ring.ring_fd, F_SETFD, flags);
		if (rc)
			fatal("fcntl(ring_shm_fd,setfd)");
	} else if (tst_method = TST_T1_CHILD) {
		/* import a previously created and shared io_uring */

		/* open the existing shm segment with the io_uring info */
		ring_shm_fd = shm_open(URING_SHM_NAME, O_RDWR, 0);
		if (ring_shm_fd < 0)
			fatal("shm_open(existing)");
		cfg_p = mmap(NULL, sizeof(*cfg_p), PROT_READ | PROT_WRITE,
			     MAP_SHARED, ring_shm_fd, 0);
		if (!cfg_p)
			fatal("mmap(shm)");

		/* import the io_uring */
		ring = &ring_storage;
		rc = uring_import(cfg_p->ring.ring_fd,
				  ring, &cfg_p->ring_params);
		if (rc < 0)
			fatal("uring_import");
	}

	/*
	 * fork/exec a child process (if necessary)
	 */
	if (tst_method == TST_T1_PARENT) {
		pid_t pid;

		/* set the ctx for the next exec */
		if (argc >= 3) {
			printf(">>> set LSM/SELinux exec: %s\n",
			       (selinux_exec(argv[2]) > 0 ? "OK" : "FAILED"));
		}

		/* fork/exec */
		pid = fork();
		if (!pid) {
			/* start the child */
			rc = execl(argv[0], argv[0], "t1_child", (char *)NULL);
			if (rc < 0)
				fatal("exec");
		} else {
			/* wait for the child to exit */
			int status;
			waitpid(pid, &status, 0);
			if (WIFEXITED(status))
				rc = WEXITSTATUS(status);
		}
	}

	/*
	 * run test(s)
	 */
	if (tst_method == TST_SQPOLL || tst_method == TST_T1_CHILD) {
		rc = uring_op_a(ring, cfg_p->ring_creds, "/tmp/iouring.4.txt");
		if (rc < 0)
			fatal("uring_op_a(\"/tmp/iouring.4.txt\")");
	}

	/*
	 * cleanup
	 */
	if (tst_method == TST_SQPOLL || tst_method == TST_T1_PARENT) {
		printf(">>> shutdown\n");
		uring_shutdown(&cfg_p->ring);
		shm_unlink(URING_SHM_NAME);
	} else if (tst_method == TST_T1_CHILD) {
		shm_unlink(URING_SHM_NAME);
	}

	return rc;
}

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-24 22:27   ` Paul Moore
@ 2021-08-25  1:36     ` Richard Guy Briggs
  0 siblings, 0 replies; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-25  1:36 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-08-24 18:27, Paul Moore wrote:
> On Tue, Aug 24, 2021 at 4:57 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > Thanks for the tests.  I have a bunch of userspace patches to add to the
> > last set I posted and these tests will help exercise them.  I also have
> > one more kernel patch to post...  I'll dive back into that now.  I had
> > wanted to post them before now but got distracted with AUDIT_TRIM
> > breakage.
> 
> If it helps, last week I started working on a little test tool for the
> audit-testsuite and selinux-testsuite (see attached).  It may not be
> final, but I don't expect too many changes to it before I post the
> test suite patches; it is definitely usable now.  It's inspired by the
> previous tests, but it uses a much more test suite friendly fork/exec
> model for testing the sharing of io_urings across process boundaries.
> 
> Would you mind sharing your latest userspace patches, if not publicly
> I would be okay with privately off-list; I'm putting together the test
> suite patches this week and it would be good to make sure I'm using
> your latest take on the userspace changes.

I intend to publish them but they need squashing and some documentation
first.  And a run through with io_uring specific tests would be good to
catch anything obvious...

> Also, what is the kernel patch?  Did you find a bug or is this some
> new functionality you think might be useful?  Both can be important,
> but the bug is *really* important; even if you don't have a fix for
> that, just a description of the problem would be good.

It was a very small patch that I realize I had already talked about and
you justified not including sessionid along with auid.  That was
addressed in a reply tacked on to your v1 patchset just now.

> paul moore

> /*
>  * io_uring test tool to exercise LSM/SELinux and audit kernel code paths
>  * Author: Paul Moore <paul@paul-moore.com>
>  *
>  * Copyright 2021 Microsoft Corporation
>  *
>  * At the time this code was written the best, and most current, source of info
>  * on io_uring seemed to be the liburing sources themselves (link below).  The
>  * code below is based on the lessons learned from looking at the liburing
>  * code.
>  *
>  * -> https://github.com/axboe/liburing
>  *
>  * The liburing LICENSE file contains the following:
>  *
>  * Copyright 2020 Jens Axboe
>  *
>  * Permission is hereby granted, free of charge, to any person obtaining a copy
>  * of this software and associated documentation files (the "Software"), to
>  * deal in the Software without restriction, including without limitation the
>  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
>  * sell copies of the Software, and to permit persons to whom the Software is
>  * furnished to do so, subject to the following conditions:
>  *
>  *  The above copyright notice and this permission notice shall be included in
>  *  all copies or substantial portions of the Software.
>  *
>  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>  *  DEALINGS IN THE SOFTWARE.
>  *
>  */
> 
> /*
>  * BUILDING:
>  *
>  * gcc -o <binary> -g -O0 -luring -lrt <source>
>  *
>  * RUNNING:
>  *
>  * The program can be run using the following command lines:
>  *
>  *  % prog sqpoll
>  * ... this invocation runs the io_uring SQPOLL test.
>  *
>  *  % prog t1
>  * ... this invocation runs the parent/child io_uring sharing test.
>  *
>  *  % prog t1 <domain>
>  * ... this invocation runs the parent/child io_uring sharing test with the
>  * child process run in the specified SELinux domain.
>  *
>  */
> 
> #include <stdlib.h>
> #include <stdio.h>
> #include <errno.h>
> #include <string.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <sys/mman.h>
> #include <sys/stat.h>
> #include <sys/wait.h>
> 
> #include <liburing.h>
> 
> struct urt_config {
> 	struct io_uring ring;
> 	struct io_uring_params ring_params;
> 	int ring_creds;
> };
> 
> #define URING_ENTRIES				8
> #define URING_SHM_NAME				"/iouring_test_4"
> 
> int selinux_state = -1;
> #define SELINUX_CTX_MAX				512
> char selinux_ctx[SELINUX_CTX_MAX] = "\0";
> 
> /**
>  * Display an error message and exit
>  * @param msg the error message
>  *
>  * Output @msg to stderr and exit with errno as the exit value.
>  */
> void fatal(const char *msg)
> {
> 	const char *str = (msg ? msg : "unknown");
> 
> 	if (!errno) {
> 		errno = 1;
> 		fprintf(stderr, "%s: unknown error\n", msg);
> 	} else
> 		perror(str);
> 
> 	if (errno < 0)
> 		exit(-errno);
> 	exit(errno);
> }
> 
> /**
>  * Determine if SELinux is enabled and set the internal state
>  *
>  * Attempt to read from /proc/self/attr/current and determine if SELinux is
>  * enabled, store the current context/domain in @selinux_ctx if SELinux is
>  * enabled.  We avoid using the libselinux API in order to increase portability
>  * and make it easier for other LSMs to adopt this test.
>  */
> int selinux_enabled(void)
> {
> 	int fd = -1;
> 	ssize_t ctx_len;
> 	char ctx[SELINUX_CTX_MAX];
> 
> 	if (selinux_state >= 0)
> 		return selinux_state;
> 
> 	/* attempt to get the current context */
> 	fd = open("/proc/self/attr/current", O_RDONLY);
> 	if (fd < 0)
> 		goto err;
> 	ctx_len = read(fd, ctx, SELINUX_CTX_MAX - 1);
> 	if (ctx_len <= 0)
> 		goto err;
> 	close(fd);
> 
> 	/* save the current context */
> 	ctx[ctx_len] = '\0';
> 	strcpy(selinux_ctx, ctx);
> 
> 	selinux_state = 1;
> 	return selinux_state;
> 
> err:
> 	if (fd >= 0)
> 		close(fd);
> 
> 	selinux_state = 0;
> 	return selinux_state;
> }
> 
> /**
>  * Return the current SELinux domain or "DISABLED" if SELinux is not enabled
>  *
>  * The returned string should not be free()'d.
>  */
> const char *selinux_current(void)
> {
> 	int rc;
> 
> 	rc = selinux_enabled();
> 	if (!rc)
> 		return "DISABLED";
> 
> 	return selinux_ctx;
> }
> 
> /**
>  * Set the SELinux domain for the next exec()'d process
>  * @param ctx the SELinux domain
>  *
>  * This is similar to the setexeccon() libselinux API but we do it manually to
>  * help increase portability and make it easier for other LSMs to adopt this
>  * test.
>  */
> int selinux_exec(const char *ctx)
> {
> 	int fd = -1;
> 	ssize_t len;
> 
> 	if (!ctx)
> 		return -EINVAL;
> 
> 	fd = open("/proc/self/attr/exec", O_WRONLY);
> 	if (fd < 0)
> 		return -errno;
> 	len = write(fd, ctx, strlen(ctx) + 1);
> 	close(fd);
> 
> 	return len;
> }
> 
> /**
>  * Setup the io_uring
>  * @param ring the io_uring pointer
>  * @param params the io_uring parameters
>  * @param creds pointer to the current process' registered io_uring personality
>  *
>  * Create a new io_uring using @params and return it in @ring with the
>  * registered personality returned in @creds.  Returns 0 on success, negative
>  * values on failure.
>  */
> int uring_setup(struct io_uring *ring,
> 		struct io_uring_params *params, int *creds)
> {
> 	int rc;
> 
> 	/* call into liburing to do the setup heavy lifting */
> 	rc = io_uring_queue_init_params(URING_ENTRIES, ring, params);
> 	if (rc < 0)
> 		fatal("io_uring_queue_init_params");
> 
> 	/* register our creds/personality */
> 	rc = io_uring_register_personality(ring);
> 	if (rc < 0)
> 		fatal("io_uring_register_personality()");
> 	*creds = rc;
> 	rc = 0;
> 
> 	printf(">>> io_uring created; fd = %d, personality = %d\n",
> 	       ring->ring_fd, *creds);
> 
> 	return rc;
> }
> 
> /**
>  * Import an existing io_uring based on the given file descriptor
>  * @param fd the io_uring's file descriptor
>  * @param ring the io_uring pointer
>  * @param params the io_uring parameters
>  *
>  * This function takes an io_uring file descriptor in @fd as well as the
>  * io_uring parameters in @params and creates a valid io_uring in @ring.
>  * Returns 0 on success, negative values on failure.
>  */
> int uring_import(int fd, struct io_uring *ring, struct io_uring_params *params)
> {
> 	int rc;
> 
> 	memset(ring, 0, sizeof(*ring));
> 	ring->flags = params->flags;
> 	ring->features = params->features;
> 	ring->ring_fd = fd;
> 
> 	ring->sq.ring_sz = params->sq_off.array +
> 			   params->sq_entries * sizeof(unsigned);
> 	ring->cq.ring_sz = params->cq_off.cqes +
> 			   params->cq_entries * sizeof(struct io_uring_cqe);
> 
> 	ring->sq.ring_ptr = mmap(NULL, ring->sq.ring_sz, PROT_READ | PROT_WRITE,
> 				 MAP_SHARED | MAP_POPULATE, fd,
> 				 IORING_OFF_SQ_RING);
> 	if (ring->sq.ring_ptr == MAP_FAILED)
> 		fatal("import mmap(ring)");
> 
> 	ring->cq.ring_ptr = mmap(0, ring->cq.ring_sz, PROT_READ | PROT_WRITE,
> 				 MAP_SHARED | MAP_POPULATE,
> 				 fd, IORING_OFF_CQ_RING);
> 	if (ring->cq.ring_ptr == MAP_FAILED) {
> 		ring->cq.ring_ptr = NULL;
> 		goto err;
> 	}
> 
> 	ring->sq.khead = ring->sq.ring_ptr + params->sq_off.head;
> 	ring->sq.ktail = ring->sq.ring_ptr + params->sq_off.tail;
> 	ring->sq.kring_mask = ring->sq.ring_ptr + params->sq_off.ring_mask;
> 	ring->sq.kring_entries = ring->sq.ring_ptr +
> 				 params->sq_off.ring_entries;
> 	ring->sq.kflags = ring->sq.ring_ptr + params->sq_off.flags;
> 	ring->sq.kdropped = ring->sq.ring_ptr + params->sq_off.dropped;
> 	ring->sq.array = ring->sq.ring_ptr + params->sq_off.array;
> 
> 	ring->sq.sqes = mmap(NULL,
> 			     params->sq_entries * sizeof(struct io_uring_sqe),
> 			     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
> 			     fd, IORING_OFF_SQES);
> 	if (ring->sq.sqes == MAP_FAILED)
> 		goto err;
> 
> 	ring->cq.khead = ring->cq.ring_ptr + params->cq_off.head;
> 	ring->cq.ktail = ring->cq.ring_ptr + params->cq_off.tail;
> 	ring->cq.kring_mask = ring->cq.ring_ptr + params->cq_off.ring_mask;
> 	ring->cq.kring_entries = ring->cq.ring_ptr +
> 				 params->cq_off.ring_entries;
> 	ring->cq.koverflow = ring->cq.ring_ptr + params->cq_off.overflow;
> 	ring->cq.cqes = ring->cq.ring_ptr + params->cq_off.cqes;
> 	if (params->cq_off.flags)
> 		ring->cq.kflags = ring->cq.ring_ptr + params->cq_off.flags;
> 
> 	return 0;
> 
> err:
> 	if (ring->sq.ring_ptr)
> 		munmap(ring->sq.ring_ptr, ring->sq.ring_sz);
> 	if (ring->cq.ring_ptr);
> 		munmap(ring->cq.ring_ptr, ring->cq.ring_sz);
> 	fatal("import mmap");
> }
> 
> void uring_shutdown(struct io_uring *ring)
> {
> 	if (!ring)
> 		return;
> 	io_uring_queue_exit(ring);
> }
> 
> /**
>  * An io_uring test
>  * @param ring the io_uring pointer
>  * @param personality the registered personality to use or 0
>  * @param path the file path to use for the test
>  *
>  * This function executes an io_uring test, see the function body for more
>  * details.  Returns 0 on success, negative values on failure.
>  */
> int uring_op_a(struct io_uring *ring, int personality, const char *path)
> {
> 
> #define __OP_A_BSIZE		512
> #define __OP_A_STR		"Lorem ipsum dolor sit amet.\n"
> 
> 	int rc;
> 	int fds[1];
> 	char buf1[__OP_A_BSIZE];
> 	char buf2[__OP_A_BSIZE];
> 	struct io_uring_sqe *sqe;
> 	struct io_uring_cqe *cqe;
> 	int str_sz = strlen(__OP_A_STR);
> 
> 	memset(buf1, 0, __OP_A_BSIZE);
> 	memset(buf2, 0, __OP_A_BSIZE);
> 	strncpy(buf1, __OP_A_STR, str_sz);
> 
> 	if (personality > 0)
> 		printf(">>> io_uring ops using personality = %d\n",
> 		       personality);
> 
> 	/*
> 	 * open
> 	 */
> 
> 	sqe = io_uring_get_sqe(ring);
> 	if (!sqe)
> 		fatal("io_uring_get_sqe(open)");
> 	io_uring_prep_openat(sqe, AT_FDCWD, path,
> 			     O_RDWR | O_TRUNC | O_CREAT, 0644);
> 	if (personality > 0)
> 		sqe->personality = personality;
> 
> 	rc = io_uring_submit(ring);
> 	if (rc < 0)
> 		fatal("io_uring_submit(open)");
> 
> 	rc = io_uring_wait_cqe(ring, &cqe);
> 	fds[0] = cqe->res;
> 	if (rc < 0)
> 		fatal("io_uring_wait_cqe(open)");
> 	if (fds[0] < 0)
> 		fatal("uring_open");
> 	io_uring_cqe_seen(ring, cqe);
> 
> 	rc = io_uring_register_files(ring, fds, 1);
> 	if(rc)
> 		fatal("io_uring_register_files");
> 
> 	printf(">>> io_uring open(): OK\n");
> 
> 	/*
> 	 * write
> 	 */
> 
> 	sqe = io_uring_get_sqe(ring);
> 	if (!sqe)
> 		fatal("io_uring_get_sqe(write1)");
> 	io_uring_prep_write(sqe, 0, buf1, str_sz, 0);
> 	io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
> 	if (personality > 0)
> 		sqe->personality = personality;
> 
> 	rc = io_uring_submit(ring);
> 	if (rc < 0)
> 		fatal("io_uring_submit(write)");
> 
> 	rc = io_uring_wait_cqe(ring, &cqe);
> 	if (rc < 0)
> 		fatal("io_uring_wait_cqe(write)");
> 	if (cqe->res < 0)
> 		fatal("uring_write");
> 	if (cqe->res != str_sz)
> 		fatal("uring_write(length)");
> 	io_uring_cqe_seen(ring, cqe);
> 
> 	printf(">>> io_uring write(): OK\n");
> 
> 	/*
> 	 * read
> 	 */
> 
> 	sqe = io_uring_get_sqe(ring);
> 	if (!sqe)
> 		fatal("io_uring_get_sqe(read1)");
> 	io_uring_prep_read(sqe, 0, buf2,__OP_A_BSIZE, 0);
> 	io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
> 	if (personality > 0)
> 		sqe->personality = personality;
> 
> 	rc = io_uring_submit(ring);
> 	if (rc < 0)
> 		fatal("io_uring_submit(read)");
> 
> 	rc = io_uring_wait_cqe(ring, &cqe);
> 	if (rc < 0)
> 		fatal("io_uring_wait_cqe(read)");
> 	if (cqe->res < 0)
> 		fatal("uring_read");
> 	if (cqe->res != str_sz)
> 		fatal("uring_read(length)");
> 	io_uring_cqe_seen(ring, cqe);
> 
> 	if (strncmp(buf1, buf2, str_sz))
> 		fatal("strncmp(buf1,buf2)");
> 
> 	printf(">>> io_uring read(): OK\n");
> 
> 	/*
> 	 * close
> 	 */
> 
> 	sqe = io_uring_get_sqe(ring);
> 	if (!sqe)
> 		fatal("io_uring_get_sqe(close)");
> 	io_uring_prep_close(sqe, 0);
> 	if (personality > 0)
> 		sqe->personality = personality;
> 
> 	rc = io_uring_submit(ring);
> 	if (rc < 0)
> 		fatal("io_uring_submit(close)");
> 
> 	rc = io_uring_wait_cqe(ring, &cqe);
> 	if (rc < 0)
> 		fatal("io_uring_wait_cqe(close)");
> 	if (cqe->res < 0)
> 		fatal("uring_close");
> 	io_uring_cqe_seen(ring, cqe);
> 
> 	rc = io_uring_unregister_files(ring);
> 	if (rc < 0)
> 		fatal("io_uring_unregister_files");
> 
> 	printf(">>> io_uring close(): OK\n");
> 
> 	return 0;
> }
> 
> /**
>  * The main entrypoint to the test program
>  * @param argc number of command line options
>  * @param argv the command line options array
>  */
> int main(int argc, char *argv[])
> {
> 	int rc = 1;
> 	int ring_shm_fd;
> 	struct io_uring ring_storage, *ring;
> 	struct urt_config *cfg_p;
> 
> 	enum { TST_UNKNOWN,
> 	       TST_SQPOLL,
> 	       TST_T1_PARENT, TST_T1_CHILD } tst_method;
> 
> 	/* parse the command line and do some sanity checks */
> 	tst_method = TST_UNKNOWN;
> 	if (argc >= 2) {
> 		if (!strcmp(argv[1], "sqpoll"))
> 			tst_method = TST_SQPOLL;
> 		else if (!strcmp(argv[1], "t1") ||
> 			 !strcmp(argv[1], "t1_parent"))
> 			tst_method = TST_T1_PARENT;
> 		else if (!strcmp(argv[1], "t1_child"))
> 			tst_method = TST_T1_CHILD;
> 	}
> 	if (tst_method == TST_UNKNOWN) {
> 		fprintf(stderr, "usage: %s <method> ... \n", argv[0]);
> 		exit(EINVAL);
> 	}
> 
> 	/* simple header */
> 	printf(">>> running as PID = %d\n", getpid());
> 	printf(">>> LSM/SELinux = %s\n", selinux_current());
> 
> 	/*
> 	 * test setup (if necessary)
> 	 */
> 	if (tst_method == TST_SQPOLL || tst_method == TST_T1_PARENT) {
> 		 /* create an io_uring and prepare it for optional sharing */
> 		int flags;
> 
> 		/* create a shm segment to hold the io_uring info */
> 		ring_shm_fd = shm_open(URING_SHM_NAME, O_CREAT | O_RDWR,
> 				       S_IRUSR | S_IWUSR);
> 		if (ring_shm_fd < 0)
> 			fatal("shm_open(create)");
> 
> 		rc = ftruncate(ring_shm_fd, sizeof(struct urt_config));
> 		if (rc < 0)
> 			fatal("ftruncate(shm)");
> 
> 		cfg_p = mmap(NULL, sizeof(*cfg_p), PROT_READ | PROT_WRITE,
> 			     MAP_SHARED, ring_shm_fd, 0);
> 		if (!cfg_p)
> 			fatal("mmap(shm)");
> 
> 		/* create the io_uring */
> 		memset(&cfg_p->ring, 0, sizeof(cfg_p->ring));
> 		memset(&cfg_p->ring_params, 0, sizeof(cfg_p->ring_params));
> 		if (tst_method == TST_SQPOLL)
> 			cfg_p->ring_params.flags |= IORING_SETUP_SQPOLL;
> 		rc = uring_setup(&cfg_p->ring, &cfg_p->ring_params,
> 				 &cfg_p->ring_creds);
> 		if (rc)
> 			fatal("uring_setup");
> 		ring = &cfg_p->ring;
> 
> 		/* explicitly clear FD_CLOEXEC on the io_uring */
> 		flags = fcntl(cfg_p->ring.ring_fd, F_GETFD, 0);
> 		if (flags < 0)
> 			fatal("fcntl(ring_shm_fd,getfd)");
> 		flags &= ~FD_CLOEXEC;
> 		rc = fcntl(cfg_p->ring.ring_fd, F_SETFD, flags);
> 		if (rc)
> 			fatal("fcntl(ring_shm_fd,setfd)");
> 	} else if (tst_method = TST_T1_CHILD) {
> 		/* import a previously created and shared io_uring */
> 
> 		/* open the existing shm segment with the io_uring info */
> 		ring_shm_fd = shm_open(URING_SHM_NAME, O_RDWR, 0);
> 		if (ring_shm_fd < 0)
> 			fatal("shm_open(existing)");
> 		cfg_p = mmap(NULL, sizeof(*cfg_p), PROT_READ | PROT_WRITE,
> 			     MAP_SHARED, ring_shm_fd, 0);
> 		if (!cfg_p)
> 			fatal("mmap(shm)");
> 
> 		/* import the io_uring */
> 		ring = &ring_storage;
> 		rc = uring_import(cfg_p->ring.ring_fd,
> 				  ring, &cfg_p->ring_params);
> 		if (rc < 0)
> 			fatal("uring_import");
> 	}
> 
> 	/*
> 	 * fork/exec a child process (if necessary)
> 	 */
> 	if (tst_method == TST_T1_PARENT) {
> 		pid_t pid;
> 
> 		/* set the ctx for the next exec */
> 		if (argc >= 3) {
> 			printf(">>> set LSM/SELinux exec: %s\n",
> 			       (selinux_exec(argv[2]) > 0 ? "OK" : "FAILED"));
> 		}
> 
> 		/* fork/exec */
> 		pid = fork();
> 		if (!pid) {
> 			/* start the child */
> 			rc = execl(argv[0], argv[0], "t1_child", (char *)NULL);
> 			if (rc < 0)
> 				fatal("exec");
> 		} else {
> 			/* wait for the child to exit */
> 			int status;
> 			waitpid(pid, &status, 0);
> 			if (WIFEXITED(status))
> 				rc = WEXITSTATUS(status);
> 		}
> 	}
> 
> 	/*
> 	 * run test(s)
> 	 */
> 	if (tst_method == TST_SQPOLL || tst_method == TST_T1_CHILD) {
> 		rc = uring_op_a(ring, cfg_p->ring_creds, "/tmp/iouring.4.txt");
> 		if (rc < 0)
> 			fatal("uring_op_a(\"/tmp/iouring.4.txt\")");
> 	}
> 
> 	/*
> 	 * cleanup
> 	 */
> 	if (tst_method == TST_SQPOLL || tst_method == TST_T1_PARENT) {
> 		printf(">>> shutdown\n");
> 		uring_shutdown(&cfg_p->ring);
> 		shm_unlink(URING_SHM_NAME);
> 	} else if (tst_method == TST_T1_CHILD) {
> 		shm_unlink(URING_SHM_NAME);
> 	}
> 
> 	return rc;
> }


- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-24 20:57 ` [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Richard Guy Briggs
  2021-08-24 22:27   ` Paul Moore
@ 2021-08-26  1:16   ` Richard Guy Briggs
  2021-08-26  1:34     ` Paul Moore
  1 sibling, 1 reply; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-26  1:16 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-08-24 16:57, Richard Guy Briggs wrote:
> On 2021-08-11 16:48, Paul Moore wrote:
> > Draft #2 of the patchset which brings auditing and proper LSM access
> > controls to the io_uring subsystem.  The original patchset was posted
> > in late May and can be found via lore using the link below:
> > 
> > https://lore.kernel.org/linux-security-module/162163367115.8379.8459012634106035341.stgit@sifl/
> > 
> > This draft should incorporate all of the feedback from the original
> > posting as well as a few smaller things I noticed while playing
> > further with the code.  The big change is of course the selective
> > auditing in the io_uring op servicing, but that has already been
> > discussed quite a bit in the original thread so I won't go into
> > detail here; the important part is that we found a way to move
> > forward and this draft captures that.  For those of you looking to
> > play with these patches, they are based on Linus' v5.14-rc5 tag and
> > on my test system they boot and appear to function without problem;
> > they pass the selinux-testsuite and audit-testsuite and I have not
> > noticed any regressions in the normal use of the system.  If you want
> > to get a copy of these patches straight from git you can use the
> > "working-io_uring" branch in the repo below:
> > 
> > git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > 
> > Beyond the existing test suite tests mentioned above, I've cobbled
> > together some very basic, very crude tests to exercise some of the
> > things I care about from a LSM/audit perspective.  These tests are
> > pretty awful (I'm not kidding), but they might be helpful for the
> > other LSM/audit developers who want to test things:
> > 
> > https://drop.paul-moore.com/90.kUgq
> > 
> > There are currently two tests: 'iouring.2' and 'iouring.3';
> > 'iouring.1' was lost in a misguided and overzealous 'rm' command.
> > The first test is standalone and basically tests the SQPOLL
> > functionality while the second tests sharing io_urings across process
> > boundaries and the credential/personality sharing mechanism.  The
> > console output of both tests isn't particularly useful, the more
> > interesting bits are in the audit and LSM specific logs.  The
> > 'iouring.2' command requires no special arguments to run but the
> > 'iouring.3' test is split into a "server" and "client"; the server
> > should be run without argument:
> > 
> >   % ./iouring.3s
> >   >>> server started, pid = 11678
> >   >>> memfd created, fd = 3
> >   >>> io_uring created; fd = 5, creds = 1
> > 
> > ... while the client should be run with two arguments: the first is
> > the PID of the server process, the second is the "memfd" fd number:
> > 
> >   % ./iouring.3c 11678 3
> >   >>> client started, server_pid = 11678 server_memfd = 3
> >   >>> io_urings = 5 (server) / 5 (client)
> >   >>> io_uring ops using creds = 1
> >   >>> async op result: 36
> >   >>> async op result: 36
> >   >>> async op result: 36
> >   >>> async op result: 36
> >   >>> START file contents
> >   What is this life if, full of care,
> >   we have no time to stand and stare.
> >   >>> END file contents
> > 
> > The tests were hacked together from various sources online,
> > attribution and links to additional info can be found in the test
> > sources, but I expect these tests to die a fiery death in the not
> > to distant future as I work to add some proper tests to the SELinux
> > and audit test suites.
> > 
> > As I believe these patches should spend a full -rcX cycle in
> > linux-next, my current plan is to continue to solicit feedback on
> > these patches while they undergo additional testing (next up is
> > verification of the audit filter code for io_uring).  Assuming no
> > critical issues are found on the mailing lists or during testing, I
> > will post a proper patchset later with the idea of merging it into
> > selinux/next after the upcoming merge window closes.
> > 
> > Any comments, feedback, etc. are welcome.
> 
> Thanks for the tests.  I have a bunch of userspace patches to add to the
> last set I posted and these tests will help exercise them.  I also have
> one more kernel patch to post...  I'll dive back into that now.  I had
> wanted to post them before now but got distracted with AUDIT_TRIM
> breakage.

Please tell me about liburing.h that is needed for these.  There is one
in tools/io_uring/liburing.h but I don't think that one is right.

The next obvious one would be include/uapi/linux/io_uring.h

I must be missing something obvious here...

> > ---
> > 
> > Casey Schaufler (1):
> >       Smack: Brutalist io_uring support with debug
> > 
> > Paul Moore (8):
> >       audit: prepare audit_context for use in calling contexts beyond
> >              syscalls
> >       audit,io_uring,io-wq: add some basic audit support to io_uring
> >       audit: dev/test patch to force io_uring auditing
> >       audit: add filtering for io_uring records
> >       fs: add anon_inode_getfile_secure() similar to
> >           anon_inode_getfd_secure()
> >       io_uring: convert io_uring to the secure anon inode interface
> >       lsm,io_uring: add LSM hooks to io_uring
> >       selinux: add support for the io_uring access controls
> > 
> > 
> >  fs/anon_inodes.c                    |  29 ++
> >  fs/io-wq.c                          |   4 +
> >  fs/io_uring.c                       |  69 +++-
> >  include/linux/anon_inodes.h         |   4 +
> >  include/linux/audit.h               |  26 ++
> >  include/linux/lsm_hook_defs.h       |   5 +
> >  include/linux/lsm_hooks.h           |  13 +
> >  include/linux/security.h            |  16 +
> >  include/uapi/linux/audit.h          |   4 +-
> >  kernel/audit.h                      |   7 +-
> >  kernel/audit_tree.c                 |   3 +-
> >  kernel/audit_watch.c                |   3 +-
> >  kernel/auditfilter.c                |  15 +-
> >  kernel/auditsc.c                    | 483 +++++++++++++++++++-----
> >  security/security.c                 |  12 +
> >  security/selinux/hooks.c            |  34 ++
> >  security/selinux/include/classmap.h |   2 +
> >  security/smack/smack_lsm.c          |  64 ++++
> >  18 files changed, 678 insertions(+), 115 deletions(-)
> > 
> 
> - RGB
> 
> --
> Richard Guy Briggs <rgb@redhat.com>
> 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
> 

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-26  1:16   ` Richard Guy Briggs
@ 2021-08-26  1:34     ` Paul Moore
  2021-08-26 16:32       ` Richard Guy Briggs
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-26  1:34 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Wed, Aug 25, 2021 at 9:16 PM Richard Guy Briggs <rgb@redhat.com> wrote:
>
> On 2021-08-24 16:57, Richard Guy Briggs wrote:
> > On 2021-08-11 16:48, Paul Moore wrote:
> > > Draft #2 of the patchset which brings auditing and proper LSM access
> > > controls to the io_uring subsystem.  The original patchset was posted
> > > in late May and can be found via lore using the link below:
> > >
> > > https://lore.kernel.org/linux-security-module/162163367115.8379.8459012634106035341.stgit@sifl/
> > >
> > > This draft should incorporate all of the feedback from the original
> > > posting as well as a few smaller things I noticed while playing
> > > further with the code.  The big change is of course the selective
> > > auditing in the io_uring op servicing, but that has already been
> > > discussed quite a bit in the original thread so I won't go into
> > > detail here; the important part is that we found a way to move
> > > forward and this draft captures that.  For those of you looking to
> > > play with these patches, they are based on Linus' v5.14-rc5 tag and
> > > on my test system they boot and appear to function without problem;
> > > they pass the selinux-testsuite and audit-testsuite and I have not
> > > noticed any regressions in the normal use of the system.  If you want
> > > to get a copy of these patches straight from git you can use the
> > > "working-io_uring" branch in the repo below:
> > >
> > > git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > > https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > >
> > > Beyond the existing test suite tests mentioned above, I've cobbled
> > > together some very basic, very crude tests to exercise some of the
> > > things I care about from a LSM/audit perspective.  These tests are
> > > pretty awful (I'm not kidding), but they might be helpful for the
> > > other LSM/audit developers who want to test things:
> > >
> > > https://drop.paul-moore.com/90.kUgq
> > >
> > > There are currently two tests: 'iouring.2' and 'iouring.3';
> > > 'iouring.1' was lost in a misguided and overzealous 'rm' command.
> > > The first test is standalone and basically tests the SQPOLL
> > > functionality while the second tests sharing io_urings across process
> > > boundaries and the credential/personality sharing mechanism.  The
> > > console output of both tests isn't particularly useful, the more
> > > interesting bits are in the audit and LSM specific logs.  The
> > > 'iouring.2' command requires no special arguments to run but the
> > > 'iouring.3' test is split into a "server" and "client"; the server
> > > should be run without argument:
> > >
> > >   % ./iouring.3s
> > >   >>> server started, pid = 11678
> > >   >>> memfd created, fd = 3
> > >   >>> io_uring created; fd = 5, creds = 1
> > >
> > > ... while the client should be run with two arguments: the first is
> > > the PID of the server process, the second is the "memfd" fd number:
> > >
> > >   % ./iouring.3c 11678 3
> > >   >>> client started, server_pid = 11678 server_memfd = 3
> > >   >>> io_urings = 5 (server) / 5 (client)
> > >   >>> io_uring ops using creds = 1
> > >   >>> async op result: 36
> > >   >>> async op result: 36
> > >   >>> async op result: 36
> > >   >>> async op result: 36
> > >   >>> START file contents
> > >   What is this life if, full of care,
> > >   we have no time to stand and stare.
> > >   >>> END file contents
> > >
> > > The tests were hacked together from various sources online,
> > > attribution and links to additional info can be found in the test
> > > sources, but I expect these tests to die a fiery death in the not
> > > to distant future as I work to add some proper tests to the SELinux
> > > and audit test suites.
> > >
> > > As I believe these patches should spend a full -rcX cycle in
> > > linux-next, my current plan is to continue to solicit feedback on
> > > these patches while they undergo additional testing (next up is
> > > verification of the audit filter code for io_uring).  Assuming no
> > > critical issues are found on the mailing lists or during testing, I
> > > will post a proper patchset later with the idea of merging it into
> > > selinux/next after the upcoming merge window closes.
> > >
> > > Any comments, feedback, etc. are welcome.
> >
> > Thanks for the tests.  I have a bunch of userspace patches to add to the
> > last set I posted and these tests will help exercise them.  I also have
> > one more kernel patch to post...  I'll dive back into that now.  I had
> > wanted to post them before now but got distracted with AUDIT_TRIM
> > breakage.
>
> Please tell me about liburing.h that is needed for these.  There is one
> in tools/io_uring/liburing.h but I don't think that one is right.
>
> The next obvious one would be include/uapi/linux/io_uring.h
>
> I must be missing something obvious here...

You are looking for the liburing header files, the upstream is here:
-> https://github.com/axboe/liburing

If you are on a RH/IBM based distro it is likely called liburing[-devel]:

% dnf whatprovides */liburing.h
Last metadata expiration check: 0:38:37 ago on Wed 25 Aug 2021 08:54:22 PM EDT.
liburing-devel-2.0-2.fc35.i686 : Development files for Linux-native io_uring I/O
                              : access library
Repo        : rawhide
Matched from:
Filename    : /usr/include/liburing.h

liburing-devel-2.0-2.fc35.x86_64 : Development files for Linux-native io_uring
                                : I/O access library
Repo        : @System
Matched from:
Filename    : /usr/include/liburing.h

liburing-devel-2.0-2.fc35.x86_64 : Development files for Linux-native io_uring
                                : I/O access library
Repo        : rawhide
Matched from:
Filename    : /usr/include/liburing.h

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-26  1:34     ` Paul Moore
@ 2021-08-26 16:32       ` Richard Guy Briggs
  2021-08-26 19:14         ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-26 16:32 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-08-25 21:34, Paul Moore wrote:
> On Wed, Aug 25, 2021 at 9:16 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> >
> > On 2021-08-24 16:57, Richard Guy Briggs wrote:
> > > On 2021-08-11 16:48, Paul Moore wrote:
> > > > Draft #2 of the patchset which brings auditing and proper LSM access
> > > > controls to the io_uring subsystem.  The original patchset was posted
> > > > in late May and can be found via lore using the link below:
> > > >
> > > > https://lore.kernel.org/linux-security-module/162163367115.8379.8459012634106035341.stgit@sifl/
> > > >
> > > > This draft should incorporate all of the feedback from the original
> > > > posting as well as a few smaller things I noticed while playing
> > > > further with the code.  The big change is of course the selective
> > > > auditing in the io_uring op servicing, but that has already been
> > > > discussed quite a bit in the original thread so I won't go into
> > > > detail here; the important part is that we found a way to move
> > > > forward and this draft captures that.  For those of you looking to
> > > > play with these patches, they are based on Linus' v5.14-rc5 tag and
> > > > on my test system they boot and appear to function without problem;
> > > > they pass the selinux-testsuite and audit-testsuite and I have not
> > > > noticed any regressions in the normal use of the system.  If you want
> > > > to get a copy of these patches straight from git you can use the
> > > > "working-io_uring" branch in the repo below:
> > > >
> > > > git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > > > https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
> > > >
> > > > Beyond the existing test suite tests mentioned above, I've cobbled
> > > > together some very basic, very crude tests to exercise some of the
> > > > things I care about from a LSM/audit perspective.  These tests are
> > > > pretty awful (I'm not kidding), but they might be helpful for the
> > > > other LSM/audit developers who want to test things:
> > > >
> > > > https://drop.paul-moore.com/90.kUgq
> > > >
> > > > There are currently two tests: 'iouring.2' and 'iouring.3';
> > > > 'iouring.1' was lost in a misguided and overzealous 'rm' command.
> > > > The first test is standalone and basically tests the SQPOLL
> > > > functionality while the second tests sharing io_urings across process
> > > > boundaries and the credential/personality sharing mechanism.  The
> > > > console output of both tests isn't particularly useful, the more
> > > > interesting bits are in the audit and LSM specific logs.  The
> > > > 'iouring.2' command requires no special arguments to run but the
> > > > 'iouring.3' test is split into a "server" and "client"; the server
> > > > should be run without argument:
> > > >
> > > >   % ./iouring.3s
> > > >   >>> server started, pid = 11678
> > > >   >>> memfd created, fd = 3
> > > >   >>> io_uring created; fd = 5, creds = 1
> > > >
> > > > ... while the client should be run with two arguments: the first is
> > > > the PID of the server process, the second is the "memfd" fd number:
> > > >
> > > >   % ./iouring.3c 11678 3
> > > >   >>> client started, server_pid = 11678 server_memfd = 3
> > > >   >>> io_urings = 5 (server) / 5 (client)
> > > >   >>> io_uring ops using creds = 1
> > > >   >>> async op result: 36
> > > >   >>> async op result: 36
> > > >   >>> async op result: 36
> > > >   >>> async op result: 36
> > > >   >>> START file contents
> > > >   What is this life if, full of care,
> > > >   we have no time to stand and stare.
> > > >   >>> END file contents
> > > >
> > > > The tests were hacked together from various sources online,
> > > > attribution and links to additional info can be found in the test
> > > > sources, but I expect these tests to die a fiery death in the not
> > > > to distant future as I work to add some proper tests to the SELinux
> > > > and audit test suites.
> > > >
> > > > As I believe these patches should spend a full -rcX cycle in
> > > > linux-next, my current plan is to continue to solicit feedback on
> > > > these patches while they undergo additional testing (next up is
> > > > verification of the audit filter code for io_uring).  Assuming no
> > > > critical issues are found on the mailing lists or during testing, I
> > > > will post a proper patchset later with the idea of merging it into
> > > > selinux/next after the upcoming merge window closes.
> > > >
> > > > Any comments, feedback, etc. are welcome.
> > >
> > > Thanks for the tests.  I have a bunch of userspace patches to add to the
> > > last set I posted and these tests will help exercise them.  I also have
> > > one more kernel patch to post...  I'll dive back into that now.  I had
> > > wanted to post them before now but got distracted with AUDIT_TRIM
> > > breakage.
> >
> > Please tell me about liburing.h that is needed for these.  There is one
> > in tools/io_uring/liburing.h but I don't think that one is right.
> >
> > The next obvious one would be include/uapi/linux/io_uring.h
> >
> > I must be missing something obvious here...
> 
> You are looking for the liburing header files, the upstream is here:
> -> https://github.com/axboe/liburing
> 
> If you are on a RH/IBM based distro it is likely called liburing[-devel]:

Found it but struct io_uring missing "features" in everything except
rawhide.  Forced upgrade of my test VMs.  :-)

audit-testsuite still passes.

I'm getting:
	# ./iouring.2                                                
	Kernel thread io_uring-sq is not running.                                      
	Unable to setup io_uring: Permission denied

	# ./iouring.3s
	>>> server started, pid = 2082                                                 
	>>> memfd created, fd = 3                                                      
	io_uring_queue_init: Permission denied

I have CONFIG_IO_URING=y set, what else is needed?

> % dnf whatprovides */liburing.h
> Last metadata expiration check: 0:38:37 ago on Wed 25 Aug 2021 08:54:22 PM EDT.
> liburing-devel-2.0-2.fc35.i686 : Development files for Linux-native io_uring I/O
>                               : access library
> Repo        : rawhide
> Matched from:
> Filename    : /usr/include/liburing.h
> 
> liburing-devel-2.0-2.fc35.x86_64 : Development files for Linux-native io_uring
>                                 : I/O access library
> Repo        : @System
> Matched from:
> Filename    : /usr/include/liburing.h
> 
> liburing-devel-2.0-2.fc35.x86_64 : Development files for Linux-native io_uring
>                                 : I/O access library
> Repo        : rawhide
> Matched from:
> Filename    : /usr/include/liburing.h
> 
> -- 
> paul moore

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-26 16:32       ` Richard Guy Briggs
@ 2021-08-26 19:14         ` Paul Moore
  2021-08-27 13:35           ` Richard Guy Briggs
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-26 19:14 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Thu, Aug 26, 2021 at 12:32 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> I'm getting:
>         # ./iouring.2
>         Kernel thread io_uring-sq is not running.
>         Unable to setup io_uring: Permission denied
>
>         # ./iouring.3s
>         >>> server started, pid = 2082
>         >>> memfd created, fd = 3
>         io_uring_queue_init: Permission denied
>
> I have CONFIG_IO_URING=y set, what else is needed?

I'm not sure how you tried to run those tests, but try running as root
and with SELinux in permissive mode.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-26 19:14         ` Paul Moore
@ 2021-08-27 13:35           ` Richard Guy Briggs
  2021-08-27 19:49             ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-27 13:35 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-08-26 15:14, Paul Moore wrote:
> On Thu, Aug 26, 2021 at 12:32 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > I'm getting:
> >         # ./iouring.2
> >         Kernel thread io_uring-sq is not running.
> >         Unable to setup io_uring: Permission denied
> >
> >         # ./iouring.3s
> >         >>> server started, pid = 2082
> >         >>> memfd created, fd = 3
> >         io_uring_queue_init: Permission denied
> >
> > I have CONFIG_IO_URING=y set, what else is needed?
> 
> I'm not sure how you tried to run those tests, but try running as root
> and with SELinux in permissive mode.

Ok, they ran, including iouring.4.  iouring.2 claimed twice: "Kernel
thread io_uring-sq is not running." and I didn't get any URING records
with ausearch.  I don't know if any of this is expected.

> paul moore

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-27 13:35           ` Richard Guy Briggs
@ 2021-08-27 19:49             ` Paul Moore
  2021-08-28 15:03               ` Richard Guy Briggs
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-27 19:49 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Fri, Aug 27, 2021 at 9:36 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> On 2021-08-26 15:14, Paul Moore wrote:
> > On Thu, Aug 26, 2021 at 12:32 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > I'm getting:
> > >         # ./iouring.2
> > >         Kernel thread io_uring-sq is not running.
> > >         Unable to setup io_uring: Permission denied
> > >
> > >         # ./iouring.3s
> > >         >>> server started, pid = 2082
> > >         >>> memfd created, fd = 3
> > >         io_uring_queue_init: Permission denied
> > >
> > > I have CONFIG_IO_URING=y set, what else is needed?
> >
> > I'm not sure how you tried to run those tests, but try running as root
> > and with SELinux in permissive mode.
>
> Ok, they ran, including iouring.4.  iouring.2 claimed twice: "Kernel
> thread io_uring-sq is not running." and I didn't get any URING records
> with ausearch.  I don't know if any of this is expected.

Now that I've written iouring.4, I would skip the others; while
helpful at the time, they are pretty crap.

I have no idea what kernel you are running, but I'm going to assume
you've applied the v2 patches (if not, you obviously need to do that
<g>).  Beyond that you may need to set a filter for the
io_uring_enter() syscall to force the issue; theoretically your audit
userspace patches should allow a uring op specifically to be filtered
but I haven't had a chance to try that yet so either the kernel or
userspace portion could be broken.

At this point if you are running into problems you'll probably need to
spend some time debugging them, as I think you're the only person who
has tested your audit userspace patches at this point (and the only
one who has access to your latest bits).

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-27 19:49             ` Paul Moore
@ 2021-08-28 15:03               ` Richard Guy Briggs
  2021-08-29 15:18                 ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Guy Briggs @ 2021-08-28 15:03 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

[-- Attachment #1: Type: text/plain, Size: 2643 bytes --]

On 2021-08-27 15:49, Paul Moore wrote:
> On Fri, Aug 27, 2021 at 9:36 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > On 2021-08-26 15:14, Paul Moore wrote:
> > > On Thu, Aug 26, 2021 at 12:32 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > I'm getting:
> > > >         # ./iouring.2
> > > >         Kernel thread io_uring-sq is not running.
> > > >         Unable to setup io_uring: Permission denied
> > > >
> > > >         # ./iouring.3s
> > > >         >>> server started, pid = 2082
> > > >         >>> memfd created, fd = 3
> > > >         io_uring_queue_init: Permission denied
> > > >
> > > > I have CONFIG_IO_URING=y set, what else is needed?
> > >
> > > I'm not sure how you tried to run those tests, but try running as root
> > > and with SELinux in permissive mode.
> >
> > Ok, they ran, including iouring.4.  iouring.2 claimed twice: "Kernel
> > thread io_uring-sq is not running." and I didn't get any URING records
> > with ausearch.  I don't know if any of this is expected.
> 
> Now that I've written iouring.4, I would skip the others; while
> helpful at the time, they are pretty crap.

Ok.

> I have no idea what kernel you are running, but I'm going to assume
> you've applied the v2 patches (if not, you obviously need to do that
> <g>).  Beyond that you may need to set a filter for the
> io_uring_enter() syscall to force the issue; theoretically your audit
> userspace patches should allow a uring op specifically to be filtered
> but I haven't had a chance to try that yet so either the kernel or
> userspace portion could be broken.

I'm running audit/next (on 5.14-rc1) with your v2 patches.

I did set a syscall filter for
	-a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
and that yielded some records with a couple of orphans that surprised me
a bit.  I've attached that log.  I was a bit surprised there were no
records for ./iouring.3*.

I'm now testing the new "-a uring,always -U ..." to get that userspace
code working as expected...

> At this point if you are running into problems you'll probably need to
> spend some time debugging them, as I think you're the only person who
> has tested your audit userspace patches at this point (and the only
> one who has access to your latest bits).

Yes, I'll do some basic debugging and then publish to avoid wasting
people's time on silly bugs, but to get help on the more serious ones.

> paul moore

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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

[-- Attachment #2: audit.log-2021-08-27-1 --]
[-- Type: text/plain, Size: 17764 bytes --]

----
type=PROCTITLE msg=audit(2021-08-27 16:41:56.190:328) : proctitle=auditctl -a exit,always -F arch b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall 
type=SYSCALL msg=audit(2021-08-27 16:41:56.190:328) : arch=x86_64 syscall=sendto success=yes exit=1072 a0=0x4 a1=0x7ffff3e0dc10 a2=0x430 a3=0x0 items=0 ppid=543 pid=12433 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=auditctl exe=/usr/sbin/auditctl subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
type=CONFIG_CHANGE msg=audit(2021-08-27 16:41:56.190:328) : auid=root ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op=add_rule key=iouringsyscall list=exit res=yes 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.032:329) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.032:329) : arch=x86_64 syscall=io_uring_setup success=yes exit=3 a0=0x8 a1=0x7fff6037b890 a2=0x7f38ee9de7a7 a3=0x3 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.034:330) : proctitle=./iouring.2 
type=MMAP msg=audit(2021-08-27 16:42:22.034:330) : fd=3 flags=MAP_SHARED|MAP_POPULATE 
type=SYSCALL msg=audit(2021-08-27 16:42:22.034:330) : arch=x86_64 syscall=mmap success=yes exit=139882499366912 a0=0x0 a1=0x260 a2=PROT_READ|PROT_WRITE a3=MAP_SHARED|MAP_POPULATE items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
type=AVC msg=audit(2021-08-27 16:42:22.034:330) : avc:  denied  { write } for  pid=12437 comm=iouring.2 path=anon_inode:[io_uring] dev="anon_inodefs" ino=26726 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:unconfined_t:s0 tclass=anon_inode permissive=1 
type=AVC msg=audit(2021-08-27 16:42:22.034:330) : avc:  denied  { map } for  pid=12437 comm=iouring.2 path=anon_inode:[io_uring] dev="anon_inodefs" ino=26726 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:unconfined_t:s0 tclass=anon_inode permissive=1 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.036:331) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.036:331) : arch=x86_64 syscall=io_uring_register success=yes exit=0 a0=0x3 a1=0x2 a2=0x7fff6037b854 a3=0x1 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.037:332) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.037:332) : arch=x86_64 syscall=io_uring_enter success=yes exit=2 a0=0x3 a1=0x2 a2=0x0 a3=0x2 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.037:333) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.037:333) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x3 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.038:334) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.038:334) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x3 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:22.084:335) : proctitle=./iouring.2 
type=SYSCALL msg=audit(2021-08-27 16:42:22.084:335) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x3 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12437 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.2 exe=/root/rgb/testing/iouring/iouring.2 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.624:336) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.624:336) : arch=x86_64 syscall=io_uring_setup success=yes exit=4 a0=0x8 a1=0x7fefe5ac10d8 a2=0x7fefe5ac10d8 a3=0x3 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.625:337) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.625:337) : arch=x86_64 syscall=io_uring_register success=yes exit=1 a0=0x4 a1=0x9 a2=0x0 a3=0x0 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.626:338) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.626:338) : arch=x86_64 syscall=io_uring_enter success=yes exit=1 a0=0x4 a1=0x1 a2=0x0 a3=0x2 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.627:341) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.627:341) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=URINGOP msg=audit(2021-08-27 16:42:30.628:339) : uring_op=18 success=no exit=EAGAIN(Resource temporarily unavailable) items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
----
type=PATH msg=audit(2021-08-27 16:42:30.628:340) : item=1 name=/tmp/iouring.4.txt inode=33 dev=00:1f mode=file,644 ouid=root ogid=root rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 
type=PATH msg=audit(2021-08-27 16:42:30.628:340) : item=0 name=/tmp/ inode=1 dev=00:1f mode=dir,sticky,777 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:tmp_t:s0 nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 
type=CWD msg=audit(2021-08-27 16:42:30.628:340) : cwd=/root/rgb/testing/iouring 
type=URINGOP msg=audit(2021-08-27 16:42:30.628:340) : uring_op=18 success=yes exit=0 items=2 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.629:342) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.629:342) : arch=x86_64 syscall=io_uring_register success=yes exit=0 a0=0x4 a1=0x2 a2=0x7ffff75290a8 a3=0x1 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.629:343) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.629:343) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.631:344) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.631:344) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.632:346) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.632:346) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=URINGOP msg=audit(2021-08-27 16:42:30.633:345) : uring_op=19 success=yes exit=0 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:30.634:347) : proctitle=./iouring.4 sqpoll 
type=SYSCALL msg=audit(2021-08-27 16:42:30.634:347) : arch=x86_64 syscall=io_uring_register success=yes exit=0 a0=0x4 a1=0x3 a2=0x0 a3=0x0 items=0 ppid=543 pid=12447 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.895:348) : proctitle=./iouring.4 t1 
type=SYSCALL msg=audit(2021-08-27 16:42:36.895:348) : arch=x86_64 syscall=io_uring_setup success=yes exit=4 a0=0x8 a1=0x7fcaf2b8a0d8 a2=0x7fcaf2b8a0d8 a3=0x3 items=0 ppid=543 pid=12451 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.896:349) : proctitle=./iouring.4 t1 
type=SYSCALL msg=audit(2021-08-27 16:42:36.896:349) : arch=x86_64 syscall=io_uring_register success=yes exit=1 a0=0x4 a1=0x9 a2=0x0 a3=0x0 items=0 ppid=543 pid=12451 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.902:350) : proctitle=./iouring.4 t1_child 
type=PATH msg=audit(2021-08-27 16:42:36.902:350) : item=0 name=/tmp/iouring.4.txt nametype=UNKNOWN cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 
type=CWD msg=audit(2021-08-27 16:42:36.902:350) : cwd=/root/rgb/testing/iouring 
type=SYSCALL msg=audit(2021-08-27 16:42:36.902:350) : arch=x86_64 syscall=io_uring_enter success=yes exit=1 a0=0x4 a1=0x1 a2=0x0 a3=0x0 items=1 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
type=URINGOP msg=audit(2021-08-27 16:42:36.902:350) : uring_op=18 items=1 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PATH msg=audit(2021-08-27 16:42:36.902:351) : item=0 name=/tmp/iouring.4.txt inode=33 dev=00:1f mode=file,644 ouid=root ogid=root rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 
type=CWD msg=audit(2021-08-27 16:42:36.902:351) : cwd=/root/rgb/testing/iouring 
type=URINGOP msg=audit(2021-08-27 16:42:36.902:351) : uring_op=18 success=yes exit=0 items=1 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.902:352) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.902:352) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.902:353) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.902:353) : arch=x86_64 syscall=io_uring_register success=yes exit=0 a0=0x4 a1=0x2 a2=0x7ffc0645bcb8 a3=0x1 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.903:354) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.903:354) : arch=x86_64 syscall=io_uring_enter success=yes exit=1 a0=0x4 a1=0x1 a2=0x0 a3=0x0 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.903:355) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.903:355) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.903:356) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.903:356) : arch=x86_64 syscall=io_uring_enter success=yes exit=1 a0=0x4 a1=0x1 a2=0x0 a3=0x0 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.903:357) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.903:357) : arch=x86_64 syscall=io_uring_enter success=yes exit=0 a0=0x4 a1=0x0 a2=0x1 a3=0x1 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.904:358) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.904:358) : arch=x86_64 syscall=io_uring_enter success=yes exit=1 a0=0x4 a1=0x1 a2=0x0 a3=0x0 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
type=URINGOP msg=audit(2021-08-27 16:42:36.904:358) : uring_op=19 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----
type=PROCTITLE msg=audit(2021-08-27 16:42:36.904:359) : proctitle=./iouring.4 t1_child 
type=SYSCALL msg=audit(2021-08-27 16:42:36.904:359) : arch=x86_64 syscall=io_uring_register success=yes exit=0 a0=0x4 a1=0x3 a2=0x0 a3=0x0 items=0 ppid=12451 pid=12452 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=ttyS0 ses=1 comm=iouring.4 exe=/root/rgb/testing/iouring/iouring.4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=iouringsyscall 
----

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-28 15:03               ` Richard Guy Briggs
@ 2021-08-29 15:18                 ` Paul Moore
  2021-09-01 19:21                   ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-29 15:18 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> I did set a syscall filter for
>         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> and that yielded some records with a couple of orphans that surprised me
> a bit.

Without looking too closely at the log you sent, you can expect URING
records without an associated SYSCALL record when the uring op is
being processed in the io-wq or sqpoll context.  In the io-wq case the
processing is happening after the thread finished the syscall but
before the execution context returns to userspace and in the case of
sqpoll the processing is handled by a separate kernel thread with no
association to a process thread.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug
  2021-08-11 20:49 ` [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug Paul Moore
@ 2021-08-31 14:44   ` Paul Moore
  2021-08-31 15:03     ` Casey Schaufler
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-08-31 14:44 UTC (permalink / raw)
  To: casey
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Wed, Aug 11, 2021 at 4:49 PM Paul Moore <paul@paul-moore.com> wrote:
>
> From: Casey Schaufler <casey@schaufler-ca.com>
>
> Add Smack privilege checks for io_uring. Use CAP_MAC_OVERRIDE
> for the override_creds case and CAP_MAC_ADMIN for creating a
> polling thread. These choices are based on conjecture regarding
> the intent of the surrounding code.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> [PM: make the smack_uring_* funcs static]
> Signed-off-by: Paul Moore <paul@paul-moore.com>
>
> ---
> v2:
> - made the smack_uring_* funcs static
> v1:
> - initial draft
> ---
>  security/smack/smack_lsm.c |   64 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 223a6da0e6dc..7fb094098f38 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -4691,6 +4691,66 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
>         return 0;
>  }
>
> +#ifdef CONFIG_IO_URING
> +/**
> + * smack_uring_override_creds - Is io_uring cred override allowed?
> + * @new: the target creds
> + *
> + * Check to see if the current task is allowed to override it's credentials
> + * to service an io_uring operation.
> + */
> +static int smack_uring_override_creds(const struct cred *new)
> +{
> +       struct task_smack *tsp = smack_cred(current_cred());
> +       struct task_smack *nsp = smack_cred(new);
> +
> +#if 1
> +       if (tsp->smk_task == nsp->smk_task)
> +               pr_info("%s: Smack matches %s\n", __func__,
> +                       tsp->smk_task->smk_known);
> +       else
> +               pr_info("%s: Smack override check %s to %s\n", __func__,
> +                       tsp->smk_task->smk_known, nsp->smk_task->smk_known);
> +#endif

Casey, with the idea of posting a v3 towards the end of the merge
window next week, without the RFC tag and with the intention of
merging it into -next during the first/second week of the -rcX phase,
do you have any objections to me removing the debug code (#if 1 ...
#endif) from your patch?  Did you have any other changes?


--
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug
  2021-08-31 14:44   ` Paul Moore
@ 2021-08-31 15:03     ` Casey Schaufler
  2021-08-31 16:43       ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Casey Schaufler @ 2021-08-31 15:03 UTC (permalink / raw)
  To: Paul Moore
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov, Casey Schaufler

On 8/31/2021 7:44 AM, Paul Moore wrote:
> On Wed, Aug 11, 2021 at 4:49 PM Paul Moore <paul@paul-moore.com> wrote:
>> From: Casey Schaufler <casey@schaufler-ca.com>
>>
>> Add Smack privilege checks for io_uring. Use CAP_MAC_OVERRIDE
>> for the override_creds case and CAP_MAC_ADMIN for creating a
>> polling thread. These choices are based on conjecture regarding
>> the intent of the surrounding code.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> [PM: make the smack_uring_* funcs static]
>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>>
>> ---
>> v2:
>> - made the smack_uring_* funcs static
>> v1:
>> - initial draft
>> ---
>>  security/smack/smack_lsm.c |   64 ++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 64 insertions(+)
>>
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index 223a6da0e6dc..7fb094098f38 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -4691,6 +4691,66 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
>>         return 0;
>>  }
>>
>> +#ifdef CONFIG_IO_URING
>> +/**
>> + * smack_uring_override_creds - Is io_uring cred override allowed?
>> + * @new: the target creds
>> + *
>> + * Check to see if the current task is allowed to override it's credentials
>> + * to service an io_uring operation.
>> + */
>> +static int smack_uring_override_creds(const struct cred *new)
>> +{
>> +       struct task_smack *tsp = smack_cred(current_cred());
>> +       struct task_smack *nsp = smack_cred(new);
>> +
>> +#if 1
>> +       if (tsp->smk_task == nsp->smk_task)
>> +               pr_info("%s: Smack matches %s\n", __func__,
>> +                       tsp->smk_task->smk_known);
>> +       else
>> +               pr_info("%s: Smack override check %s to %s\n", __func__,
>> +                       tsp->smk_task->smk_known, nsp->smk_task->smk_known);
>> +#endif
> Casey, with the idea of posting a v3 towards the end of the merge
> window next week, without the RFC tag and with the intention of
> merging it into -next during the first/second week of the -rcX phase,
> do you have any objections to me removing the debug code (#if 1 ...
> #endif) from your patch?  Did you have any other changes?

I have no other changes. And yes, the debug code should be stripped.
Thank you.

>
>
> --
> paul moore
> www.paul-moore.com

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

* Re: [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug
  2021-08-31 15:03     ` Casey Schaufler
@ 2021-08-31 16:43       ` Paul Moore
  0 siblings, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-08-31 16:43 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Tue, Aug 31, 2021 at 11:03 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 8/31/2021 7:44 AM, Paul Moore wrote:
> >
> > Casey, with the idea of posting a v3 towards the end of the merge
> > window next week, without the RFC tag and with the intention of
> > merging it into -next during the first/second week of the -rcX phase,
> > do you have any objections to me removing the debug code (#if 1 ...
> > #endif) from your patch?  Did you have any other changes?
>
> I have no other changes. And yes, the debug code should be stripped.
> Thank you.

Great, I'll remove that code for the v3 dump.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-08-29 15:18                 ` Paul Moore
@ 2021-09-01 19:21                   ` Paul Moore
  2021-09-10  0:58                     ` Richard Guy Briggs
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-09-01 19:21 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > I did set a syscall filter for
> >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > and that yielded some records with a couple of orphans that surprised me
> > a bit.
>
> Without looking too closely at the log you sent, you can expect URING
> records without an associated SYSCALL record when the uring op is
> being processed in the io-wq or sqpoll context.  In the io-wq case the
> processing is happening after the thread finished the syscall but
> before the execution context returns to userspace and in the case of
> sqpoll the processing is handled by a separate kernel thread with no
> association to a process thread.

I spent some time this morning/afternoon playing with the io_uring
audit filtering capability and with your audit userspace
ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
map the io_uring ops correctly), but I know you mentioned you have a
number of fixes/improvements still as a work-in-progress there so I'm
not too concerned.  The important part is that the kernel pieces look
to be working correctly.

As usual, if you notice anything awry while playing with the userspace
changes please let me know.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-01 19:21                   ` Paul Moore
@ 2021-09-10  0:58                     ` Richard Guy Briggs
  2021-09-13 19:23                       ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Guy Briggs @ 2021-09-10  0:58 UTC (permalink / raw)
  To: Paul Moore, sgrubb
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-09-01 15:21, Paul Moore wrote:
> On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> > On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > I did set a syscall filter for
> > >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > > and that yielded some records with a couple of orphans that surprised me
> > > a bit.
> >
> > Without looking too closely at the log you sent, you can expect URING
> > records without an associated SYSCALL record when the uring op is
> > being processed in the io-wq or sqpoll context.  In the io-wq case the
> > processing is happening after the thread finished the syscall but
> > before the execution context returns to userspace and in the case of
> > sqpoll the processing is handled by a separate kernel thread with no
> > association to a process thread.
> 
> I spent some time this morning/afternoon playing with the io_uring
> audit filtering capability and with your audit userspace
> ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
> the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
> map the io_uring ops correctly), but I know you mentioned you have a
> number of fixes/improvements still as a work-in-progress there so I'm
> not too concerned.  The important part is that the kernel pieces look
> to be working correctly.

Ok, I have squashed and pushed the audit userspace support for iouring:
	https://github.com/rgbriggs/audit-userspace/commit/e8bd8d2ea8adcaa758024cb9b8fa93895ae35eea
	https://github.com/linux-audit/audit-userspace/compare/master...rgbriggs:ghak-iouring-filtering.v2.1
There are test rpms for f35 here:
	http://people.redhat.com/~rbriggs/ghak-iouring/git-e8bd8d2-fc35/

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

"auditctl -a uring,always -S ..." will now throw an error and require
"-U" instead.

> As usual, if you notice anything awry while playing with the userspace
> changes please let me know.

Same for userspace...  I think I already see one mapping uring op names
in ausearch...

> paul moore

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-10  0:58                     ` Richard Guy Briggs
@ 2021-09-13 19:23                       ` Paul Moore
  2021-09-14  1:50                         ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-09-13 19:23 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: sgrubb, linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Thu, Sep 9, 2021 at 8:59 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> On 2021-09-01 15:21, Paul Moore wrote:
> > On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> > > On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > I did set a syscall filter for
> > > >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > > > and that yielded some records with a couple of orphans that surprised me
> > > > a bit.
> > >
> > > Without looking too closely at the log you sent, you can expect URING
> > > records without an associated SYSCALL record when the uring op is
> > > being processed in the io-wq or sqpoll context.  In the io-wq case the
> > > processing is happening after the thread finished the syscall but
> > > before the execution context returns to userspace and in the case of
> > > sqpoll the processing is handled by a separate kernel thread with no
> > > association to a process thread.
> >
> > I spent some time this morning/afternoon playing with the io_uring
> > audit filtering capability and with your audit userspace
> > ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
> > the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
> > map the io_uring ops correctly), but I know you mentioned you have a
> > number of fixes/improvements still as a work-in-progress there so I'm
> > not too concerned.  The important part is that the kernel pieces look
> > to be working correctly.
>
> Ok, I have squashed and pushed the audit userspace support for iouring:
>         https://github.com/rgbriggs/audit-userspace/commit/e8bd8d2ea8adcaa758024cb9b8fa93895ae35eea
>         https://github.com/linux-audit/audit-userspace/compare/master...rgbriggs:ghak-iouring-filtering.v2.1
> There are test rpms for f35 here:
>         http://people.redhat.com/~rbriggs/ghak-iouring/git-e8bd8d2-fc35/
>
> userspace v2 changelog:
> - check for watch before adding perm
> - update manpage to include filesystem filter
> - update support for the uring filter list: doc, -U op, op names
> - add support for the AUDIT_URINGOP record type
> - add uringop support to ausearch
> - add uringop support to aureport
> - lots of bug fixes
>
> "auditctl -a uring,always -S ..." will now throw an error and require
> "-U" instead.

Thanks Richard.

FYI, I rebased the io_uring/LSM/audit patchset on top of v5.15-rc1
today and tested both with your v1.0 and with your v2.1 branch and the
various combinations seemed to work just fine (of course the v2.1
userspace branch was more polished, less warts, etc.).  I'm going to
go over the patch set one more time to make sure everything is still
looking good, write up an updated cover letter, and post a v3 revision
later tonight with the hope of merging it into -next later this week.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-13 19:23                       ` Paul Moore
@ 2021-09-14  1:50                         ` Paul Moore
  2021-09-14  2:49                           ` Paul Moore
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-09-14  1:50 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: sgrubb, linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Mon, Sep 13, 2021 at 3:23 PM Paul Moore <paul@paul-moore.com> wrote:
> On Thu, Sep 9, 2021 at 8:59 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > On 2021-09-01 15:21, Paul Moore wrote:
> > > On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> > > > On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > > I did set a syscall filter for
> > > > >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > > > > and that yielded some records with a couple of orphans that surprised me
> > > > > a bit.
> > > >
> > > > Without looking too closely at the log you sent, you can expect URING
> > > > records without an associated SYSCALL record when the uring op is
> > > > being processed in the io-wq or sqpoll context.  In the io-wq case the
> > > > processing is happening after the thread finished the syscall but
> > > > before the execution context returns to userspace and in the case of
> > > > sqpoll the processing is handled by a separate kernel thread with no
> > > > association to a process thread.
> > >
> > > I spent some time this morning/afternoon playing with the io_uring
> > > audit filtering capability and with your audit userspace
> > > ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
> > > the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
> > > map the io_uring ops correctly), but I know you mentioned you have a
> > > number of fixes/improvements still as a work-in-progress there so I'm
> > > not too concerned.  The important part is that the kernel pieces look
> > > to be working correctly.
> >
> > Ok, I have squashed and pushed the audit userspace support for iouring:
> >         https://github.com/rgbriggs/audit-userspace/commit/e8bd8d2ea8adcaa758024cb9b8fa93895ae35eea
> >         https://github.com/linux-audit/audit-userspace/compare/master...rgbriggs:ghak-iouring-filtering.v2.1
> > There are test rpms for f35 here:
> >         http://people.redhat.com/~rbriggs/ghak-iouring/git-e8bd8d2-fc35/
> >
> > userspace v2 changelog:
> > - check for watch before adding perm
> > - update manpage to include filesystem filter
> > - update support for the uring filter list: doc, -U op, op names
> > - add support for the AUDIT_URINGOP record type
> > - add uringop support to ausearch
> > - add uringop support to aureport
> > - lots of bug fixes
> >
> > "auditctl -a uring,always -S ..." will now throw an error and require
> > "-U" instead.
>
> Thanks Richard.
>
> FYI, I rebased the io_uring/LSM/audit patchset on top of v5.15-rc1
> today and tested both with your v1.0 and with your v2.1 branch and the
> various combinations seemed to work just fine (of course the v2.1
> userspace branch was more polished, less warts, etc.).  I'm going to
> go over the patch set one more time to make sure everything is still
> looking good, write up an updated cover letter, and post a v3 revision
> later tonight with the hope of merging it into -next later this week.

Best laid plans of mice and men ...

It turns out the LSM hook macros are full of warnings-now-errors that
should likely be resolved before sending anything LSM related to
Linus.  I'll post v3 once I fix this, which may not be until tomorrow.

(To be clear, the warnings/errors aren't new to this patchset, I'm
likely just the first person to notice them.)

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-14  1:50                         ` Paul Moore
@ 2021-09-14  2:49                           ` Paul Moore
  2021-09-15 12:29                             ` Richard Guy Briggs
  0 siblings, 1 reply; 35+ messages in thread
From: Paul Moore @ 2021-09-14  2:49 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: sgrubb, linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Mon, Sep 13, 2021 at 9:50 PM Paul Moore <paul@paul-moore.com> wrote:
> On Mon, Sep 13, 2021 at 3:23 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Thu, Sep 9, 2021 at 8:59 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > On 2021-09-01 15:21, Paul Moore wrote:
> > > > On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> > > > > On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > > > I did set a syscall filter for
> > > > > >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > > > > > and that yielded some records with a couple of orphans that surprised me
> > > > > > a bit.
> > > > >
> > > > > Without looking too closely at the log you sent, you can expect URING
> > > > > records without an associated SYSCALL record when the uring op is
> > > > > being processed in the io-wq or sqpoll context.  In the io-wq case the
> > > > > processing is happening after the thread finished the syscall but
> > > > > before the execution context returns to userspace and in the case of
> > > > > sqpoll the processing is handled by a separate kernel thread with no
> > > > > association to a process thread.
> > > >
> > > > I spent some time this morning/afternoon playing with the io_uring
> > > > audit filtering capability and with your audit userspace
> > > > ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
> > > > the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
> > > > map the io_uring ops correctly), but I know you mentioned you have a
> > > > number of fixes/improvements still as a work-in-progress there so I'm
> > > > not too concerned.  The important part is that the kernel pieces look
> > > > to be working correctly.
> > >
> > > Ok, I have squashed and pushed the audit userspace support for iouring:
> > >         https://github.com/rgbriggs/audit-userspace/commit/e8bd8d2ea8adcaa758024cb9b8fa93895ae35eea
> > >         https://github.com/linux-audit/audit-userspace/compare/master...rgbriggs:ghak-iouring-filtering.v2.1
> > > There are test rpms for f35 here:
> > >         http://people.redhat.com/~rbriggs/ghak-iouring/git-e8bd8d2-fc35/
> > >
> > > userspace v2 changelog:
> > > - check for watch before adding perm
> > > - update manpage to include filesystem filter
> > > - update support for the uring filter list: doc, -U op, op names
> > > - add support for the AUDIT_URINGOP record type
> > > - add uringop support to ausearch
> > > - add uringop support to aureport
> > > - lots of bug fixes
> > >
> > > "auditctl -a uring,always -S ..." will now throw an error and require
> > > "-U" instead.
> >
> > Thanks Richard.
> >
> > FYI, I rebased the io_uring/LSM/audit patchset on top of v5.15-rc1
> > today and tested both with your v1.0 and with your v2.1 branch and the
> > various combinations seemed to work just fine (of course the v2.1
> > userspace branch was more polished, less warts, etc.).  I'm going to
> > go over the patch set one more time to make sure everything is still
> > looking good, write up an updated cover letter, and post a v3 revision
> > later tonight with the hope of merging it into -next later this week.
>
> Best laid plans of mice and men ...
>
> It turns out the LSM hook macros are full of warnings-now-errors that
> should likely be resolved before sending anything LSM related to
> Linus.  I'll post v3 once I fix this, which may not be until tomorrow.
>
> (To be clear, the warnings/errors aren't new to this patchset, I'm
> likely just the first person to notice them.)

Actually, scratch that ... I'm thinking that might just be an oddity
of the Intel 0day test robot building for the xtensa arch.  I'll post
the v3 patchset tonight.

-- 
paul moore
www.paul-moore.com

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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-14  2:49                           ` Paul Moore
@ 2021-09-15 12:29                             ` Richard Guy Briggs
  2021-09-15 13:02                               ` Steve Grubb
  2021-09-15 14:12                               ` Paul Moore
  0 siblings, 2 replies; 35+ messages in thread
From: Richard Guy Briggs @ 2021-09-15 12:29 UTC (permalink / raw)
  To: Paul Moore
  Cc: sgrubb, linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On 2021-09-13 22:49, Paul Moore wrote:
> On Mon, Sep 13, 2021 at 9:50 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Mon, Sep 13, 2021 at 3:23 PM Paul Moore <paul@paul-moore.com> wrote:
> > > On Thu, Sep 9, 2021 at 8:59 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > On 2021-09-01 15:21, Paul Moore wrote:
> > > > > On Sun, Aug 29, 2021 at 11:18 AM Paul Moore <paul@paul-moore.com> wrote:
> > > > > > On Sat, Aug 28, 2021 at 11:04 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > > > > I did set a syscall filter for
> > > > > > >         -a exit,always -F arch=b64 -S io_uring_enter,io_uring_setup,io_uring_register -F key=iouringsyscall
> > > > > > > and that yielded some records with a couple of orphans that surprised me
> > > > > > > a bit.
> > > > > >
> > > > > > Without looking too closely at the log you sent, you can expect URING
> > > > > > records without an associated SYSCALL record when the uring op is
> > > > > > being processed in the io-wq or sqpoll context.  In the io-wq case the
> > > > > > processing is happening after the thread finished the syscall but
> > > > > > before the execution context returns to userspace and in the case of
> > > > > > sqpoll the processing is handled by a separate kernel thread with no
> > > > > > association to a process thread.
> > > > >
> > > > > I spent some time this morning/afternoon playing with the io_uring
> > > > > audit filtering capability and with your audit userspace
> > > > > ghau-iouring-filtering.v1.0 branch it appears to work correctly.  Yes,
> > > > > the userspace tooling isn't quite 100% yet (e.g. `auditctl -l` doesn't
> > > > > map the io_uring ops correctly), but I know you mentioned you have a
> > > > > number of fixes/improvements still as a work-in-progress there so I'm
> > > > > not too concerned.  The important part is that the kernel pieces look
> > > > > to be working correctly.
> > > >
> > > > Ok, I have squashed and pushed the audit userspace support for iouring:
> > > >         https://github.com/rgbriggs/audit-userspace/commit/e8bd8d2ea8adcaa758024cb9b8fa93895ae35eea
> > > >         https://github.com/linux-audit/audit-userspace/compare/master...rgbriggs:ghak-iouring-filtering.v2.1
> > > > There are test rpms for f35 here:
> > > >         http://people.redhat.com/~rbriggs/ghak-iouring/git-e8bd8d2-fc35/
> > > >
> > > > userspace v2 changelog:
> > > > - check for watch before adding perm
> > > > - update manpage to include filesystem filter
> > > > - update support for the uring filter list: doc, -U op, op names
> > > > - add support for the AUDIT_URINGOP record type
> > > > - add uringop support to ausearch
> > > > - add uringop support to aureport
> > > > - lots of bug fixes
> > > >
> > > > "auditctl -a uring,always -S ..." will now throw an error and require
> > > > "-U" instead.
> > >
> > > Thanks Richard.
> > >
> > > FYI, I rebased the io_uring/LSM/audit patchset on top of v5.15-rc1
> > > today and tested both with your v1.0 and with your v2.1 branch and the
> > > various combinations seemed to work just fine (of course the v2.1
> > > userspace branch was more polished, less warts, etc.).  I'm going to
> > > go over the patch set one more time to make sure everything is still
> > > looking good, write up an updated cover letter, and post a v3 revision
> > > later tonight with the hope of merging it into -next later this week.
> >
> > Best laid plans of mice and men ...
> >
> > It turns out the LSM hook macros are full of warnings-now-errors that
> > should likely be resolved before sending anything LSM related to
> > Linus.  I'll post v3 once I fix this, which may not be until tomorrow.
> >
> > (To be clear, the warnings/errors aren't new to this patchset, I'm
> > likely just the first person to notice them.)
> 
> Actually, scratch that ... I'm thinking that might just be an oddity
> of the Intel 0day test robot building for the xtensa arch.  I'll post
> the v3 patchset tonight.

I was in the middle of reviewing the v2 patchset to add my acks when I
forgot to add the comment that you still haven't convinced me that ses=
isn't needed or relevant if we are including auid=.

> paul moore

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
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] 35+ messages in thread

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-15 12:29                             ` Richard Guy Briggs
@ 2021-09-15 13:02                               ` Steve Grubb
  2021-09-15 14:12                               ` Paul Moore
  1 sibling, 0 replies; 35+ messages in thread
From: Steve Grubb @ 2021-09-15 13:02 UTC (permalink / raw)
  To: Paul Moore, Richard Guy Briggs
  Cc: linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Wednesday, September 15, 2021 8:29:08 AM EDT Richard Guy Briggs wrote:
> I was in the middle of reviewing the v2 patchset to add my acks when I
> forgot to add the comment that you still haven't convinced me that ses=
> isn't needed or relevant if we are including auid=.

The session id is needed to disambiguate which login the event belongs to. It 
is necessary sometimes to trace an event back to the login because it was a 
remote login from an unexpected IP address.

-Steve



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

* Re: [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring
  2021-09-15 12:29                             ` Richard Guy Briggs
  2021-09-15 13:02                               ` Steve Grubb
@ 2021-09-15 14:12                               ` Paul Moore
  1 sibling, 0 replies; 35+ messages in thread
From: Paul Moore @ 2021-09-15 14:12 UTC (permalink / raw)
  To: Richard Guy Briggs
  Cc: sgrubb, linux-security-module, selinux, linux-audit, io-uring,
	linux-fsdevel, Kumar Kartikeya Dwivedi, Jens Axboe,
	Pavel Begunkov

On Wed, Sep 15, 2021 at 8:29 AM Richard Guy Briggs <rgb@redhat.com> wrote:
> I was in the middle of reviewing the v2 patchset to add my acks when I
> forgot to add the comment that you still haven't convinced me that ses=
> isn't needed or relevant if we are including auid=.

[Side note: v3 was posted on Monday, it would be more helpful to see
the Reviewed-by tags on the v3 patchset.]

Ah, okay, it wasn't clear to me from your earlier comments that this
was your concern.  It sounded as if you were arguing that both session
ID and audit ID needed to be logged for every io_uring op, which
doesn't make sense (as previously discussed).  However, I see your
point, and in fact pulling the audit ID from @current in the
audit_log_uring() function is just plain wrong ... likely a vestige of
the original copy-n-paste or format matching, I'll drop that now.
Thanks.

While a small code change, it is somewhat significant so I'll post an
updated v4 patchset later today once it passes through a round of
testing.

-- 
paul moore
www.paul-moore.com

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

end of thread, other threads:[~2021-09-15 14:12 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-11 20:48 [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 1/9] audit: prepare audit_context for use in calling contexts beyond syscalls Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 2/9] audit,io_uring,io-wq: add some basic audit support to io_uring Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 3/9] audit: dev/test patch to force io_uring auditing Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 4/9] audit: add filtering for io_uring records Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 5/9] fs: add anon_inode_getfile_secure() similar to anon_inode_getfd_secure() Paul Moore
2021-08-12  9:32   ` Mickaël Salaün
2021-08-12 14:32     ` Paul Moore
2021-08-12 15:35       ` Mickaël Salaün
2021-08-11 20:48 ` [RFC PATCH v2 6/9] io_uring: convert io_uring to the secure anon inode interface Paul Moore
2021-08-11 20:48 ` [RFC PATCH v2 7/9] lsm,io_uring: add LSM hooks to io_uring Paul Moore
2021-08-11 20:49 ` [RFC PATCH v2 8/9] selinux: add support for the io_uring access controls Paul Moore
2021-08-11 20:49 ` [RFC PATCH v2 9/9] Smack: Brutalist io_uring support with debug Paul Moore
2021-08-31 14:44   ` Paul Moore
2021-08-31 15:03     ` Casey Schaufler
2021-08-31 16:43       ` Paul Moore
2021-08-24 20:57 ` [RFC PATCH v2 0/9] Add LSM access controls and auditing to io_uring Richard Guy Briggs
2021-08-24 22:27   ` Paul Moore
2021-08-25  1:36     ` Richard Guy Briggs
2021-08-26  1:16   ` Richard Guy Briggs
2021-08-26  1:34     ` Paul Moore
2021-08-26 16:32       ` Richard Guy Briggs
2021-08-26 19:14         ` Paul Moore
2021-08-27 13:35           ` Richard Guy Briggs
2021-08-27 19:49             ` Paul Moore
2021-08-28 15:03               ` Richard Guy Briggs
2021-08-29 15:18                 ` Paul Moore
2021-09-01 19:21                   ` Paul Moore
2021-09-10  0:58                     ` Richard Guy Briggs
2021-09-13 19:23                       ` Paul Moore
2021-09-14  1:50                         ` Paul Moore
2021-09-14  2:49                           ` Paul Moore
2021-09-15 12:29                             ` Richard Guy Briggs
2021-09-15 13:02                               ` Steve Grubb
2021-09-15 14:12                               ` Paul Moore

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).