Confirm SELinux policies are enforced on userfaultfd operations via secure anon-inode interface. Signed-off-by: Lokesh Gidra <lokeshgidra@xxxxxxxxxx> --- 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 ); + +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