Message ID | 20201125125402.211692-1-lokeshgidra@google.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Ondrej Mosnáček |
Headers | show |
Series | [v1,1/1] selinux-testsuite: Add userfaultfd test | expand |
Hi Lokesh, On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > Confirm SELinux policies are enforced on userfaultfd operations > via secure anon-inode interface. > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > --- > policy/Makefile | 2 +- > policy/userfaultfd.cil | 17 ++++++++++++ > tests/Makefile | 2 +- > tests/userfaultfd/Makefile | 3 ++ > tests/userfaultfd/test | 15 ++++++++++ > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > 6 files changed, 86 insertions(+), 2 deletions(-) > create mode 100644 policy/userfaultfd.cil > create mode 100644 tests/userfaultfd/Makefile > create mode 100755 tests/userfaultfd/test > create mode 100644 tests/userfaultfd/userfaultfd.c > > diff --git a/policy/Makefile b/policy/Makefile > index 6c49091..02e7568 100644 > --- a/policy/Makefile > +++ b/policy/Makefile > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > endif > > ifeq ($(SUPPORTS_CIL),y) > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > # If other MLS tests get written this can be moved outside of the glblub test > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > new file mode 100644 > index 0000000..0743fff > --- /dev/null > +++ b/policy/userfaultfd.cil > @@ -0,0 +1,17 @@ > +(class anon_inode ()) > +(classcommon anon_inode file) > +(classorder (unordered anon_inode)) > +(type uffd_t) > +; Label the UFFD with uffd_t; this can be specialized per domain > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > +(allow unconfined_t uffd_t (anon_inode (create))) > +; Permit read() and ioctl() on the UFFD; > +; Comment out if you want to test read or basic ioctl enforcement. > +(allow unconfined_t uffd_t (anon_inode (read))) > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > +; Currently the first one is uncommented; comment that out if trying another. > +; None > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > +; UFFDIO_API > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > diff --git a/tests/Makefile b/tests/Makefile > index 4c00b5f..3871570 100644 > --- a/tests/Makefile > +++ b/tests/Makefile > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > task_setnice task_setscheduler task_getscheduler task_getsid \ > task_getpgid task_setpgid file ioctl capable_file capable_net \ > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > new file mode 100644 > index 0000000..66d02a1 > --- /dev/null > +++ b/tests/userfaultfd/Makefile > @@ -0,0 +1,3 @@ > +all: userfaultfd > +clean: > + rm -f userfaultfd > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > new file mode 100755 > index 0000000..dd42aa8 > --- /dev/null > +++ b/tests/userfaultfd/test > @@ -0,0 +1,15 @@ > +#!/usr/bin/perl > + > +use Test; > + > +BEGIN { > + plan tests => 1; > +} > + > +$basedir = $0; > +$basedir =~ s|(.*)/[^/]*|$1|; > + > +$result = system("$basedir/userfaultfd"); > +ok( $result, 0 ); This is a good start, but it is only a very basic test :) I would expect at least these tests here: 1. that an userfaultfd node created by a domain *without* the transition rule gets the context of the creating process (should be possible by calling fgetxattr(2) on the fd), 2. that an userfaultfd node created by a domain *with* the transition rule gets the context specified by the rule, 3. that a process with context that is *allowed* to { create read write [...] } a given userfaultfd type by the policy *can* indeed successfully perform these operations (or at least that the error returned is not -EACCESS), 4. that a process with context that is *NOT allowed* to { create read write [...] } a given userfaultfd type by the policy *cannot* perform these operations and the error returned is -EACCESS. (The more permissions you can test the better, but I'd like to see at least the three (create, read, write).) For this, you will need to define several process types in the test policy and run the test program(s) with a specific type using runcon (see e.g. policy/test_link.te and tests/link/test for a simple example). I suggest using the CIL module only for adding the class and permissions and a separate .te file to define the process and userfaultfd types (so that you can use the unconfined_runs_test() interface for common permissions needed for the process types). You will likely also need to communicate different locations of failures / error codes from the test program(s) to the script via exit code. See tests/keys for an example of such pattern (though you can use a different approach as long as it gets the job done :) Sorry for requiring all the effort, but we're trying to keep reasonably high standards for tests here. It's sometimes a PITA, but it pays off in the long run ;) Thanks, > + > +exit; > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > new file mode 100644 > index 0000000..9baebd9 > --- /dev/null > +++ b/tests/userfaultfd/userfaultfd.c > @@ -0,0 +1,49 @@ > +#include <stdio.h> > +#include <fcntl.h> > +#include <unistd.h> > + > +#include <sys/types.h> > +#include <sys/ioctl.h> > +#include <sys/syscall.h> > + > +#include <linux/userfaultfd.h> > + > +void print_api(const struct uffdio_api *api) > +{ > + printf("api: %llu\n", api->api); > + printf("features: %llu\n", api->features); > + printf("ioctls: %llu\n", api->ioctls); > + > + printf("\n"); > +} > + > +int main (void) > +{ > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > + if (uffd < 0) { > + perror("syscall(userfaultfd)"); > + return -1; > + } > + > + struct uffdio_api api = {0}; > + api.api = UFFD_API; > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > + perror("UFFDIO_API"); > + return -1; > + } > + > + print_api(&api); > + > + struct uffd_msg msg = {0}; > + ssize_t count = read(uffd, &msg, sizeof(msg)); > + if (count < 0) { > + // Expected to fail as no memory range registered. > + return 0; > + } else if (count == 0) { > + printf("read EOF\n\n"); > + } > + > + printf("read uffd\n\n"); > + > + return 0; > +} > -- > 2.28.0 > -- Ondrej Mosnacek Software Engineer, Platform Security - SELinux kernel Red Hat, Inc.
On Fri, Nov 27, 2020 at 9:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > Confirm SELinux policies are enforced on userfaultfd operations > > via secure anon-inode interface. > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> ... > This is a good start, but it is only a very basic test :) > > I would expect at least these tests here: > 1. ... Since it has been a while I wanted to check-in and see how this was going? Having a good test in place in the test suite is an important part of getting the kernel code merged.
On Wed, Dec 9, 2020 at 6:45 PM Paul Moore <paul@paul-moore.com> wrote: > > On Fri, Nov 27, 2020 at 9:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > Confirm SELinux policies are enforced on userfaultfd operations > > > via secure anon-inode interface. > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > ... > > > This is a good start, but it is only a very basic test :) > > > > I would expect at least these tests here: > > 1. ... > > Since it has been a while I wanted to check-in and see how this was > going? Having a good test in place in the test suite is an important > part of getting the kernel code merged. > Sorry for the delay. I got caught up in some other work. I'll send another patch addressing all the comments from Ondrej by the end of this week. > -- > paul moore > www.paul-moore.com
On Wed, Dec 9, 2020 at 10:27 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > On Wed, Dec 9, 2020 at 6:45 PM Paul Moore <paul@paul-moore.com> wrote: > > On Fri, Nov 27, 2020 at 9:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > > Confirm SELinux policies are enforced on userfaultfd operations > > > > via secure anon-inode interface. > > > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > > > ... > > > > > This is a good start, but it is only a very basic test :) > > > > > > I would expect at least these tests here: > > > 1. ... > > > > Since it has been a while I wanted to check-in and see how this was > > going? Having a good test in place in the test suite is an important > > part of getting the kernel code merged. > > > > Sorry for the delay. I got caught up in some other work. I'll send > another patch addressing all the comments from Ondrej by the end of > this week. No problem, thanks for the update.
Hi Ondrej, On Fri, Nov 27, 2020 at 6:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > Hi Lokesh, > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > Confirm SELinux policies are enforced on userfaultfd operations > > via secure anon-inode interface. > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > --- > > policy/Makefile | 2 +- > > policy/userfaultfd.cil | 17 ++++++++++++ > > tests/Makefile | 2 +- > > tests/userfaultfd/Makefile | 3 ++ > > tests/userfaultfd/test | 15 ++++++++++ > > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > > 6 files changed, 86 insertions(+), 2 deletions(-) > > create mode 100644 policy/userfaultfd.cil > > create mode 100644 tests/userfaultfd/Makefile > > create mode 100755 tests/userfaultfd/test > > create mode 100644 tests/userfaultfd/userfaultfd.c > > > > diff --git a/policy/Makefile b/policy/Makefile > > index 6c49091..02e7568 100644 > > --- a/policy/Makefile > > +++ b/policy/Makefile > > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > > endif > > > > ifeq ($(SUPPORTS_CIL),y) > > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > > # If other MLS tests get written this can be moved outside of the glblub test > > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > > new file mode 100644 > > index 0000000..0743fff > > --- /dev/null > > +++ b/policy/userfaultfd.cil > > @@ -0,0 +1,17 @@ > > +(class anon_inode ()) > > +(classcommon anon_inode file) > > +(classorder (unordered anon_inode)) > > +(type uffd_t) > > +; Label the UFFD with uffd_t; this can be specialized per domain > > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > > +(allow unconfined_t uffd_t (anon_inode (create))) > > +; Permit read() and ioctl() on the UFFD; > > +; Comment out if you want to test read or basic ioctl enforcement. > > +(allow unconfined_t uffd_t (anon_inode (read))) > > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > > +; Currently the first one is uncommented; comment that out if trying another. > > +; None > > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > > +; UFFDIO_API > > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > > diff --git a/tests/Makefile b/tests/Makefile > > index 4c00b5f..3871570 100644 > > --- a/tests/Makefile > > +++ b/tests/Makefile > > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > > task_setnice task_setscheduler task_getscheduler task_getsid \ > > task_getpgid task_setpgid file ioctl capable_file capable_net \ > > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > > new file mode 100644 > > index 0000000..66d02a1 > > --- /dev/null > > +++ b/tests/userfaultfd/Makefile > > @@ -0,0 +1,3 @@ > > +all: userfaultfd > > +clean: > > + rm -f userfaultfd > > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > > new file mode 100755 > > index 0000000..dd42aa8 > > --- /dev/null > > +++ b/tests/userfaultfd/test > > @@ -0,0 +1,15 @@ > > +#!/usr/bin/perl > > + > > +use Test; > > + > > +BEGIN { > > + plan tests => 1; > > +} > > + > > +$basedir = $0; > > +$basedir =~ s|(.*)/[^/]*|$1|; > > + > > +$result = system("$basedir/userfaultfd"); > > +ok( $result, 0 ); > > This is a good start, but it is only a very basic test :) > > I would expect at least these tests here: > 1. that an userfaultfd node created by a domain *without* the > transition rule gets the context of the creating process (should be > possible by calling fgetxattr(2) on the fd), > 2. that an userfaultfd node created by a domain *with* the transition > rule gets the context specified by the rule, > 3. that a process with context that is *allowed* to { create read > write [...] } a given userfaultfd type by the policy *can* indeed > successfully perform these operations (or at least that the error > returned is not -EACCESS), > 4. that a process with context that is *NOT allowed* to { create read > write [...] } a given userfaultfd type by the policy *cannot* perform > these operations and the error returned is -EACCESS. > > (The more permissions you can test the better, but I'd like to see at > least the three (create, read, write).) > > For this, you will need to define several process types in the test > policy and run the test program(s) with a specific type using runcon > (see e.g. policy/test_link.te and tests/link/test for a simple > example). I suggest using the CIL module only for adding the class and > permissions and a separate .te file to define the process and > userfaultfd types (so that you can use the unconfined_runs_test() > interface for common permissions needed for the process types). > I'm having a bit of a hard time managing the test policy in a cil module and a .te file. My inexperience with SELinux could be a reason :) I defined 'anon_inode' class, like in this patch in the CIL module as follows: (class anon_inode ()) (classcommon anon_inode file) (classorder (unordered anon_inode)) But then when I used anon_inode in the .te file as follows: ... type uffd_t; type_transition test_userfaultfd_t test_userfaultfd_t : anon_inode uffd_t "[userfaultfd]"; allow test_userfaultfd_t uffd_t:anon_inode { create ioctl read }; I get a compile error: test_policy.te:<line#>:ERROR 'unknown class anon_inode' at token ';' on line ... Any advice on where I am making mistakes? > You will likely also need to communicate different locations of > failures / error codes from the test program(s) to the script via exit > code. See tests/keys for an example of such pattern (though you can > use a different approach as long as it gets the job done :) > > Sorry for requiring all the effort, but we're trying to keep > reasonably high standards for tests here. It's sometimes a PITA, but > it pays off in the long run ;) > > Thanks, > > > + > > +exit; > > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > > new file mode 100644 > > index 0000000..9baebd9 > > --- /dev/null > > +++ b/tests/userfaultfd/userfaultfd.c > > @@ -0,0 +1,49 @@ > > +#include <stdio.h> > > +#include <fcntl.h> > > +#include <unistd.h> > > + > > +#include <sys/types.h> > > +#include <sys/ioctl.h> > > +#include <sys/syscall.h> > > + > > +#include <linux/userfaultfd.h> > > + > > +void print_api(const struct uffdio_api *api) > > +{ > > + printf("api: %llu\n", api->api); > > + printf("features: %llu\n", api->features); > > + printf("ioctls: %llu\n", api->ioctls); > > + > > + printf("\n"); > > +} > > + > > +int main (void) > > +{ > > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > > + if (uffd < 0) { > > + perror("syscall(userfaultfd)"); > > + return -1; > > + } > > + > > + struct uffdio_api api = {0}; > > + api.api = UFFD_API; > > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > > + perror("UFFDIO_API"); > > + return -1; > > + } > > + > > + print_api(&api); > > + > > + struct uffd_msg msg = {0}; > > + ssize_t count = read(uffd, &msg, sizeof(msg)); > > + if (count < 0) { > > + // Expected to fail as no memory range registered. > > + return 0; > > + } else if (count == 0) { > > + printf("read EOF\n\n"); > > + } > > + > > + printf("read uffd\n\n"); > > + > > + return 0; > > +} > > -- > > 2.28.0 > > > > -- > Ondrej Mosnacek > Software Engineer, Platform Security - SELinux kernel > Red Hat, Inc. >
On Fri, Dec 11, 2020 at 1:52 AM Lokesh Gidra <lokeshgidra@google.com> wrote: > Hi Ondrej, > On Fri, Nov 27, 2020 at 6:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > Hi Lokesh, > > > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > Confirm SELinux policies are enforced on userfaultfd operations > > > via secure anon-inode interface. > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > > --- > > > policy/Makefile | 2 +- > > > policy/userfaultfd.cil | 17 ++++++++++++ > > > tests/Makefile | 2 +- > > > tests/userfaultfd/Makefile | 3 ++ > > > tests/userfaultfd/test | 15 ++++++++++ > > > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > > > 6 files changed, 86 insertions(+), 2 deletions(-) > > > create mode 100644 policy/userfaultfd.cil > > > create mode 100644 tests/userfaultfd/Makefile > > > create mode 100755 tests/userfaultfd/test > > > create mode 100644 tests/userfaultfd/userfaultfd.c > > > > > > diff --git a/policy/Makefile b/policy/Makefile > > > index 6c49091..02e7568 100644 > > > --- a/policy/Makefile > > > +++ b/policy/Makefile > > > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > > > endif > > > > > > ifeq ($(SUPPORTS_CIL),y) > > > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > > > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > > > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > > > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > > > # If other MLS tests get written this can be moved outside of the glblub test > > > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > > > new file mode 100644 > > > index 0000000..0743fff > > > --- /dev/null > > > +++ b/policy/userfaultfd.cil > > > @@ -0,0 +1,17 @@ > > > +(class anon_inode ()) > > > +(classcommon anon_inode file) > > > +(classorder (unordered anon_inode)) > > > +(type uffd_t) > > > +; Label the UFFD with uffd_t; this can be specialized per domain > > > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > > > +(allow unconfined_t uffd_t (anon_inode (create))) > > > +; Permit read() and ioctl() on the UFFD; > > > +; Comment out if you want to test read or basic ioctl enforcement. > > > +(allow unconfined_t uffd_t (anon_inode (read))) > > > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > > > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > > > +; Currently the first one is uncommented; comment that out if trying another. > > > +; None > > > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > > > +; UFFDIO_API > > > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > > > diff --git a/tests/Makefile b/tests/Makefile > > > index 4c00b5f..3871570 100644 > > > --- a/tests/Makefile > > > +++ b/tests/Makefile > > > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > > > task_setnice task_setscheduler task_getscheduler task_getsid \ > > > task_getpgid task_setpgid file ioctl capable_file capable_net \ > > > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > > > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > > > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > > > > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > > > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > > > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > > > new file mode 100644 > > > index 0000000..66d02a1 > > > --- /dev/null > > > +++ b/tests/userfaultfd/Makefile > > > @@ -0,0 +1,3 @@ > > > +all: userfaultfd > > > +clean: > > > + rm -f userfaultfd > > > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > > > new file mode 100755 > > > index 0000000..dd42aa8 > > > --- /dev/null > > > +++ b/tests/userfaultfd/test > > > @@ -0,0 +1,15 @@ > > > +#!/usr/bin/perl > > > + > > > +use Test; > > > + > > > +BEGIN { > > > + plan tests => 1; > > > +} > > > + > > > +$basedir = $0; > > > +$basedir =~ s|(.*)/[^/]*|$1|; > > > + > > > +$result = system("$basedir/userfaultfd"); > > > +ok( $result, 0 ); > > > > This is a good start, but it is only a very basic test :) > > > > I would expect at least these tests here: > > 1. that an userfaultfd node created by a domain *without* the > > transition rule gets the context of the creating process (should be > > possible by calling fgetxattr(2) on the fd), > > 2. that an userfaultfd node created by a domain *with* the transition > > rule gets the context specified by the rule, > > 3. that a process with context that is *allowed* to { create read > > write [...] } a given userfaultfd type by the policy *can* indeed > > successfully perform these operations (or at least that the error > > returned is not -EACCESS), > > 4. that a process with context that is *NOT allowed* to { create read > > write [...] } a given userfaultfd type by the policy *cannot* perform > > these operations and the error returned is -EACCESS. > > > > (The more permissions you can test the better, but I'd like to see at > > least the three (create, read, write).) > > > > For this, you will need to define several process types in the test > > policy and run the test program(s) with a specific type using runcon > > (see e.g. policy/test_link.te and tests/link/test for a simple > > example). I suggest using the CIL module only for adding the class and > > permissions and a separate .te file to define the process and > > userfaultfd types (so that you can use the unconfined_runs_test() > > interface for common permissions needed for the process types). > > > I'm having a bit of a hard time managing the test policy in a cil > module and a .te file. My inexperience with SELinux could be a reason > :) > > I defined 'anon_inode' class, like in this patch in the CIL module as follows: > (class anon_inode ()) > (classcommon anon_inode file) > (classorder (unordered anon_inode)) > > But then when I used anon_inode in the .te file as follows: > ... > type uffd_t; > type_transition test_userfaultfd_t test_userfaultfd_t : anon_inode > uffd_t "[userfaultfd]"; > allow test_userfaultfd_t uffd_t:anon_inode { create ioctl read }; > > I get a compile error: > test_policy.te:<line#>:ERROR 'unknown class anon_inode' at token ';' on line ... > > Any advice on where I am making mistakes? Ouch! No, the mistake is mine :) I forgot that the classes/permissions added via CIL won't be available in the refpolicy build infrastructure... But I think it should be possible to define the types and add basic rules for them in .te and only add the necessary userfaultfd rules in the .cil file: test_userfaultfd_newclass.cil: ``` (class anon_inode ()) (classcommon anon_inode file) (classorder (unordered anon_inode)) (typeattributeset cil_gen_require test_userfaultfd_t) (typeattributeset cil_gen_require uffd_t) (typetransition test_userfaultfd_t test_userfaultfd_t anon_inode "[userfaultfd]" uffd_t) (allow test_userfaultfd_t uffd_t (anon_inode (create ioctl read))) [...] ``` test_userfaultfd.te: ``` type uffd_t; type test_userfaultfd_t; domain_type(test_userfaultfd_t) unconfined_runs_test(test_userfaultfd_t) typeattribute test_userfaultfd_t testdomain; [...] ``` We don't have an established way of handling the testing of new classes/permissions in the testsuite before they are defined in the distribution policy, but I think we could try this way here. The downside is that the rules are not in one place, but we can later merge everything into one .te file once the new class is widely available in the distribution policies. > > You will likely also need to communicate different locations of > > failures / error codes from the test program(s) to the script via exit > > code. See tests/keys for an example of such pattern (though you can > > use a different approach as long as it gets the job done :) > > > > Sorry for requiring all the effort, but we're trying to keep > > reasonably high standards for tests here. It's sometimes a PITA, but > > it pays off in the long run ;) > > > > Thanks, > > > > > + > > > +exit; > > > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > > > new file mode 100644 > > > index 0000000..9baebd9 > > > --- /dev/null > > > +++ b/tests/userfaultfd/userfaultfd.c > > > @@ -0,0 +1,49 @@ > > > +#include <stdio.h> > > > +#include <fcntl.h> > > > +#include <unistd.h> > > > + > > > +#include <sys/types.h> > > > +#include <sys/ioctl.h> > > > +#include <sys/syscall.h> > > > + > > > +#include <linux/userfaultfd.h> > > > + > > > +void print_api(const struct uffdio_api *api) > > > +{ > > > + printf("api: %llu\n", api->api); > > > + printf("features: %llu\n", api->features); > > > + printf("ioctls: %llu\n", api->ioctls); > > > + > > > + printf("\n"); > > > +} > > > + > > > +int main (void) > > > +{ > > > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > > > + if (uffd < 0) { > > > + perror("syscall(userfaultfd)"); > > > + return -1; > > > + } > > > + > > > + struct uffdio_api api = {0}; > > > + api.api = UFFD_API; > > > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > > > + perror("UFFDIO_API"); > > > + return -1; > > > + } > > > + > > > + print_api(&api); > > > + > > > + struct uffd_msg msg = {0}; > > > + ssize_t count = read(uffd, &msg, sizeof(msg)); > > > + if (count < 0) { > > > + // Expected to fail as no memory range registered. > > > + return 0; > > > + } else if (count == 0) { > > > + printf("read EOF\n\n"); > > > + } > > > + > > > + printf("read uffd\n\n"); > > > + > > > + return 0; > > > +} > > > -- > > > 2.28.0 > > > > > > > -- > > Ondrej Mosnacek > > Software Engineer, Platform Security - SELinux kernel > > Red Hat, Inc. > > >
On Fri, Dec 11, 2020 at 1:11 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > On Fri, Dec 11, 2020 at 1:52 AM Lokesh Gidra <lokeshgidra@google.com> wrote: > > Hi Ondrej, > > On Fri, Nov 27, 2020 at 6:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > > > Hi Lokesh, > > > > > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > > Confirm SELinux policies are enforced on userfaultfd operations > > > > via secure anon-inode interface. > > > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > > > --- > > > > policy/Makefile | 2 +- > > > > policy/userfaultfd.cil | 17 ++++++++++++ > > > > tests/Makefile | 2 +- > > > > tests/userfaultfd/Makefile | 3 ++ > > > > tests/userfaultfd/test | 15 ++++++++++ > > > > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > > > > 6 files changed, 86 insertions(+), 2 deletions(-) > > > > create mode 100644 policy/userfaultfd.cil > > > > create mode 100644 tests/userfaultfd/Makefile > > > > create mode 100755 tests/userfaultfd/test > > > > create mode 100644 tests/userfaultfd/userfaultfd.c > > > > > > > > diff --git a/policy/Makefile b/policy/Makefile > > > > index 6c49091..02e7568 100644 > > > > --- a/policy/Makefile > > > > +++ b/policy/Makefile > > > > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > > > > endif > > > > > > > > ifeq ($(SUPPORTS_CIL),y) > > > > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > > > > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > > > > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > > > > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > > > > # If other MLS tests get written this can be moved outside of the glblub test > > > > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > > > > new file mode 100644 > > > > index 0000000..0743fff > > > > --- /dev/null > > > > +++ b/policy/userfaultfd.cil > > > > @@ -0,0 +1,17 @@ > > > > +(class anon_inode ()) > > > > +(classcommon anon_inode file) > > > > +(classorder (unordered anon_inode)) > > > > +(type uffd_t) > > > > +; Label the UFFD with uffd_t; this can be specialized per domain > > > > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > > > > +(allow unconfined_t uffd_t (anon_inode (create))) > > > > +; Permit read() and ioctl() on the UFFD; > > > > +; Comment out if you want to test read or basic ioctl enforcement. > > > > +(allow unconfined_t uffd_t (anon_inode (read))) > > > > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > > > > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > > > > +; Currently the first one is uncommented; comment that out if trying another. > > > > +; None > > > > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > > > > +; UFFDIO_API > > > > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > > > > diff --git a/tests/Makefile b/tests/Makefile > > > > index 4c00b5f..3871570 100644 > > > > --- a/tests/Makefile > > > > +++ b/tests/Makefile > > > > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > > > > task_setnice task_setscheduler task_getscheduler task_getsid \ > > > > task_getpgid task_setpgid file ioctl capable_file capable_net \ > > > > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > > > > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > > > > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > > > > > > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > > > > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > > > > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > > > > new file mode 100644 > > > > index 0000000..66d02a1 > > > > --- /dev/null > > > > +++ b/tests/userfaultfd/Makefile > > > > @@ -0,0 +1,3 @@ > > > > +all: userfaultfd > > > > +clean: > > > > + rm -f userfaultfd > > > > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > > > > new file mode 100755 > > > > index 0000000..dd42aa8 > > > > --- /dev/null > > > > +++ b/tests/userfaultfd/test > > > > @@ -0,0 +1,15 @@ > > > > +#!/usr/bin/perl > > > > + > > > > +use Test; > > > > + > > > > +BEGIN { > > > > + plan tests => 1; > > > > +} > > > > + > > > > +$basedir = $0; > > > > +$basedir =~ s|(.*)/[^/]*|$1|; > > > > + > > > > +$result = system("$basedir/userfaultfd"); > > > > +ok( $result, 0 ); > > > > > > This is a good start, but it is only a very basic test :) > > > > > > I would expect at least these tests here: > > > 1. that an userfaultfd node created by a domain *without* the > > > transition rule gets the context of the creating process (should be > > > possible by calling fgetxattr(2) on the fd), > > > 2. that an userfaultfd node created by a domain *with* the transition > > > rule gets the context specified by the rule, > > > 3. that a process with context that is *allowed* to { create read > > > write [...] } a given userfaultfd type by the policy *can* indeed > > > successfully perform these operations (or at least that the error > > > returned is not -EACCESS), > > > 4. that a process with context that is *NOT allowed* to { create read > > > write [...] } a given userfaultfd type by the policy *cannot* perform > > > these operations and the error returned is -EACCESS. > > > > > > (The more permissions you can test the better, but I'd like to see at > > > least the three (create, read, write).) > > > > > > For this, you will need to define several process types in the test > > > policy and run the test program(s) with a specific type using runcon > > > (see e.g. policy/test_link.te and tests/link/test for a simple > > > example). I suggest using the CIL module only for adding the class and > > > permissions and a separate .te file to define the process and > > > userfaultfd types (so that you can use the unconfined_runs_test() > > > interface for common permissions needed for the process types). > > > > > I'm having a bit of a hard time managing the test policy in a cil > > module and a .te file. My inexperience with SELinux could be a reason > > :) > > > > I defined 'anon_inode' class, like in this patch in the CIL module as follows: > > (class anon_inode ()) > > (classcommon anon_inode file) > > (classorder (unordered anon_inode)) > > > > But then when I used anon_inode in the .te file as follows: > > ... > > type uffd_t; > > type_transition test_userfaultfd_t test_userfaultfd_t : anon_inode > > uffd_t "[userfaultfd]"; > > allow test_userfaultfd_t uffd_t:anon_inode { create ioctl read }; > > > > I get a compile error: > > test_policy.te:<line#>:ERROR 'unknown class anon_inode' at token ';' on line ... > > > > Any advice on where I am making mistakes? > > Ouch! No, the mistake is mine :) I forgot that the classes/permissions > added via CIL won't be available in the refpolicy build > infrastructure... But I think it should be possible to define the > types and add basic rules for them in .te and only add the necessary > userfaultfd rules in the .cil file: > > test_userfaultfd_newclass.cil: > ``` > (class anon_inode ()) > (classcommon anon_inode file) > (classorder (unordered anon_inode)) > (typeattributeset cil_gen_require test_userfaultfd_t) > (typeattributeset cil_gen_require uffd_t) > (typetransition test_userfaultfd_t test_userfaultfd_t anon_inode > "[userfaultfd]" uffd_t) > (allow test_userfaultfd_t uffd_t (anon_inode (create ioctl read))) > [...] > ``` > > test_userfaultfd.te: > ``` > type uffd_t; > type test_userfaultfd_t; > domain_type(test_userfaultfd_t) > unconfined_runs_test(test_userfaultfd_t) > typeattribute test_userfaultfd_t testdomain; > [...] > ``` > Thanks for your prompt reply. IIUC, if I have to add policy for another process (say without read permission), I''ll have to add the following lines in addition to the above lines right: in test_userfaultfd_newclass.cil ``` (typeattributeset cil_gen_require test_noread_userfaultfd_t) (typetransition test_noread_userfaultfd_t test_noread_userfaultfd_t anon_inode "[userfaultfd]" uffd_t) (allow test_noread_userfaultfd_t uffd_t (anon_inode (create ioctl))) [...] ``` and in test_userfaultfd.te ``` type test_noread_userfaultfd_t; domain_type(test_noread_userfaultfd_t) unconfined_runs_test(test_noread_userfaultfd_t) typeattribute test_noread_userfaultfd_t testdomain; [...] ``` Basically, in order to be able to use domain_type() and unconfined_runs_test() interface, I need to write part of the policy in the .te file. Is that right? > We don't have an established way of handling the testing of new > classes/permissions in the testsuite before they are defined in the > distribution policy, but I think we could try this way here. The > downside is that the rules are not in one place, but we can later > merge everything into one .te file once the new class is widely > available in the distribution policies. > > > > You will likely also need to communicate different locations of > > > failures / error codes from the test program(s) to the script via exit > > > code. See tests/keys for an example of such pattern (though you can > > > use a different approach as long as it gets the job done :) > > > > > > Sorry for requiring all the effort, but we're trying to keep > > > reasonably high standards for tests here. It's sometimes a PITA, but > > > it pays off in the long run ;) > > > > > > Thanks, > > > > > > > + > > > > +exit; > > > > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > > > > new file mode 100644 > > > > index 0000000..9baebd9 > > > > --- /dev/null > > > > +++ b/tests/userfaultfd/userfaultfd.c > > > > @@ -0,0 +1,49 @@ > > > > +#include <stdio.h> > > > > +#include <fcntl.h> > > > > +#include <unistd.h> > > > > + > > > > +#include <sys/types.h> > > > > +#include <sys/ioctl.h> > > > > +#include <sys/syscall.h> > > > > + > > > > +#include <linux/userfaultfd.h> > > > > + > > > > +void print_api(const struct uffdio_api *api) > > > > +{ > > > > + printf("api: %llu\n", api->api); > > > > + printf("features: %llu\n", api->features); > > > > + printf("ioctls: %llu\n", api->ioctls); > > > > + > > > > + printf("\n"); > > > > +} > > > > + > > > > +int main (void) > > > > +{ > > > > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > > > > + if (uffd < 0) { > > > > + perror("syscall(userfaultfd)"); > > > > + return -1; > > > > + } > > > > + > > > > + struct uffdio_api api = {0}; > > > > + api.api = UFFD_API; > > > > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > > > > + perror("UFFDIO_API"); > > > > + return -1; > > > > + } > > > > + > > > > + print_api(&api); > > > > + > > > > + struct uffd_msg msg = {0}; > > > > + ssize_t count = read(uffd, &msg, sizeof(msg)); > > > > + if (count < 0) { > > > > + // Expected to fail as no memory range registered. > > > > + return 0; > > > > + } else if (count == 0) { > > > > + printf("read EOF\n\n"); > > > > + } > > > > + > > > > + printf("read uffd\n\n"); > > > > + > > > > + return 0; > > > > +} > > > > -- > > > > 2.28.0 > > > > > > > > > > -- > > > Ondrej Mosnacek > > > Software Engineer, Platform Security - SELinux kernel > > > Red Hat, Inc. > > > > > > > > -- > Ondrej Mosnacek > Software Engineer, Platform Security - SELinux kernel > Red Hat, Inc. >
On Fri, Dec 11, 2020 at 2:40 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > On Fri, Dec 11, 2020 at 1:11 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > On Fri, Dec 11, 2020 at 1:52 AM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > Hi Ondrej, > > > On Fri, Nov 27, 2020 at 6:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > > > > > Hi Lokesh, > > > > > > > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > > > Confirm SELinux policies are enforced on userfaultfd operations > > > > > via secure anon-inode interface. > > > > > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > > > > --- > > > > > policy/Makefile | 2 +- > > > > > policy/userfaultfd.cil | 17 ++++++++++++ > > > > > tests/Makefile | 2 +- > > > > > tests/userfaultfd/Makefile | 3 ++ > > > > > tests/userfaultfd/test | 15 ++++++++++ > > > > > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > > > > > 6 files changed, 86 insertions(+), 2 deletions(-) > > > > > create mode 100644 policy/userfaultfd.cil > > > > > create mode 100644 tests/userfaultfd/Makefile > > > > > create mode 100755 tests/userfaultfd/test > > > > > create mode 100644 tests/userfaultfd/userfaultfd.c > > > > > > > > > > diff --git a/policy/Makefile b/policy/Makefile > > > > > index 6c49091..02e7568 100644 > > > > > --- a/policy/Makefile > > > > > +++ b/policy/Makefile > > > > > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > > > > > endif > > > > > > > > > > ifeq ($(SUPPORTS_CIL),y) > > > > > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > > > > > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > > > > > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > > > > > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > > > > > # If other MLS tests get written this can be moved outside of the glblub test > > > > > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > > > > > new file mode 100644 > > > > > index 0000000..0743fff > > > > > --- /dev/null > > > > > +++ b/policy/userfaultfd.cil > > > > > @@ -0,0 +1,17 @@ > > > > > +(class anon_inode ()) > > > > > +(classcommon anon_inode file) > > > > > +(classorder (unordered anon_inode)) > > > > > +(type uffd_t) > > > > > +; Label the UFFD with uffd_t; this can be specialized per domain > > > > > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > > > > > +(allow unconfined_t uffd_t (anon_inode (create))) > > > > > +; Permit read() and ioctl() on the UFFD; > > > > > +; Comment out if you want to test read or basic ioctl enforcement. > > > > > +(allow unconfined_t uffd_t (anon_inode (read))) > > > > > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > > > > > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > > > > > +; Currently the first one is uncommented; comment that out if trying another. > > > > > +; None > > > > > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > > > > > +; UFFDIO_API > > > > > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > > > > > diff --git a/tests/Makefile b/tests/Makefile > > > > > index 4c00b5f..3871570 100644 > > > > > --- a/tests/Makefile > > > > > +++ b/tests/Makefile > > > > > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > > > > > task_setnice task_setscheduler task_getscheduler task_getsid \ > > > > > task_getpgid task_setpgid file ioctl capable_file capable_net \ > > > > > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > > > > > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > > > > > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > > > > > > > > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > > > > > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > > > > > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > > > > > new file mode 100644 > > > > > index 0000000..66d02a1 > > > > > --- /dev/null > > > > > +++ b/tests/userfaultfd/Makefile > > > > > @@ -0,0 +1,3 @@ > > > > > +all: userfaultfd > > > > > +clean: > > > > > + rm -f userfaultfd > > > > > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > > > > > new file mode 100755 > > > > > index 0000000..dd42aa8 > > > > > --- /dev/null > > > > > +++ b/tests/userfaultfd/test > > > > > @@ -0,0 +1,15 @@ > > > > > +#!/usr/bin/perl > > > > > + > > > > > +use Test; > > > > > + > > > > > +BEGIN { > > > > > + plan tests => 1; > > > > > +} > > > > > + > > > > > +$basedir = $0; > > > > > +$basedir =~ s|(.*)/[^/]*|$1|; > > > > > + > > > > > +$result = system("$basedir/userfaultfd"); > > > > > +ok( $result, 0 ); > > > > > > > > This is a good start, but it is only a very basic test :) > > > > > > > > I would expect at least these tests here: > > > > 1. that an userfaultfd node created by a domain *without* the > > > > transition rule gets the context of the creating process (should be > > > > possible by calling fgetxattr(2) on the fd), > > > > 2. that an userfaultfd node created by a domain *with* the transition > > > > rule gets the context specified by the rule, > > > > 3. that a process with context that is *allowed* to { create read > > > > write [...] } a given userfaultfd type by the policy *can* indeed > > > > successfully perform these operations (or at least that the error > > > > returned is not -EACCESS), > > > > 4. that a process with context that is *NOT allowed* to { create read > > > > write [...] } a given userfaultfd type by the policy *cannot* perform > > > > these operations and the error returned is -EACCESS. > > > > > > > > (The more permissions you can test the better, but I'd like to see at > > > > least the three (create, read, write).) > > > > > > > > For this, you will need to define several process types in the test > > > > policy and run the test program(s) with a specific type using runcon > > > > (see e.g. policy/test_link.te and tests/link/test for a simple > > > > example). I suggest using the CIL module only for adding the class and > > > > permissions and a separate .te file to define the process and > > > > userfaultfd types (so that you can use the unconfined_runs_test() > > > > interface for common permissions needed for the process types). > > > > > > > I'm having a bit of a hard time managing the test policy in a cil > > > module and a .te file. My inexperience with SELinux could be a reason > > > :) > > > > > > I defined 'anon_inode' class, like in this patch in the CIL module as follows: > > > (class anon_inode ()) > > > (classcommon anon_inode file) > > > (classorder (unordered anon_inode)) > > > > > > But then when I used anon_inode in the .te file as follows: > > > ... > > > type uffd_t; > > > type_transition test_userfaultfd_t test_userfaultfd_t : anon_inode > > > uffd_t "[userfaultfd]"; > > > allow test_userfaultfd_t uffd_t:anon_inode { create ioctl read }; > > > > > > I get a compile error: > > > test_policy.te:<line#>:ERROR 'unknown class anon_inode' at token ';' on line ... > > > > > > Any advice on where I am making mistakes? > > > > Ouch! No, the mistake is mine :) I forgot that the classes/permissions > > added via CIL won't be available in the refpolicy build > > infrastructure... But I think it should be possible to define the > > types and add basic rules for them in .te and only add the necessary > > userfaultfd rules in the .cil file: > > > > test_userfaultfd_newclass.cil: > > ``` > > (class anon_inode ()) > > (classcommon anon_inode file) > > (classorder (unordered anon_inode)) > > (typeattributeset cil_gen_require test_userfaultfd_t) > > (typeattributeset cil_gen_require uffd_t) > > (typetransition test_userfaultfd_t test_userfaultfd_t anon_inode > > "[userfaultfd]" uffd_t) > > (allow test_userfaultfd_t uffd_t (anon_inode (create ioctl read))) > > [...] > > ``` > > > > test_userfaultfd.te: > > ``` > > type uffd_t; > > type test_userfaultfd_t; > > domain_type(test_userfaultfd_t) > > unconfined_runs_test(test_userfaultfd_t) > > typeattribute test_userfaultfd_t testdomain; > > [...] > > ``` > > > Thanks for your prompt reply. > > IIUC, if I have to add policy for another process (say without read > permission), I''ll have to add the following lines in addition to the > above lines right: > > in test_userfaultfd_newclass.cil > ``` > (typeattributeset cil_gen_require test_noread_userfaultfd_t) > (typetransition test_noread_userfaultfd_t test_noread_userfaultfd_t > anon_inode "[userfaultfd]" uffd_t) > (allow test_noread_userfaultfd_t uffd_t (anon_inode (create ioctl))) > [...] > ``` > and in test_userfaultfd.te > ``` > type test_noread_userfaultfd_t; > domain_type(test_noread_userfaultfd_t) > unconfined_runs_test(test_noread_userfaultfd_t) > typeattribute test_noread_userfaultfd_t testdomain; > [...] > ``` > > Basically, in order to be able to use domain_type() and > unconfined_runs_test() interface, I need to write part of the policy > in the .te file. Is that right? Yes, exactly. > > > We don't have an established way of handling the testing of new > > classes/permissions in the testsuite before they are defined in the > > distribution policy, but I think we could try this way here. The > > downside is that the rules are not in one place, but we can later > > merge everything into one .te file once the new class is widely > > available in the distribution policies. > > > > > > You will likely also need to communicate different locations of > > > > failures / error codes from the test program(s) to the script via exit > > > > code. See tests/keys for an example of such pattern (though you can > > > > use a different approach as long as it gets the job done :) > > > > > > > > Sorry for requiring all the effort, but we're trying to keep > > > > reasonably high standards for tests here. It's sometimes a PITA, but > > > > it pays off in the long run ;) > > > > > > > > Thanks, > > > > > > > > > + > > > > > +exit; > > > > > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > > > > > new file mode 100644 > > > > > index 0000000..9baebd9 > > > > > --- /dev/null > > > > > +++ b/tests/userfaultfd/userfaultfd.c > > > > > @@ -0,0 +1,49 @@ > > > > > +#include <stdio.h> > > > > > +#include <fcntl.h> > > > > > +#include <unistd.h> > > > > > + > > > > > +#include <sys/types.h> > > > > > +#include <sys/ioctl.h> > > > > > +#include <sys/syscall.h> > > > > > + > > > > > +#include <linux/userfaultfd.h> > > > > > + > > > > > +void print_api(const struct uffdio_api *api) > > > > > +{ > > > > > + printf("api: %llu\n", api->api); > > > > > + printf("features: %llu\n", api->features); > > > > > + printf("ioctls: %llu\n", api->ioctls); > > > > > + > > > > > + printf("\n"); > > > > > +} > > > > > + > > > > > +int main (void) > > > > > +{ > > > > > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > > > > > + if (uffd < 0) { > > > > > + perror("syscall(userfaultfd)"); > > > > > + return -1; > > > > > + } > > > > > + > > > > > + struct uffdio_api api = {0}; > > > > > + api.api = UFFD_API; > > > > > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > > > > > + perror("UFFDIO_API"); > > > > > + return -1; > > > > > + } > > > > > + > > > > > + print_api(&api); > > > > > + > > > > > + struct uffd_msg msg = {0}; > > > > > + ssize_t count = read(uffd, &msg, sizeof(msg)); > > > > > + if (count < 0) { > > > > > + // Expected to fail as no memory range registered. > > > > > + return 0; > > > > > + } else if (count == 0) { > > > > > + printf("read EOF\n\n"); > > > > > + } > > > > > + > > > > > + printf("read uffd\n\n"); > > > > > + > > > > > + return 0; > > > > > +} > > > > > -- > > > > > 2.28.0 > > > > > > > > > > > > > -- > > > > Ondrej Mosnacek > > > > Software Engineer, Platform Security - SELinux kernel > > > > Red Hat, Inc. > > > > > > > > > > > > > -- > > Ondrej Mosnacek > > Software Engineer, Platform Security - SELinux kernel > > Red Hat, Inc. > > >
On Fri, Dec 11, 2020 at 5:52 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > On Fri, Dec 11, 2020 at 2:40 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > On Fri, Dec 11, 2020 at 1:11 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > > > On Fri, Dec 11, 2020 at 1:52 AM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > > Hi Ondrej, > > > > On Fri, Nov 27, 2020 at 6:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote: > > > > > > > > > > Hi Lokesh, > > > > > > > > > > On Wed, Nov 25, 2020 at 1:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote: > > > > > > Confirm SELinux policies are enforced on userfaultfd operations > > > > > > via secure anon-inode interface. > > > > > > > > > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> > > > > > > --- > > > > > > policy/Makefile | 2 +- > > > > > > policy/userfaultfd.cil | 17 ++++++++++++ > > > > > > tests/Makefile | 2 +- > > > > > > tests/userfaultfd/Makefile | 3 ++ > > > > > > tests/userfaultfd/test | 15 ++++++++++ > > > > > > tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ > > > > > > 6 files changed, 86 insertions(+), 2 deletions(-) > > > > > > create mode 100644 policy/userfaultfd.cil > > > > > > create mode 100644 tests/userfaultfd/Makefile > > > > > > create mode 100755 tests/userfaultfd/test > > > > > > create mode 100644 tests/userfaultfd/userfaultfd.c > > > > > > > > > > > > diff --git a/policy/Makefile b/policy/Makefile > > > > > > index 6c49091..02e7568 100644 > > > > > > --- a/policy/Makefile > > > > > > +++ b/policy/Makefile > > > > > > @@ -36,7 +36,7 @@ SUPPORTS_CIL = n > > > > > > endif > > > > > > > > > > > > ifeq ($(SUPPORTS_CIL),y) > > > > > > -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil > > > > > > +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil > > > > > > ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) > > > > > > ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) > > > > > > # If other MLS tests get written this can be moved outside of the glblub test > > > > > > diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil > > > > > > new file mode 100644 > > > > > > index 0000000..0743fff > > > > > > --- /dev/null > > > > > > +++ b/policy/userfaultfd.cil > > > > > > @@ -0,0 +1,17 @@ > > > > > > +(class anon_inode ()) > > > > > > +(classcommon anon_inode file) > > > > > > +(classorder (unordered anon_inode)) > > > > > > +(type uffd_t) > > > > > > +; Label the UFFD with uffd_t; this can be specialized per domain > > > > > > +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) > > > > > > +(allow unconfined_t uffd_t (anon_inode (create))) > > > > > > +; Permit read() and ioctl() on the UFFD; > > > > > > +; Comment out if you want to test read or basic ioctl enforcement. > > > > > > +(allow unconfined_t uffd_t (anon_inode (read))) > > > > > > +(allow unconfined_t uffd_t (anon_inode (ioctl))) > > > > > > +; Uncomment one of the allowx lines below to test ioctl whitelisting. > > > > > > +; Currently the first one is uncommented; comment that out if trying another. > > > > > > +; None > > > > > > +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) > > > > > > +; UFFDIO_API > > > > > > +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) > > > > > > diff --git a/tests/Makefile b/tests/Makefile > > > > > > index 4c00b5f..3871570 100644 > > > > > > --- a/tests/Makefile > > > > > > +++ b/tests/Makefile > > > > > > @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ > > > > > > task_setnice task_setscheduler task_getscheduler task_getsid \ > > > > > > task_getpgid task_setpgid file ioctl capable_file capable_net \ > > > > > > capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ > > > > > > - inet_socket overlay checkreqprot mqueue mac_admin atsecure > > > > > > + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd > > > > > > > > > > > > ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) > > > > > > ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) > > > > > > diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile > > > > > > new file mode 100644 > > > > > > index 0000000..66d02a1 > > > > > > --- /dev/null > > > > > > +++ b/tests/userfaultfd/Makefile > > > > > > @@ -0,0 +1,3 @@ > > > > > > +all: userfaultfd > > > > > > +clean: > > > > > > + rm -f userfaultfd > > > > > > diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test > > > > > > new file mode 100755 > > > > > > index 0000000..dd42aa8 > > > > > > --- /dev/null > > > > > > +++ b/tests/userfaultfd/test > > > > > > @@ -0,0 +1,15 @@ > > > > > > +#!/usr/bin/perl > > > > > > + > > > > > > +use Test; > > > > > > + > > > > > > +BEGIN { > > > > > > + plan tests => 1; > > > > > > +} > > > > > > + > > > > > > +$basedir = $0; > > > > > > +$basedir =~ s|(.*)/[^/]*|$1|; > > > > > > + > > > > > > +$result = system("$basedir/userfaultfd"); > > > > > > +ok( $result, 0 ); > > > > > > > > > > This is a good start, but it is only a very basic test :) > > > > > > > > > > I would expect at least these tests here: > > > > > 1. that an userfaultfd node created by a domain *without* the > > > > > transition rule gets the context of the creating process (should be > > > > > possible by calling fgetxattr(2) on the fd), > > > > > 2. that an userfaultfd node created by a domain *with* the transition > > > > > rule gets the context specified by the rule, > > > > > 3. that a process with context that is *allowed* to { create read > > > > > write [...] } a given userfaultfd type by the policy *can* indeed > > > > > successfully perform these operations (or at least that the error > > > > > returned is not -EACCESS), > > > > > 4. that a process with context that is *NOT allowed* to { create read > > > > > write [...] } a given userfaultfd type by the policy *cannot* perform > > > > > these operations and the error returned is -EACCESS. > > > > > > > > > > (The more permissions you can test the better, but I'd like to see at > > > > > least the three (create, read, write).) > > > > > > > > > > For this, you will need to define several process types in the test > > > > > policy and run the test program(s) with a specific type using runcon > > > > > (see e.g. policy/test_link.te and tests/link/test for a simple > > > > > example). I suggest using the CIL module only for adding the class and > > > > > permissions and a separate .te file to define the process and > > > > > userfaultfd types (so that you can use the unconfined_runs_test() > > > > > interface for common permissions needed for the process types). > > > > > > > > > I'm having a bit of a hard time managing the test policy in a cil > > > > module and a .te file. My inexperience with SELinux could be a reason > > > > :) > > > > > > > > I defined 'anon_inode' class, like in this patch in the CIL module as follows: > > > > (class anon_inode ()) > > > > (classcommon anon_inode file) > > > > (classorder (unordered anon_inode)) > > > > > > > > But then when I used anon_inode in the .te file as follows: > > > > ... > > > > type uffd_t; > > > > type_transition test_userfaultfd_t test_userfaultfd_t : anon_inode > > > > uffd_t "[userfaultfd]"; > > > > allow test_userfaultfd_t uffd_t:anon_inode { create ioctl read }; > > > > > > > > I get a compile error: > > > > test_policy.te:<line#>:ERROR 'unknown class anon_inode' at token ';' on line ... > > > > > > > > Any advice on where I am making mistakes? > > > > > > Ouch! No, the mistake is mine :) I forgot that the classes/permissions > > > added via CIL won't be available in the refpolicy build > > > infrastructure... But I think it should be possible to define the > > > types and add basic rules for them in .te and only add the necessary > > > userfaultfd rules in the .cil file: > > > > > > test_userfaultfd_newclass.cil: > > > ``` > > > (class anon_inode ()) > > > (classcommon anon_inode file) > > > (classorder (unordered anon_inode)) > > > (typeattributeset cil_gen_require test_userfaultfd_t) > > > (typeattributeset cil_gen_require uffd_t) > > > (typetransition test_userfaultfd_t test_userfaultfd_t anon_inode > > > "[userfaultfd]" uffd_t) > > > (allow test_userfaultfd_t uffd_t (anon_inode (create ioctl read))) > > > [...] > > > ``` > > > > > > test_userfaultfd.te: > > > ``` > > > type uffd_t; > > > type test_userfaultfd_t; > > > domain_type(test_userfaultfd_t) > > > unconfined_runs_test(test_userfaultfd_t) > > > typeattribute test_userfaultfd_t testdomain; > > > [...] > > > ``` > > > > > Thanks for your prompt reply. > > > > IIUC, if I have to add policy for another process (say without read > > permission), I''ll have to add the following lines in addition to the > > above lines right: > > > > in test_userfaultfd_newclass.cil > > ``` > > (typeattributeset cil_gen_require test_noread_userfaultfd_t) > > (typetransition test_noread_userfaultfd_t test_noread_userfaultfd_t > > anon_inode "[userfaultfd]" uffd_t) > > (allow test_noread_userfaultfd_t uffd_t (anon_inode (create ioctl))) > > [...] > > ``` > > and in test_userfaultfd.te > > ``` > > type test_noread_userfaultfd_t; > > domain_type(test_noread_userfaultfd_t) > > unconfined_runs_test(test_noread_userfaultfd_t) > > typeattribute test_noread_userfaultfd_t testdomain; > > [...] > > ``` > > > > Basically, in order to be able to use domain_type() and > > unconfined_runs_test() interface, I need to write part of the policy > > in the .te file. Is that right? > > Yes, exactly. Thanks for confirming. With the above rules compilation is working fine, but the test fails Based on the tests/link/test, the command I'm using in the test script is: $result = system "runcon -t test_userfaultfd_t $basedir/userfaultfd"; The error message is: runcon: 'userfaultfd/userfaultfd': permission denied Any suggestions? > > > > > > We don't have an established way of handling the testing of new > > > classes/permissions in the testsuite before they are defined in the > > > distribution policy, but I think we could try this way here. The > > > downside is that the rules are not in one place, but we can later > > > merge everything into one .te file once the new class is widely > > > available in the distribution policies. > > > > > > > > You will likely also need to communicate different locations of > > > > > failures / error codes from the test program(s) to the script via exit > > > > > code. See tests/keys for an example of such pattern (though you can > > > > > use a different approach as long as it gets the job done :) > > > > > > > > > > Sorry for requiring all the effort, but we're trying to keep > > > > > reasonably high standards for tests here. It's sometimes a PITA, but > > > > > it pays off in the long run ;) > > > > > > > > > > Thanks, > > > > > > > > > > > + > > > > > > +exit; > > > > > > diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c > > > > > > new file mode 100644 > > > > > > index 0000000..9baebd9 > > > > > > --- /dev/null > > > > > > +++ b/tests/userfaultfd/userfaultfd.c > > > > > > @@ -0,0 +1,49 @@ > > > > > > +#include <stdio.h> > > > > > > +#include <fcntl.h> > > > > > > +#include <unistd.h> > > > > > > + > > > > > > +#include <sys/types.h> > > > > > > +#include <sys/ioctl.h> > > > > > > +#include <sys/syscall.h> > > > > > > + > > > > > > +#include <linux/userfaultfd.h> > > > > > > + > > > > > > +void print_api(const struct uffdio_api *api) > > > > > > +{ > > > > > > + printf("api: %llu\n", api->api); > > > > > > + printf("features: %llu\n", api->features); > > > > > > + printf("ioctls: %llu\n", api->ioctls); > > > > > > + > > > > > > + printf("\n"); > > > > > > +} > > > > > > + > > > > > > +int main (void) > > > > > > +{ > > > > > > + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); > > > > > > + if (uffd < 0) { > > > > > > + perror("syscall(userfaultfd)"); > > > > > > + return -1; > > > > > > + } > > > > > > + > > > > > > + struct uffdio_api api = {0}; > > > > > > + api.api = UFFD_API; > > > > > > + if (ioctl(uffd, UFFDIO_API, &api) < 0) { > > > > > > + perror("UFFDIO_API"); > > > > > > + return -1; > > > > > > + } > > > > > > + > > > > > > + print_api(&api); > > > > > > + > > > > > > + struct uffd_msg msg = {0}; > > > > > > + ssize_t count = read(uffd, &msg, sizeof(msg)); > > > > > > + if (count < 0) { > > > > > > + // Expected to fail as no memory range registered. > > > > > > + return 0; > > > > > > + } else if (count == 0) { > > > > > > + printf("read EOF\n\n"); > > > > > > + } > > > > > > + > > > > > > + printf("read uffd\n\n"); > > > > > > + > > > > > > + return 0; > > > > > > +} > > > > > > -- > > > > > > 2.28.0 > > > > > > > > > > > > > > > > -- > > > > > Ondrej Mosnacek > > > > > Software Engineer, Platform Security - SELinux kernel > > > > > Red Hat, Inc. > > > > > > > > > > > > > > > > > > -- > > > Ondrej Mosnacek > > > Software Engineer, Platform Security - SELinux kernel > > > Red Hat, Inc. > > > > > > > > -- > Ondrej Mosnacek > Software Engineer, Platform Security - SELinux kernel > Red Hat, Inc. >
diff --git a/policy/Makefile b/policy/Makefile index 6c49091..02e7568 100644 --- a/policy/Makefile +++ b/policy/Makefile @@ -36,7 +36,7 @@ SUPPORTS_CIL = n endif ifeq ($(SUPPORTS_CIL),y) -CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil +CIL_TARGETS = test_mlsconstrain.cil test_overlay_defaultrange.cil userfaultfd.cil ifeq ($(shell [ $(MAX_KERNEL_POLICY) -ge 32 ] && echo true),true) ifeq ($(shell [ $(POL_VERS) -ge 32 ] && echo true),true) # If other MLS tests get written this can be moved outside of the glblub test diff --git a/policy/userfaultfd.cil b/policy/userfaultfd.cil new file mode 100644 index 0000000..0743fff --- /dev/null +++ b/policy/userfaultfd.cil @@ -0,0 +1,17 @@ +(class anon_inode ()) +(classcommon anon_inode file) +(classorder (unordered anon_inode)) +(type uffd_t) +; Label the UFFD with uffd_t; this can be specialized per domain +(typetransition unconfined_t unconfined_t anon_inode "[userfaultfd]" uffd_t) +(allow unconfined_t uffd_t (anon_inode (create))) +; Permit read() and ioctl() on the UFFD; +; Comment out if you want to test read or basic ioctl enforcement. +(allow unconfined_t uffd_t (anon_inode (read))) +(allow unconfined_t uffd_t (anon_inode (ioctl))) +; Uncomment one of the allowx lines below to test ioctl whitelisting. +; Currently the first one is uncommented; comment that out if trying another. +; None +;(allowx unconfined_t uffd_t (ioctl anon_inode ((0x00)))) +; UFFDIO_API +(allowx unconfined_t uffd_t (ioctl anon_inode ((0xaa3f)))) diff --git a/tests/Makefile b/tests/Makefile index 4c00b5f..3871570 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -27,7 +27,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ task_setnice task_setscheduler task_getscheduler task_getsid \ task_getpgid task_setpgid file ioctl capable_file capable_net \ capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ - inet_socket overlay checkreqprot mqueue mac_admin atsecure + inet_socket overlay checkreqprot mqueue mac_admin atsecure userfaultfd ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) diff --git a/tests/userfaultfd/Makefile b/tests/userfaultfd/Makefile new file mode 100644 index 0000000..66d02a1 --- /dev/null +++ b/tests/userfaultfd/Makefile @@ -0,0 +1,3 @@ +all: userfaultfd +clean: + rm -f userfaultfd diff --git a/tests/userfaultfd/test b/tests/userfaultfd/test new file mode 100755 index 0000000..dd42aa8 --- /dev/null +++ b/tests/userfaultfd/test @@ -0,0 +1,15 @@ +#!/usr/bin/perl + +use Test; + +BEGIN { + plan tests => 1; +} + +$basedir = $0; +$basedir =~ s|(.*)/[^/]*|$1|; + +$result = system("$basedir/userfaultfd"); +ok( $result, 0 ); + +exit; diff --git a/tests/userfaultfd/userfaultfd.c b/tests/userfaultfd/userfaultfd.c new file mode 100644 index 0000000..9baebd9 --- /dev/null +++ b/tests/userfaultfd/userfaultfd.c @@ -0,0 +1,49 @@ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/syscall.h> + +#include <linux/userfaultfd.h> + +void print_api(const struct uffdio_api *api) +{ + printf("api: %llu\n", api->api); + printf("features: %llu\n", api->features); + printf("ioctls: %llu\n", api->ioctls); + + printf("\n"); +} + +int main (void) +{ + long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (uffd < 0) { + perror("syscall(userfaultfd)"); + return -1; + } + + struct uffdio_api api = {0}; + api.api = UFFD_API; + if (ioctl(uffd, UFFDIO_API, &api) < 0) { + perror("UFFDIO_API"); + return -1; + } + + print_api(&api); + + struct uffd_msg msg = {0}; + ssize_t count = read(uffd, &msg, sizeof(msg)); + if (count < 0) { + // Expected to fail as no memory range registered. + return 0; + } else if (count == 0) { + printf("read EOF\n\n"); + } + + printf("read uffd\n\n"); + + return 0; +}
Confirm SELinux policies are enforced on userfaultfd operations via secure anon-inode interface. Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> --- policy/Makefile | 2 +- policy/userfaultfd.cil | 17 ++++++++++++ tests/Makefile | 2 +- tests/userfaultfd/Makefile | 3 ++ tests/userfaultfd/test | 15 ++++++++++ tests/userfaultfd/userfaultfd.c | 49 +++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 policy/userfaultfd.cil create mode 100644 tests/userfaultfd/Makefile create mode 100755 tests/userfaultfd/test create mode 100644 tests/userfaultfd/userfaultfd.c