[V3] selinux-testsuite: Add kernel module tests
diff mbox series

Message ID 20191118173602.25506-1-richard_c_haines@btinternet.com
State Superseded
Headers show
Series
  • [V3] selinux-testsuite: Add kernel module tests
Related show

Commit Message

Richard Haines Nov. 18, 2019, 5:36 p.m. UTC
Test kernel module loading permissions.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
V2 Change:
Check permission denial module_load versus module_request by using a
test kernel module for each.
Note: Rawhide (with secnext kernel) adds built-in.a and built-in.a.cmd when
building modules, therefore added to Makefile and .gitignore.
V3 Changes:
As requested in [1] except policy change, coalesced type attributes instead.

[1] https://lore.kernel.org/selinux/CAFqZXNtm_X+YssnX_3_5ThkVZY+9SBeQC5Qo78s+geSsBok8=Q@mail.gmail.com/

 policy/Makefile                           |   4 +
 policy/test_module_load.te                | 110 +++++++++++++++++++
 tests/Makefile                            |   4 +
 tests/module_load/.gitignore              |  11 ++
 tests/module_load/Makefile                |  12 +++
 tests/module_load/finit_load.c            |  94 +++++++++++++++++
 tests/module_load/init_load.c             | 123 ++++++++++++++++++++++
 tests/module_load/setest_module_load.c    |  18 ++++
 tests/module_load/setest_module_request.c |  22 ++++
 tests/module_load/test                    |  62 +++++++++++
 10 files changed, 460 insertions(+)
 create mode 100644 policy/test_module_load.te
 create mode 100644 tests/module_load/.gitignore
 create mode 100644 tests/module_load/Makefile
 create mode 100644 tests/module_load/finit_load.c
 create mode 100644 tests/module_load/init_load.c
 create mode 100644 tests/module_load/setest_module_load.c
 create mode 100644 tests/module_load/setest_module_request.c
 create mode 100755 tests/module_load/test

Comments

Stephen Smalley Nov. 18, 2019, 6:15 p.m. UTC | #1
On 11/18/19 12:36 PM, Richard Haines wrote:
> Test kernel module loading permissions.
> 
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> ---
> V2 Change:
> Check permission denial module_load versus module_request by using a
> test kernel module for each.
> Note: Rawhide (with secnext kernel) adds built-in.a and built-in.a.cmd when
> building modules, therefore added to Makefile and .gitignore.
> V3 Changes:
> As requested in [1] except policy change, coalesced type attributes instead.

That isn't what I meant.  I meant you could get rid of one or the other 
of initmoddoman or finitmoddomain altogether and use a single type 
attribute for both sets of types, because you allow exactly the same 
allow rules / refpolicy interfaces to both attributes (just the rules 
for entering via test files and from sysadm).  Anyway, not a big deal 
either way.

> 
> [1] https://lore.kernel.org/selinux/CAFqZXNtm_X+YssnX_3_5ThkVZY+9SBeQC5Qo78s+geSsBok8=Q@mail.gmail.com/
> 
>   policy/Makefile                           |   4 +
>   policy/test_module_load.te                | 110 +++++++++++++++++++
>   tests/Makefile                            |   4 +
>   tests/module_load/.gitignore              |  11 ++
>   tests/module_load/Makefile                |  12 +++
>   tests/module_load/finit_load.c            |  94 +++++++++++++++++
>   tests/module_load/init_load.c             | 123 ++++++++++++++++++++++
>   tests/module_load/setest_module_load.c    |  18 ++++
>   tests/module_load/setest_module_request.c |  22 ++++
>   tests/module_load/test                    |  62 +++++++++++
>   10 files changed, 460 insertions(+)
>   create mode 100644 policy/test_module_load.te
>   create mode 100644 tests/module_load/.gitignore
>   create mode 100644 tests/module_load/Makefile
>   create mode 100644 tests/module_load/finit_load.c
>   create mode 100644 tests/module_load/init_load.c
>   create mode 100644 tests/module_load/setest_module_load.c
>   create mode 100644 tests/module_load/setest_module_request.c
>   create mode 100755 tests/module_load/test
> 
> diff --git a/policy/Makefile b/policy/Makefile
> index ad94c43..25dfb69 100644
> --- a/policy/Makefile
> +++ b/policy/Makefile
> @@ -94,6 +94,10 @@ ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && echo
>   TARGETS += test_key_socket.te
>   endif
>   
> +ifeq ($(shell grep -q module_load $(POLDEV)/include/support/all_perms.spt && echo true),true)
> +TARGETS+=test_module_load.te
> +endif
> +
>   ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
>   TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
>   endif
> diff --git a/policy/test_module_load.te b/policy/test_module_load.te
> new file mode 100644
> index 0000000..9256ddd
> --- /dev/null
> +++ b/policy/test_module_load.te
> @@ -0,0 +1,110 @@
> +#
> +############################## Define Macro ################################
> +#
> +# Replace domain_type() macro as it hides some relevant denials in audit.log
> +#
> +gen_require(`
> +	type setrans_var_run_t, syslogd_t;
> +')
> +
> +define(`module_domain_type',`
> +	allow $1 proc_t:dir { search };
> +	allow $1 proc_t:lnk_file { read };
> +	allow $1 self:dir { search };
> +	allow $1 self:file { open read write };
> +	dontaudit init_t syslogd_t:fd use;
> +	dontaudit $1 security_t:filesystem getattr;
> +	dontaudit $1 self:file getattr;
> +	dontaudit $1 setrans_var_run_t:dir search;
> +	dontaudit unconfined_t $1:process { noatsecure rlimitinh siginh };
> +')
> +
> +#
> +############# Test kernel modules with finitmod_module(2) ###################
> +#
> +attribute finitmoddomain;
> +
> +type test_finitmod_t;
> +module_domain_type(test_finitmod_t)
> +unconfined_runs_test(test_finitmod_t)
> +typeattribute test_finitmod_t testdomain, finitmoddomain;
> +
> +allow test_finitmod_t self:capability { sys_module };
> +allow test_finitmod_t test_file_t:system { module_load };
> +allow test_finitmod_t kernel_t:system { module_request };
> +
> +############### Deny cap sys_module ######################
> +type test_finitmod_deny_sys_module_t;
> +module_domain_type(test_finitmod_deny_sys_module_t)
> +unconfined_runs_test(test_finitmod_deny_sys_module_t)
> +typeattribute test_finitmod_deny_sys_module_t testdomain, finitmoddomain;
> +
> +neverallow test_finitmod_deny_sys_module_t self:capability { sys_module };
> +
> +############### Deny sys module_load ######################
> +type test_finitmod_deny_module_load_t;
> +module_domain_type(test_finitmod_deny_module_load_t)
> +unconfined_runs_test(test_finitmod_deny_module_load_t)
> +typeattribute test_finitmod_deny_module_load_t testdomain, finitmoddomain;
> +
> +allow test_finitmod_deny_module_load_t self:capability { sys_module };
> +neverallow test_finitmod_deny_module_load_t test_file_t:system { module_load };
> +
> +############### Deny sys module_request ######################
> +type test_finitmod_deny_module_request_t;
> +module_domain_type(test_finitmod_deny_module_request_t)
> +unconfined_runs_test(test_finitmod_deny_module_request_t)
> +typeattribute test_finitmod_deny_module_request_t testdomain, finitmoddomain;
> +
> +allow test_finitmod_deny_module_request_t self:capability { sys_module };
> +allow test_finitmod_deny_module_request_t test_file_t:system { module_load };
> +neverallow test_finitmod_deny_module_request_t kernel_t:system { module_request };
> +
> +#
> +############# Test kernel modules with initmod_module(2) ###################
> +#
> +attribute initmoddomain;
> +
> +type test_initmod_t;
> +module_domain_type(test_initmod_t)
> +unconfined_runs_test(test_initmod_t)
> +typeattribute test_initmod_t testdomain, initmoddomain;
> +
> +allow test_initmod_t self:capability { sys_module };
> +allow test_initmod_t self:system { module_load };
> +allow test_initmod_t kernel_t:system { module_request };
> +
> +############### Deny cap sys_module ######################
> +type test_initmod_deny_sys_module_t;
> +module_domain_type(test_initmod_deny_sys_module_t)
> +unconfined_runs_test(test_initmod_deny_sys_module_t)
> +typeattribute test_initmod_deny_sys_module_t testdomain, initmoddomain;
> +
> +neverallow test_initmod_deny_sys_module_t self:capability { sys_module };
> +
> +############### Deny sys module_load ######################
> +type test_initmod_deny_module_load_t;
> +module_domain_type(test_initmod_deny_module_load_t)
> +unconfined_runs_test(test_initmod_deny_module_load_t)
> +typeattribute test_initmod_deny_module_load_t testdomain, initmoddomain;
> +
> +allow test_initmod_deny_module_load_t self:capability { sys_module };
> +neverallow test_initmod_deny_module_load_t self:system { module_load };
> +
> +############### Deny sys module_request ######################
> +type test_initmod_deny_module_request_t;
> +module_domain_type(test_initmod_deny_module_request_t)
> +unconfined_runs_test(test_initmod_deny_module_request_t)
> +typeattribute test_initmod_deny_module_request_t testdomain, initmoddomain;
> +
> +allow test_initmod_deny_module_request_t self:capability { sys_module };
> +allow test_initmod_deny_module_request_t self:system { module_load };
> +neverallow test_initmod_deny_module_request_t kernel_t:system { module_request };
> +
> +#
> +########### Allow these domains to be entered from sysadm domain ############
> +#
> +miscfiles_domain_entry_test_files(finitmoddomain)
> +userdom_sysadm_entry_spec_domtrans_to(finitmoddomain)
> +miscfiles_domain_entry_test_files(initmoddomain)
> +userdom_sysadm_entry_spec_domtrans_to(initmoddomain)
> diff --git a/tests/Makefile b/tests/Makefile
> index cca6648..0452887 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -72,6 +72,10 @@ ifeq ($(shell grep -q all_file_perms.*watch $(POLDEV)/include/support/all_perms.
>   SUBDIRS+=notify
>   endif
>   
> +ifeq ($(shell grep -q module_load $(POLDEV)/include/support/all_perms.spt && echo true),true)
> +SUBDIRS+=module_load
> +endif
> +
>   ifeq ($(DISTRO),RHEL4)
>       SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
>   endif
> diff --git a/tests/module_load/.gitignore b/tests/module_load/.gitignore
> new file mode 100644
> index 0000000..7fa5772
> --- /dev/null
> +++ b/tests/module_load/.gitignore
> @@ -0,0 +1,11 @@
> +finit_load
> +init_load
> +modules.order
> +Module.symvers
> +*.a
> +*.o
> +*.ko
> +*.cmd
> +*.mod
> +*.mod.c
> +.*.cmd
> diff --git a/tests/module_load/Makefile b/tests/module_load/Makefile
> new file mode 100644
> index 0000000..b6eba25
> --- /dev/null
> +++ b/tests/module_load/Makefile
> @@ -0,0 +1,12 @@
> +obj-m = setest_module_load.o setest_module_request.o
> +
> +TARGETS = finit_load init_load
> +LDLIBS += -lselinux
> +KDIR = /lib/modules/$(shell uname -r)/build
> +
> +all: $(TARGETS)
> +	$(MAKE) -C $(KDIR) M=$(PWD)
> +
> +clean:
> +	rm -f $(TARGETS)
> +	rm -f *.a *.o *.ko *.cmd *.mod *.mod.c .*.cmd Module.symvers modules.order
> diff --git a/tests/module_load/finit_load.c b/tests/module_load/finit_load.c
> new file mode 100644
> index 0000000..1c05d7b
> --- /dev/null
> +++ b/tests/module_load/finit_load.c
> @@ -0,0 +1,94 @@
> +#define _GNU_SOURCE 1
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <sys/syscall.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progfile_name)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] path name\n"
> +		"Where:\n\t"
> +		"-v    Print information.\n\t"
> +		"path  Kernel module build path.\n\t"
> +		"name  Name of kernel module to load.\n", progfile_name);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char *context, file_name[PATH_MAX];
> +	int opt, result, fd, s_errno;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "v")) != -1) {
> +		switch (opt) {
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (optind >= argc)
> +		print_usage(argv[0]);
> +
> +	result = sprintf(file_name, "%s/%s.ko", argv[optind],
> +			 argv[optind + 1]);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed sprintf\n");
> +		exit(-1);
> +	}
> +
> +	fd = open(file_name, O_RDONLY);
> +	if (!fd) {
> +		fprintf(stderr, "Failed to open %s: %s\n",
> +			file_name, strerror(errno));
> +		exit(-1);
> +	}
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			close(fd);
> +			exit(-1);
> +		}
> +
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	result = syscall(__NR_finit_module, fd, "", 0);
> +	s_errno = errno;
> +	close(fd);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed to load '%s' module: %s\n",
> +			file_name, strerror(s_errno));
> +		/* Denying: sys_module=EPERM, module_load=EACCES */
> +		exit(s_errno);
> +	}
> +
> +	if (verbose)
> +		printf("Loaded kernel module:  %s\n", file_name);
> +
> +	result = syscall(__NR_delete_module, argv[optind + 1], 0);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed to delete '%s' module: %s\n",
> +			argv[optind + 1], strerror(errno));
> +		exit(-1);
> +	}
> +
> +	if (verbose)
> +		printf("Deleted kernel module: %s\n", argv[optind + 1]);
> +
> +	return 0;
> +}
> diff --git a/tests/module_load/init_load.c b/tests/module_load/init_load.c
> new file mode 100644
> index 0000000..0422c19
> --- /dev/null
> +++ b/tests/module_load/init_load.c
> @@ -0,0 +1,123 @@
> +#define _GNU_SOURCE 1
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <sys/stat.h>
> +#include <sys/syscall.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progfile_name)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] path name\n"
> +		"Where:\n\t"
> +		"-v    Print information.\n\t"
> +		"path  Kernel module build path.\n\t"
> +		"name  Name of kernel module to load.\n", progfile_name);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char *context, file_name[PATH_MAX];
> +	int opt, result, fd, s_errno;
> +	bool verbose = false;
> +	void *elf_image;
> +	struct stat st;
> +
> +	while ((opt = getopt(argc, argv, "v")) != -1) {
> +		switch (opt) {
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (optind >= argc)
> +		print_usage(argv[0]);
> +
> +	result = sprintf(file_name, "%s/%s.ko", argv[optind],
> +			 argv[optind + 1]);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed sprintf\n");
> +		exit(-1);
> +	}
> +
> +	fd = open(file_name, O_RDONLY);
> +	if (!fd) {
> +		fprintf(stderr, "Failed to open %s: %s\n",
> +			file_name, strerror(errno));
> +		exit(-1);
> +	}
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			close(fd);
> +			exit(-1);
> +		}
> +
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	result = fstat(fd, &st);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed fstat on %s: %s\n",
> +			file_name, strerror(errno));
> +		close(fd);
> +		exit(-1);
> +	}
> +
> +	elf_image = malloc(st.st_size);
> +	if (!elf_image) {
> +		fprintf(stderr, "Failed malloc on %s: %s\n",
> +			file_name, strerror(errno));
> +		close(fd);
> +		exit(-1);
> +	}
> +
> +	result = read(fd, elf_image, st.st_size);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed read on %s: %s\n",
> +			file_name, strerror(errno));
> +		close(fd);
> +		free(elf_image);
> +		exit(-1);
> +	}
> +	close(fd);
> +
> +	result = syscall(__NR_init_module, elf_image, st.st_size, "");
> +	s_errno = errno;
> +	free(elf_image);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed to load '%s' module: %s\n",
> +			file_name, strerror(s_errno));
> +		/* Denying: sys_module=EPERM, module_load & request=EACCES */
> +		exit(s_errno);
> +	}
> +
> +	if (verbose)
> +		printf("Loaded kernel module:  %s\n", file_name);
> +
> +	result = syscall(__NR_delete_module, argv[optind + 1], 0);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed to delete '%s' module: %s\n",
> +			argv[optind + 1], strerror(errno));
> +		exit(-1);
> +	}
> +
> +	if (verbose)
> +		printf("Deleted kernel module: %s\n", argv[optind + 1]);
> +
> +	return 0;
> +}
> diff --git a/tests/module_load/setest_module_load.c b/tests/module_load/setest_module_load.c
> new file mode 100644
> index 0000000..0be7a26
> --- /dev/null
> +++ b/tests/module_load/setest_module_load.c
> @@ -0,0 +1,18 @@
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +static int __init setest_module_load_init(void)
> +{
> +	pr_info("INIT - setest_module_load\n");
> +	return 0;
> +}
> +
> +static void __exit setest_module_load_exit(void)
> +{
> +	pr_info("EXIT - setest_module_load\n");
> +}
> +
> +module_init(setest_module_load_init);
> +module_exit(setest_module_load_exit);
> +MODULE_LICENSE("GPL");
> diff --git a/tests/module_load/setest_module_request.c b/tests/module_load/setest_module_request.c
> new file mode 100644
> index 0000000..f79d4ef
> --- /dev/null
> +++ b/tests/module_load/setest_module_request.c
> @@ -0,0 +1,22 @@
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +static int __init setest_module_request_init(void)
> +{
> +	int result;
> +
> +	pr_info("INIT - setest_module_request\n");
> +	result = request_module_nowait("dummy-module");
> +	pr_info("request_module() returned: %d\n", result);
> +	return result;
> +}
> +
> +static void __exit setest_module_request_exit(void)
> +{
> +	pr_info("EXIT - setest_module_request\n");
> +}
> +
> +module_init(setest_module_request_init);
> +module_exit(setest_module_request_exit);
> +MODULE_LICENSE("GPL");
> diff --git a/tests/module_load/test b/tests/module_load/test
> new file mode 100755
> index 0000000..c3242fc
> --- /dev/null
> +++ b/tests/module_load/test
> @@ -0,0 +1,62 @@
> +#!/usr/bin/perl
> +use Test::More;
> +
> +BEGIN {
> +    $basedir = $0;
> +    $basedir =~ s|(.*)/[^/]*|$1|;
> +
> +    # allow info to be shown during tests
> +    $v = $ARGV[0];
> +    if ($v) {
> +        if ( $v ne "-v" ) {
> +            plan skip_all => "Invalid option (use -v)";
> +        }
> +    }
> +    else {
> +        $v = " ";
> +    }
> +
> +    plan tests => 8;
> +}
> +
> +print "Test finit_module(2)\n";
> +$result = system
> +"runcon -t test_finitmod_t $basedir/finit_load $v $basedir setest_module_request";
> +ok( $result eq 0 );
> +
> +# Deny capability { sys_module } - EPERM
> +$result = system
> +"runcon -t test_finitmod_deny_sys_module_t $basedir/finit_load $v $basedir setest_module_load 2>&1";
> +ok( $result >> 8 eq 1 );
> +
> +# Deny system { module_load } - EACCES
> +$result = system
> +"runcon -t test_finitmod_deny_module_load_t $basedir/finit_load $v $basedir setest_module_load 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +# Deny system { module_request } - EACCES
> +$result = system
> +"runcon -t test_finitmod_deny_module_request_t $basedir/finit_load $v $basedir setest_module_request 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +print "Test init_module(2)\n";
> +$result = system
> +"runcon -t test_initmod_t $basedir/init_load $v $basedir setest_module_request";
> +ok( $result eq 0 );
> +
> +# Deny capability { sys_module } - EPERM
> +$result = system
> +"runcon -t test_initmod_deny_sys_module_t $basedir/init_load $v $basedir setest_module_load 2>&1";
> +ok( $result >> 8 eq 1 );
> +
> +# Deny system { module_load } - EACCES
> +$result = system
> +"runcon -t test_initmod_deny_module_load_t $basedir/init_load $v $basedir setest_module_load 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +# Deny system { module_request } - EACCES
> +$result = system
> +"runcon -t test_initmod_deny_module_request_t $basedir/init_load $v $basedir setest_module_request 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +exit;
>

Patch
diff mbox series

diff --git a/policy/Makefile b/policy/Makefile
index ad94c43..25dfb69 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -94,6 +94,10 @@  ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && echo
 TARGETS += test_key_socket.te
 endif
 
+ifeq ($(shell grep -q module_load $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS+=test_module_load.te
+endif
+
 ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
 TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
 endif
diff --git a/policy/test_module_load.te b/policy/test_module_load.te
new file mode 100644
index 0000000..9256ddd
--- /dev/null
+++ b/policy/test_module_load.te
@@ -0,0 +1,110 @@ 
+#
+############################## Define Macro ################################
+#
+# Replace domain_type() macro as it hides some relevant denials in audit.log
+#
+gen_require(`
+	type setrans_var_run_t, syslogd_t;
+')
+
+define(`module_domain_type',`
+	allow $1 proc_t:dir { search };
+	allow $1 proc_t:lnk_file { read };
+	allow $1 self:dir { search };
+	allow $1 self:file { open read write };
+	dontaudit init_t syslogd_t:fd use;
+	dontaudit $1 security_t:filesystem getattr;
+	dontaudit $1 self:file getattr;
+	dontaudit $1 setrans_var_run_t:dir search;
+	dontaudit unconfined_t $1:process { noatsecure rlimitinh siginh };
+')
+
+#
+############# Test kernel modules with finitmod_module(2) ###################
+#
+attribute finitmoddomain;
+
+type test_finitmod_t;
+module_domain_type(test_finitmod_t)
+unconfined_runs_test(test_finitmod_t)
+typeattribute test_finitmod_t testdomain, finitmoddomain;
+
+allow test_finitmod_t self:capability { sys_module };
+allow test_finitmod_t test_file_t:system { module_load };
+allow test_finitmod_t kernel_t:system { module_request };
+
+############### Deny cap sys_module ######################
+type test_finitmod_deny_sys_module_t;
+module_domain_type(test_finitmod_deny_sys_module_t)
+unconfined_runs_test(test_finitmod_deny_sys_module_t)
+typeattribute test_finitmod_deny_sys_module_t testdomain, finitmoddomain;
+
+neverallow test_finitmod_deny_sys_module_t self:capability { sys_module };
+
+############### Deny sys module_load ######################
+type test_finitmod_deny_module_load_t;
+module_domain_type(test_finitmod_deny_module_load_t)
+unconfined_runs_test(test_finitmod_deny_module_load_t)
+typeattribute test_finitmod_deny_module_load_t testdomain, finitmoddomain;
+
+allow test_finitmod_deny_module_load_t self:capability { sys_module };
+neverallow test_finitmod_deny_module_load_t test_file_t:system { module_load };
+
+############### Deny sys module_request ######################
+type test_finitmod_deny_module_request_t;
+module_domain_type(test_finitmod_deny_module_request_t)
+unconfined_runs_test(test_finitmod_deny_module_request_t)
+typeattribute test_finitmod_deny_module_request_t testdomain, finitmoddomain;
+
+allow test_finitmod_deny_module_request_t self:capability { sys_module };
+allow test_finitmod_deny_module_request_t test_file_t:system { module_load };
+neverallow test_finitmod_deny_module_request_t kernel_t:system { module_request };
+
+#
+############# Test kernel modules with initmod_module(2) ###################
+#
+attribute initmoddomain;
+
+type test_initmod_t;
+module_domain_type(test_initmod_t)
+unconfined_runs_test(test_initmod_t)
+typeattribute test_initmod_t testdomain, initmoddomain;
+
+allow test_initmod_t self:capability { sys_module };
+allow test_initmod_t self:system { module_load };
+allow test_initmod_t kernel_t:system { module_request };
+
+############### Deny cap sys_module ######################
+type test_initmod_deny_sys_module_t;
+module_domain_type(test_initmod_deny_sys_module_t)
+unconfined_runs_test(test_initmod_deny_sys_module_t)
+typeattribute test_initmod_deny_sys_module_t testdomain, initmoddomain;
+
+neverallow test_initmod_deny_sys_module_t self:capability { sys_module };
+
+############### Deny sys module_load ######################
+type test_initmod_deny_module_load_t;
+module_domain_type(test_initmod_deny_module_load_t)
+unconfined_runs_test(test_initmod_deny_module_load_t)
+typeattribute test_initmod_deny_module_load_t testdomain, initmoddomain;
+
+allow test_initmod_deny_module_load_t self:capability { sys_module };
+neverallow test_initmod_deny_module_load_t self:system { module_load };
+
+############### Deny sys module_request ######################
+type test_initmod_deny_module_request_t;
+module_domain_type(test_initmod_deny_module_request_t)
+unconfined_runs_test(test_initmod_deny_module_request_t)
+typeattribute test_initmod_deny_module_request_t testdomain, initmoddomain;
+
+allow test_initmod_deny_module_request_t self:capability { sys_module };
+allow test_initmod_deny_module_request_t self:system { module_load };
+neverallow test_initmod_deny_module_request_t kernel_t:system { module_request };
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(finitmoddomain)
+userdom_sysadm_entry_spec_domtrans_to(finitmoddomain)
+miscfiles_domain_entry_test_files(initmoddomain)
+userdom_sysadm_entry_spec_domtrans_to(initmoddomain)
diff --git a/tests/Makefile b/tests/Makefile
index cca6648..0452887 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -72,6 +72,10 @@  ifeq ($(shell grep -q all_file_perms.*watch $(POLDEV)/include/support/all_perms.
 SUBDIRS+=notify
 endif
 
+ifeq ($(shell grep -q module_load $(POLDEV)/include/support/all_perms.spt && echo true),true)
+SUBDIRS+=module_load
+endif
+
 ifeq ($(DISTRO),RHEL4)
     SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
 endif
diff --git a/tests/module_load/.gitignore b/tests/module_load/.gitignore
new file mode 100644
index 0000000..7fa5772
--- /dev/null
+++ b/tests/module_load/.gitignore
@@ -0,0 +1,11 @@ 
+finit_load
+init_load
+modules.order
+Module.symvers
+*.a
+*.o
+*.ko
+*.cmd
+*.mod
+*.mod.c
+.*.cmd
diff --git a/tests/module_load/Makefile b/tests/module_load/Makefile
new file mode 100644
index 0000000..b6eba25
--- /dev/null
+++ b/tests/module_load/Makefile
@@ -0,0 +1,12 @@ 
+obj-m = setest_module_load.o setest_module_request.o
+
+TARGETS = finit_load init_load
+LDLIBS += -lselinux
+KDIR = /lib/modules/$(shell uname -r)/build
+
+all: $(TARGETS)
+	$(MAKE) -C $(KDIR) M=$(PWD)
+
+clean:
+	rm -f $(TARGETS)
+	rm -f *.a *.o *.ko *.cmd *.mod *.mod.c .*.cmd Module.symvers modules.order
diff --git a/tests/module_load/finit_load.c b/tests/module_load/finit_load.c
new file mode 100644
index 0000000..1c05d7b
--- /dev/null
+++ b/tests/module_load/finit_load.c
@@ -0,0 +1,94 @@ 
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/syscall.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progfile_name)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] path name\n"
+		"Where:\n\t"
+		"-v    Print information.\n\t"
+		"path  Kernel module build path.\n\t"
+		"name  Name of kernel module to load.\n", progfile_name);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *context, file_name[PATH_MAX];
+	int opt, result, fd, s_errno;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (optind >= argc)
+		print_usage(argv[0]);
+
+	result = sprintf(file_name, "%s/%s.ko", argv[optind],
+			 argv[optind + 1]);
+	if (result < 0) {
+		fprintf(stderr, "Failed sprintf\n");
+		exit(-1);
+	}
+
+	fd = open(file_name, O_RDONLY);
+	if (!fd) {
+		fprintf(stderr, "Failed to open %s: %s\n",
+			file_name, strerror(errno));
+		exit(-1);
+	}
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			close(fd);
+			exit(-1);
+		}
+
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	result = syscall(__NR_finit_module, fd, "", 0);
+	s_errno = errno;
+	close(fd);
+	if (result < 0) {
+		fprintf(stderr, "Failed to load '%s' module: %s\n",
+			file_name, strerror(s_errno));
+		/* Denying: sys_module=EPERM, module_load=EACCES */
+		exit(s_errno);
+	}
+
+	if (verbose)
+		printf("Loaded kernel module:  %s\n", file_name);
+
+	result = syscall(__NR_delete_module, argv[optind + 1], 0);
+	if (result < 0) {
+		fprintf(stderr, "Failed to delete '%s' module: %s\n",
+			argv[optind + 1], strerror(errno));
+		exit(-1);
+	}
+
+	if (verbose)
+		printf("Deleted kernel module: %s\n", argv[optind + 1]);
+
+	return 0;
+}
diff --git a/tests/module_load/init_load.c b/tests/module_load/init_load.c
new file mode 100644
index 0000000..0422c19
--- /dev/null
+++ b/tests/module_load/init_load.c
@@ -0,0 +1,123 @@ 
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progfile_name)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] path name\n"
+		"Where:\n\t"
+		"-v    Print information.\n\t"
+		"path  Kernel module build path.\n\t"
+		"name  Name of kernel module to load.\n", progfile_name);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *context, file_name[PATH_MAX];
+	int opt, result, fd, s_errno;
+	bool verbose = false;
+	void *elf_image;
+	struct stat st;
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (optind >= argc)
+		print_usage(argv[0]);
+
+	result = sprintf(file_name, "%s/%s.ko", argv[optind],
+			 argv[optind + 1]);
+	if (result < 0) {
+		fprintf(stderr, "Failed sprintf\n");
+		exit(-1);
+	}
+
+	fd = open(file_name, O_RDONLY);
+	if (!fd) {
+		fprintf(stderr, "Failed to open %s: %s\n",
+			file_name, strerror(errno));
+		exit(-1);
+	}
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			close(fd);
+			exit(-1);
+		}
+
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	result = fstat(fd, &st);
+	if (result < 0) {
+		fprintf(stderr, "Failed fstat on %s: %s\n",
+			file_name, strerror(errno));
+		close(fd);
+		exit(-1);
+	}
+
+	elf_image = malloc(st.st_size);
+	if (!elf_image) {
+		fprintf(stderr, "Failed malloc on %s: %s\n",
+			file_name, strerror(errno));
+		close(fd);
+		exit(-1);
+	}
+
+	result = read(fd, elf_image, st.st_size);
+	if (result < 0) {
+		fprintf(stderr, "Failed read on %s: %s\n",
+			file_name, strerror(errno));
+		close(fd);
+		free(elf_image);
+		exit(-1);
+	}
+	close(fd);
+
+	result = syscall(__NR_init_module, elf_image, st.st_size, "");
+	s_errno = errno;
+	free(elf_image);
+	if (result < 0) {
+		fprintf(stderr, "Failed to load '%s' module: %s\n",
+			file_name, strerror(s_errno));
+		/* Denying: sys_module=EPERM, module_load & request=EACCES */
+		exit(s_errno);
+	}
+
+	if (verbose)
+		printf("Loaded kernel module:  %s\n", file_name);
+
+	result = syscall(__NR_delete_module, argv[optind + 1], 0);
+	if (result < 0) {
+		fprintf(stderr, "Failed to delete '%s' module: %s\n",
+			argv[optind + 1], strerror(errno));
+		exit(-1);
+	}
+
+	if (verbose)
+		printf("Deleted kernel module: %s\n", argv[optind + 1]);
+
+	return 0;
+}
diff --git a/tests/module_load/setest_module_load.c b/tests/module_load/setest_module_load.c
new file mode 100644
index 0000000..0be7a26
--- /dev/null
+++ b/tests/module_load/setest_module_load.c
@@ -0,0 +1,18 @@ 
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+static int __init setest_module_load_init(void)
+{
+	pr_info("INIT - setest_module_load\n");
+	return 0;
+}
+
+static void __exit setest_module_load_exit(void)
+{
+	pr_info("EXIT - setest_module_load\n");
+}
+
+module_init(setest_module_load_init);
+module_exit(setest_module_load_exit);
+MODULE_LICENSE("GPL");
diff --git a/tests/module_load/setest_module_request.c b/tests/module_load/setest_module_request.c
new file mode 100644
index 0000000..f79d4ef
--- /dev/null
+++ b/tests/module_load/setest_module_request.c
@@ -0,0 +1,22 @@ 
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+static int __init setest_module_request_init(void)
+{
+	int result;
+
+	pr_info("INIT - setest_module_request\n");
+	result = request_module_nowait("dummy-module");
+	pr_info("request_module() returned: %d\n", result);
+	return result;
+}
+
+static void __exit setest_module_request_exit(void)
+{
+	pr_info("EXIT - setest_module_request\n");
+}
+
+module_init(setest_module_request_init);
+module_exit(setest_module_request_exit);
+MODULE_LICENSE("GPL");
diff --git a/tests/module_load/test b/tests/module_load/test
new file mode 100755
index 0000000..c3242fc
--- /dev/null
+++ b/tests/module_load/test
@@ -0,0 +1,62 @@ 
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    # allow info to be shown during tests
+    $v = $ARGV[0];
+    if ($v) {
+        if ( $v ne "-v" ) {
+            plan skip_all => "Invalid option (use -v)";
+        }
+    }
+    else {
+        $v = " ";
+    }
+
+    plan tests => 8;
+}
+
+print "Test finit_module(2)\n";
+$result = system
+"runcon -t test_finitmod_t $basedir/finit_load $v $basedir setest_module_request";
+ok( $result eq 0 );
+
+# Deny capability { sys_module } - EPERM
+$result = system
+"runcon -t test_finitmod_deny_sys_module_t $basedir/finit_load $v $basedir setest_module_load 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny system { module_load } - EACCES
+$result = system
+"runcon -t test_finitmod_deny_module_load_t $basedir/finit_load $v $basedir setest_module_load 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Deny system { module_request } - EACCES
+$result = system
+"runcon -t test_finitmod_deny_module_request_t $basedir/finit_load $v $basedir setest_module_request 2>&1";
+ok( $result >> 8 eq 13 );
+
+print "Test init_module(2)\n";
+$result = system
+"runcon -t test_initmod_t $basedir/init_load $v $basedir setest_module_request";
+ok( $result eq 0 );
+
+# Deny capability { sys_module } - EPERM
+$result = system
+"runcon -t test_initmod_deny_sys_module_t $basedir/init_load $v $basedir setest_module_load 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny system { module_load } - EACCES
+$result = system
+"runcon -t test_initmod_deny_module_load_t $basedir/init_load $v $basedir setest_module_load 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Deny system { module_request } - EACCES
+$result = system
+"runcon -t test_initmod_deny_module_request_t $basedir/init_load $v $basedir setest_module_request 2>&1";
+ok( $result >> 8 eq 13 );
+
+exit;