diff mbox series

[2/3] selinux: implement the security_uring_cmd() LSM hook

Message ID 166120327379.369593.4939320600435400704.stgit@olly (mailing list archive)
State Handled Elsewhere
Delegated to: Paul Moore
Headers show
Series LSM hooks for IORING_OP_URING_CMD | expand

Commit Message

Paul Moore Aug. 22, 2022, 9:21 p.m. UTC
Add a SELinux access control for the iouring IORING_OP_URING_CMD
command.  This includes the addition of a new permission in the
existing "io_uring" object class: "cmd".  The subject of the new
permission check is the domain of the process requesting access, the
object is the open file which points to the device/file that is the
target of the IORING_OP_URING_CMD operation.  A sample policy rule
is shown below:

  allow <domain> <file>:io_uring { cmd };

Cc: stable@vger.kernel.org
Fixes: ee692a21e9bf ("fs,io_uring: add infrastructure for uring-cmd")
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
 security/selinux/hooks.c            |   24 ++++++++++++++++++++++++
 security/selinux/include/classmap.h |    2 +-
 2 files changed, 25 insertions(+), 1 deletion(-)

Comments

Greg Kroah-Hartman Aug. 23, 2022, 6:52 a.m. UTC | #1
On Mon, Aug 22, 2022 at 05:21:13PM -0400, Paul Moore wrote:
> Add a SELinux access control for the iouring IORING_OP_URING_CMD
> command.  This includes the addition of a new permission in the
> existing "io_uring" object class: "cmd".  The subject of the new
> permission check is the domain of the process requesting access, the
> object is the open file which points to the device/file that is the
> target of the IORING_OP_URING_CMD operation.  A sample policy rule
> is shown below:
> 
>   allow <domain> <file>:io_uring { cmd };
> 
> Cc: stable@vger.kernel.org

This is not stable material as you are adding a new feature.  Please
read the stable documentation for what is and is not allowed.

thanks,

greg k-h
Paul Moore Aug. 23, 2022, 4:49 p.m. UTC | #2
On Tue, Aug 23, 2022 at 2:52 AM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> On Mon, Aug 22, 2022 at 05:21:13PM -0400, Paul Moore wrote:
> > Add a SELinux access control for the iouring IORING_OP_URING_CMD
> > command.  This includes the addition of a new permission in the
> > existing "io_uring" object class: "cmd".  The subject of the new
> > permission check is the domain of the process requesting access, the
> > object is the open file which points to the device/file that is the
> > target of the IORING_OP_URING_CMD operation.  A sample policy rule
> > is shown below:
> >
> >   allow <domain> <file>:io_uring { cmd };
> >
> > Cc: stable@vger.kernel.org
>
> This is not stable material as you are adding a new feature.  Please
> read the stable documentation for what is and is not allowed.

Strongly disagree, see my comments on patch 1/3 in this patchset.
Joel Granados Sept. 1, 2022, 8:15 p.m. UTC | #3
Hey Paul

I realize that you have already sent this upstream but I wanted to share
the Selinux part of the testing that we did to see if there is any
feedback.

With my tests I see that the selinux_uring_cmd hook is run and it
results in a "avc : denied" when I run it with selinux in permissive
mode with an unpriviledged user. I assume that this is the expected
behavior. Here is how I tested

*** With the patch:
* I ran the io_uring_passthrough.c test on a char device with an
  unpriviledged user.
* I took care of changing the permissions of /dev/ng0n1 to 666 prior
  to any testing.
* made sure that Selinux was in permissive mode.
* Made sure to have audit activated by passing "audit=1" to the kernel
* After noticing that some audit messages where getting lost I upped the
  backlog limit to 256
* Prior to executing the test, I also placed a breakpoint inside
  selinux_uring_cmd to make sure that it was executed.
* This is the output of the audit when I executed the test:

  [  136.615924] audit: type=1400 audit(1662043624.701:94): avc:  denied  { create } for  pid=263 comm="io_uring_passth" anonclass=[io_uring] scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
  [  136.621036] audit: type=1300 audit(1662043624.701:94): arch=c000003e syscall=425 success=yes exit=3 a0=40 a1=7ffca29835a0 a2=7ffca29835a0 a3=561529be2300 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
  [  136.624812] audit: type=1327 audit(1662043624.701:94): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
  [  136.626074] audit: type=1400 audit(1662043624.702:95): avc:  denied  { map } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
  [  136.628012] audit: type=1400 audit(1662043624.702:95): avc:  denied  { read write } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
  [  136.629873] audit: type=1300 audit(1662043624.702:95): arch=c000003e syscall=9 success=yes exit=140179765297152 a0=0 a1=1380 a2=3 a3=8001 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
  [  136.632415] audit: type=1327 audit(1662043624.702:95): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
  [  136.633652] audit: type=1400 audit(1662043624.705:96): avc:  denied  { cmd } for  pid=263 comm="io_uring_passth" path="/dev/ng0n1" dev="devtmpfs" ino=120 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:device_t tclass=io_uring permissive=1
  [  136.635384] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
  [  136.636863] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)

* From the output on time 136.633652 I see that the access should have
  been denied had selinux been enforcing. 
* I also saw that the breakpoint hit.

*** Without the patch:
* I ran the io_uring_passthrough.c test on a char device with an
  unpriviledged user.
* I took care of changing the permissions of /dev/ng0n1 to 666 prior
  to any testing.
* made sure that Selinux was in permissive mode.
* Made sure to have audit activated by passing "audit=1" to the kernel
* After noticing that some audit messages where getting lost I upped the
  backlog limit to 256
* There were no audit messages when I executed the test.

As with my smack tests I would really appreciate feecback on the
approach I took to testing and it's validity.

Thx in advance

Best


On Mon, Aug 22, 2022 at 05:21:13PM -0400, Paul Moore wrote:
> Add a SELinux access control for the iouring IORING_OP_URING_CMD
> command.  This includes the addition of a new permission in the
> existing "io_uring" object class: "cmd".  The subject of the new
> permission check is the domain of the process requesting access, the
> object is the open file which points to the device/file that is the
> target of the IORING_OP_URING_CMD operation.  A sample policy rule
> is shown below:
> 
>   allow <domain> <file>:io_uring { cmd };
> 
> Cc: stable@vger.kernel.org
> Fixes: ee692a21e9bf ("fs,io_uring: add infrastructure for uring-cmd")
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>  security/selinux/hooks.c            |   24 ++++++++++++++++++++++++
>  security/selinux/include/classmap.h |    2 +-
>  2 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 79573504783b..03bca97c8b29 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -91,6 +91,7 @@
>  #include <uapi/linux/mount.h>
>  #include <linux/fsnotify.h>
>  #include <linux/fanotify.h>
> +#include <linux/io_uring.h>
>  
>  #include "avc.h"
>  #include "objsec.h"
> @@ -6987,6 +6988,28 @@ static int selinux_uring_sqpoll(void)
>  	return avc_has_perm(&selinux_state, sid, sid,
>  			    SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
>  }
> +
> +/**
> + * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
> + * @ioucmd: the io_uring command structure
> + *
> + * Check to see if the current domain is allowed to execute an
> + * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
> + *
> + */
> +static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
> +{
> +	struct file *file = ioucmd->file;
> +	struct inode *inode = file_inode(file);
> +	struct inode_security_struct *isec = selinux_inode(inode);
> +	struct common_audit_data ad;
> +
> +	ad.type = LSM_AUDIT_DATA_FILE;
> +	ad.u.file = file;
> +
> +	return avc_has_perm(&selinux_state, current_sid(), isec->sid,
> +			    SECCLASS_IO_URING, IO_URING__CMD, &ad);
> +}
>  #endif /* CONFIG_IO_URING */
>  
>  /*
> @@ -7231,6 +7254,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
>  #ifdef CONFIG_IO_URING
>  	LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
>  	LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
> +	LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
>  #endif
>  
>  	/*
> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> index ff757ae5f253..1c2f41ff4e55 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -253,7 +253,7 @@ const struct security_class_mapping secclass_map[] = {
>  	{ "anon_inode",
>  	  { COMMON_FILE_PERMS, NULL } },
>  	{ "io_uring",
> -	  { "override_creds", "sqpoll", NULL } },
> +	  { "override_creds", "sqpoll", "cmd", NULL } },
>  	{ NULL }
>    };
>  
>
Paul Moore Sept. 1, 2022, 9:30 p.m. UTC | #4
On Thu, Sep 1, 2022 at 4:15 PM Joel Granados <j.granados@samsung.com> wrote:
> Hey Paul
>
> I realize that you have already sent this upstream but I wanted to share
> the Selinux part of the testing that we did to see if there is any
> feedback.
>
> With my tests I see that the selinux_uring_cmd hook is run and it
> results in a "avc : denied" when I run it with selinux in permissive
> mode with an unpriviledged user. I assume that this is the expected
> behavior. Here is how I tested
>
> *** With the patch:
> * I ran the io_uring_passthrough.c test on a char device with an
>   unpriviledged user.
> * I took care of changing the permissions of /dev/ng0n1 to 666 prior
>   to any testing.
> * made sure that Selinux was in permissive mode.
> * Made sure to have audit activated by passing "audit=1" to the kernel
> * After noticing that some audit messages where getting lost I upped the
>   backlog limit to 256
> * Prior to executing the test, I also placed a breakpoint inside
>   selinux_uring_cmd to make sure that it was executed.
> * This is the output of the audit when I executed the test:
>
>   [  136.615924] audit: type=1400 audit(1662043624.701:94): avc:  denied  { create } for  pid=263 comm="io_uring_passth" anonclass=[io_uring] scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
>   [  136.621036] audit: type=1300 audit(1662043624.701:94): arch=c000003e syscall=425 success=yes exit=3 a0=40 a1=7ffca29835a0 a2=7ffca29835a0 a3=561529be2300 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
>   [  136.624812] audit: type=1327 audit(1662043624.701:94): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
>   [  136.626074] audit: type=1400 audit(1662043624.702:95): avc:  denied  { map } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
>   [  136.628012] audit: type=1400 audit(1662043624.702:95): avc:  denied  { read write } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
>   [  136.629873] audit: type=1300 audit(1662043624.702:95): arch=c000003e syscall=9 success=yes exit=140179765297152 a0=0 a1=1380 a2=3 a3=8001 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
>   [  136.632415] audit: type=1327 audit(1662043624.702:95): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
>   [  136.633652] audit: type=1400 audit(1662043624.705:96): avc:  denied  { cmd } for  pid=263 comm="io_uring_passth" path="/dev/ng0n1" dev="devtmpfs" ino=120 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:device_t tclass=io_uring permissive=1
>   [  136.635384] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
>   [  136.636863] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
>
> * From the output on time 136.633652 I see that the access should have
>   been denied had selinux been enforcing.
> * I also saw that the breakpoint hit.
>
> *** Without the patch:
> * I ran the io_uring_passthrough.c test on a char device with an
>   unpriviledged user.
> * I took care of changing the permissions of /dev/ng0n1 to 666 prior
>   to any testing.
> * made sure that Selinux was in permissive mode.
> * Made sure to have audit activated by passing "audit=1" to the kernel
> * After noticing that some audit messages where getting lost I upped the
>   backlog limit to 256
> * There were no audit messages when I executed the test.
>
> As with my smack tests I would really appreciate feecback on the
> approach I took to testing and it's validity.

Hi Joel,

Thanks for the additional testing and verification!  Work like this is
always welcome, regardless if the patch has already been merged
upstream.

As far as you test approach is concerned, I think you are on the right
track, I might suggest resolving the other SELinux/AVC denials you are
seeing with your test application to help reduce the noise in the
logs.  Are you familiar with the selinux-testsuite (link below)?

* https://github.com/SELinuxProject/selinux-testsuite
Joel Granados Sept. 7, 2022, 8:17 a.m. UTC | #5
Hey Paul

On Thu, Sep 01, 2022 at 05:30:38PM -0400, Paul Moore wrote:
> On Thu, Sep 1, 2022 at 4:15 PM Joel Granados <j.granados@samsung.com> wrote:
> > Hey Paul
> >
> > I realize that you have already sent this upstream but I wanted to share
> > the Selinux part of the testing that we did to see if there is any
> > feedback.
> >
> > With my tests I see that the selinux_uring_cmd hook is run and it
> > results in a "avc : denied" when I run it with selinux in permissive
> > mode with an unpriviledged user. I assume that this is the expected
> > behavior. Here is how I tested
> >
> > *** With the patch:
> > * I ran the io_uring_passthrough.c test on a char device with an
> >   unpriviledged user.
> > * I took care of changing the permissions of /dev/ng0n1 to 666 prior
> >   to any testing.
> > * made sure that Selinux was in permissive mode.
> > * Made sure to have audit activated by passing "audit=1" to the kernel
> > * After noticing that some audit messages where getting lost I upped the
> >   backlog limit to 256
> > * Prior to executing the test, I also placed a breakpoint inside
> >   selinux_uring_cmd to make sure that it was executed.
> > * This is the output of the audit when I executed the test:
> >
> >   [  136.615924] audit: type=1400 audit(1662043624.701:94): avc:  denied  { create } for  pid=263 comm="io_uring_passth" anonclass=[io_uring] scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> >   [  136.621036] audit: type=1300 audit(1662043624.701:94): arch=c000003e syscall=425 success=yes exit=3 a0=40 a1=7ffca29835a0 a2=7ffca29835a0 a3=561529be2300 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
> >   [  136.624812] audit: type=1327 audit(1662043624.701:94): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
> >   [  136.626074] audit: type=1400 audit(1662043624.702:95): avc:  denied  { map } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> >   [  136.628012] audit: type=1400 audit(1662043624.702:95): avc:  denied  { read write } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> >   [  136.629873] audit: type=1300 audit(1662043624.702:95): arch=c000003e syscall=9 success=yes exit=140179765297152 a0=0 a1=1380 a2=3 a3=8001 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
> >   [  136.632415] audit: type=1327 audit(1662043624.702:95): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
> >   [  136.633652] audit: type=1400 audit(1662043624.705:96): avc:  denied  { cmd } for  pid=263 comm="io_uring_passth" path="/dev/ng0n1" dev="devtmpfs" ino=120 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:device_t tclass=io_uring permissive=1
> >   [  136.635384] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
> >   [  136.636863] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
> >
> > * From the output on time 136.633652 I see that the access should have
> >   been denied had selinux been enforcing.
> > * I also saw that the breakpoint hit.
> >
> > *** Without the patch:
> > * I ran the io_uring_passthrough.c test on a char device with an
> >   unpriviledged user.
> > * I took care of changing the permissions of /dev/ng0n1 to 666 prior
> >   to any testing.
> > * made sure that Selinux was in permissive mode.
> > * Made sure to have audit activated by passing "audit=1" to the kernel
> > * After noticing that some audit messages where getting lost I upped the
> >   backlog limit to 256
> > * There were no audit messages when I executed the test.
> >
> > As with my smack tests I would really appreciate feecback on the
> > approach I took to testing and it's validity.
> 
> Hi Joel,
> 
> Thanks for the additional testing and verification!  Work like this is
> always welcome, regardless if the patch has already been merged
> upstream.
np

> 
> As far as you test approach is concerned, I think you are on the right
> track, I might suggest resolving the other SELinux/AVC denials you are
> seeing with your test application to help reduce the noise in the
> logs.  Are you familiar with the selinux-testsuite (link below)?
> 
> * https://protect2.fireeye.com/v1/url?k=6f356c96-0ebe79ac-6f34e7d9-74fe4860008a-01002a6e4c92bb3e&q=1&e=46f33488-9311-49fa-9747-da210f2d147d&u=https%3A%2F%2Fgithub.com%2FSELinuxProject%2Fselinux-testsuite
Thx. Could not figure out how to remove the AVC from a quick look at the
page, but I'll probably figures something out :).

ATM, I'm doing a performance test on the io_uring_passtrhough
path to see how much, if any, perf we loose.

Thx again

Best

Joel

> 
> -- 
> paul-moore.com
Joel Granados Sept. 16, 2022, 12:59 p.m. UTC | #6
Hello.

Took the time to re-run my performance tests on the current LSM patch
for io_uring_cmd. I'll explain what I did and then give the results:

How I ran it:
I took a version of the kernel with the patch a0d2212773d1 and then
compiled two versions: The first was the vanilla kernel and the other
was the same except for the LSM hook called from io_uring_cmd removed.
Same kernel configurations. For my tests I used one of the test files
from FIO called t/io_uring.c which is basically a READ test. I ran my
tests on both an nvme device and the null device (/dev/null). For the
first I did not change io_uring.c and for the second I replaced the
admin calls with dummy data that was not really needed for testing with
/dev/null. These are the arguments I used for the test
"./t/io_uring -b4096 -d128 -c32 -s32 -p0 -F1 -B0 -O0 -P1 -u1 -n1"
Finally, I'm taking the max of several samples.

Results:
+-------------------------------------+------------------------+-----------------------+
|                Name                 | /dev/ng0n1 (BW: MiB/s) | /dev/null (BW: GiB/s) |
+-------------------------------------+------------------------+-----------------------+
| (A) for-next (vanilla)              |                   1341 |                 30.16 |
| (B) for-next (no io_uring_cmd hook) |                   1362 |                 40.61 |
| [1-(A/B)] * 100                     |             1.54185022 |          25.732578183 |
+-------------------------------------+------------------------+-----------------------+

So on a device (dev/ng0n1) there is a 1% performance difference on a
read. Whereas on the null device (dev/null) there is a 25% difference on
a read.

This difference is interesting and expected as there is a lot more stuff
happening when we go through the actual device.

Best

Joel

On Wed, Sep 07, 2022 at 10:17:29AM +0200, Joel Granados wrote:
> Hey Paul
> 
> On Thu, Sep 01, 2022 at 05:30:38PM -0400, Paul Moore wrote:
> > On Thu, Sep 1, 2022 at 4:15 PM Joel Granados <j.granados@samsung.com> wrote:
> > > Hey Paul
> > >
> > > I realize that you have already sent this upstream but I wanted to share
> > > the Selinux part of the testing that we did to see if there is any
> > > feedback.
> > >
> > > With my tests I see that the selinux_uring_cmd hook is run and it
> > > results in a "avc : denied" when I run it with selinux in permissive
> > > mode with an unpriviledged user. I assume that this is the expected
> > > behavior. Here is how I tested
> > >
> > > *** With the patch:
> > > * I ran the io_uring_passthrough.c test on a char device with an
> > >   unpriviledged user.
> > > * I took care of changing the permissions of /dev/ng0n1 to 666 prior
> > >   to any testing.
> > > * made sure that Selinux was in permissive mode.
> > > * Made sure to have audit activated by passing "audit=1" to the kernel
> > > * After noticing that some audit messages where getting lost I upped the
> > >   backlog limit to 256
> > > * Prior to executing the test, I also placed a breakpoint inside
> > >   selinux_uring_cmd to make sure that it was executed.
> > > * This is the output of the audit when I executed the test:
> > >
> > >   [  136.615924] audit: type=1400 audit(1662043624.701:94): avc:  denied  { create } for  pid=263 comm="io_uring_passth" anonclass=[io_uring] scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> > >   [  136.621036] audit: type=1300 audit(1662043624.701:94): arch=c000003e syscall=425 success=yes exit=3 a0=40 a1=7ffca29835a0 a2=7ffca29835a0 a3=561529be2300 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
> > >   [  136.624812] audit: type=1327 audit(1662043624.701:94): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
> > >   [  136.626074] audit: type=1400 audit(1662043624.702:95): avc:  denied  { map } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> > >   [  136.628012] audit: type=1400 audit(1662043624.702:95): avc:  denied  { read write } for  pid=263 comm="io_uring_passth" path="anon_inode:[io_uring]" dev="anon_inodefs" ino=11715 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:kernel_t tclass=anon_inode permissive=1
> > >   [  136.629873] audit: type=1300 audit(1662043624.702:95): arch=c000003e syscall=9 success=yes exit=140179765297152 a0=0 a1=1380 a2=3 a3=8001 items=0 ppid=252 pid=263 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts1 ses=3 comm="io_uring_passth" exe="/mnt/src/liburing/test/io_uring_passthrough.t" subj=system_u:system_r:kernel_t key=(null)
> > >   [  136.632415] audit: type=1327 audit(1662043624.702:95): proctitle=2F6D6E742F7372632F6C69627572696E672F746573742F696F5F7572696E675F706173737468726F7567682E74002F6465762F6E67306E31
> > >   [  136.633652] audit: type=1400 audit(1662043624.705:96): avc:  denied  { cmd } for  pid=263 comm="io_uring_passth" path="/dev/ng0n1" dev="devtmpfs" ino=120 scontext=system_u:system_r:kernel_t tcontext=system_u:object_r:device_t tclass=io_uring permissive=1
> > >   [  136.635384] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
> > >   [  136.636863] audit: type=1336 audit(1662043624.705:96): uring_op=46 items=0 ppid=252 pid=263 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 subj=system_u:system_r:kernel_t key=(null)
> > >
> > > * From the output on time 136.633652 I see that the access should have
> > >   been denied had selinux been enforcing.
> > > * I also saw that the breakpoint hit.
> > >
> > > *** Without the patch:
> > > * I ran the io_uring_passthrough.c test on a char device with an
> > >   unpriviledged user.
> > > * I took care of changing the permissions of /dev/ng0n1 to 666 prior
> > >   to any testing.
> > > * made sure that Selinux was in permissive mode.
> > > * Made sure to have audit activated by passing "audit=1" to the kernel
> > > * After noticing that some audit messages where getting lost I upped the
> > >   backlog limit to 256
> > > * There were no audit messages when I executed the test.
> > >
> > > As with my smack tests I would really appreciate feecback on the
> > > approach I took to testing and it's validity.
> > 
> > Hi Joel,
> > 
> > Thanks for the additional testing and verification!  Work like this is
> > always welcome, regardless if the patch has already been merged
> > upstream.
> np
> 
> > 
> > As far as you test approach is concerned, I think you are on the right
> > track, I might suggest resolving the other SELinux/AVC denials you are
> > seeing with your test application to help reduce the noise in the
> > logs.  Are you familiar with the selinux-testsuite (link below)?
> > 
> > * https://protect2.fireeye.com/v1/url?k=6f356c96-0ebe79ac-6f34e7d9-74fe4860008a-01002a6e4c92bb3e&q=1&e=46f33488-9311-49fa-9747-da210f2d147d&u=https%3A%2F%2Fgithub.com%2FSELinuxProject%2Fselinux-testsuite
> Thx. Could not figure out how to remove the AVC from a quick look at the
> page, but I'll probably figures something out :).
> 
> ATM, I'm doing a performance test on the io_uring_passtrhough
> path to see how much, if any, perf we loose.
> 
> Thx again
> 
> Best
> 
> Joel
> 
> > 
> > -- 
> > paul-moore.com
diff mbox series

Patch

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 79573504783b..03bca97c8b29 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,6 +91,7 @@ 
 #include <uapi/linux/mount.h>
 #include <linux/fsnotify.h>
 #include <linux/fanotify.h>
+#include <linux/io_uring.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -6987,6 +6988,28 @@  static int selinux_uring_sqpoll(void)
 	return avc_has_perm(&selinux_state, sid, sid,
 			    SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
 }
+
+/**
+ * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
+ * @ioucmd: the io_uring command structure
+ *
+ * Check to see if the current domain is allowed to execute an
+ * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
+ *
+ */
+static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+	struct file *file = ioucmd->file;
+	struct inode *inode = file_inode(file);
+	struct inode_security_struct *isec = selinux_inode(inode);
+	struct common_audit_data ad;
+
+	ad.type = LSM_AUDIT_DATA_FILE;
+	ad.u.file = file;
+
+	return avc_has_perm(&selinux_state, current_sid(), isec->sid,
+			    SECCLASS_IO_URING, IO_URING__CMD, &ad);
+}
 #endif /* CONFIG_IO_URING */
 
 /*
@@ -7231,6 +7254,7 @@  static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 #ifdef CONFIG_IO_URING
 	LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
 	LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
+	LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
 #endif
 
 	/*
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index ff757ae5f253..1c2f41ff4e55 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -253,7 +253,7 @@  const struct security_class_mapping secclass_map[] = {
 	{ "anon_inode",
 	  { COMMON_FILE_PERMS, NULL } },
 	{ "io_uring",
-	  { "override_creds", "sqpoll", NULL } },
+	  { "override_creds", "sqpoll", "cmd", NULL } },
 	{ NULL }
   };