linux-kselftest-5.6-rc1-kunit
This kunit update for Linux 5.6-rc1 consists of: -- Support for building kunit as a module from Alan Maguire -- AppArmor KUnit tests for policy unpack from Mike Salvatore -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAl4xz/wACgkQCwJExA0N Qxyg2A//X0bnhN82oCchkTRW3GyGi5wTR2wGhoNzMZD0XUtCvn+4BlCSP20ttYdT beiLCiewcuEdvXRyEV9Kikvet/67ovbjA/ce6ZrR7TlIHo8esKcy19/nu1OTvtI1 8eji1q7NSEV9iswz1ZoBAw+MTDHZfOI9qYY2UPcwjy7xWN84z2X1w+8UQ3EamOKd 6BfbohsYuuTTHhA2k1aUzvQcHqNz0YdH4yvNQpdunJXLUI04TeGZA6Ug66u6kWEd 1f5SSAu6r1vnU7DADrb1QwEDuIwL4KBuaMg2Rj5GLxTNp3wxmW9M2Dit+iN7+vNH TS31kZW6KgxC5XuGVPENJaWlDX5Hm+5W8uiRZLNXsxDy927u53RzwrSZw/FbdbB1 HuPZZCzE1soWHdPIQz44HCCAg9XddypYlC1o4IYL1JkJknqG12ky4xgM8GRNCZAB oUW3Ax3Lcr0EJALO/kFd/uEbl79PdmDk8uPMU1jtLyx5cs70yC3fsT2GB+DbP802 i/FxTtrOMGjU2OWcYfQcXapvZdgImf9nPsSZe3FJXjHfytNRbVZOZ2rHAMh03Keu EBthDs6ejm6OUSGUXjngE9NaQKXsNSQ1Qor+6FrGnT4IxUMzWenudqHH7/dgF7Fr fHlZGBilKMc/EYKb/6hj4kvEChrSIXj6TFknmI28I/epPiOr2gU= =AFO4 -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-5.6-rc1-kunit' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull Kselftest kunit updates from Shuah Khan: "This kunit update consists of: - Support for building kunit as a module from Alan Maguire - AppArmor KUnit tests for policy unpack from Mike Salvatore" * tag 'linux-kselftest-5.6-rc1-kunit' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: building kunit as a module breaks allmodconfig kunit: update documentation to describe module-based build kunit: allow kunit to be loaded as a module kunit: remove timeout dependence on sysctl_hung_task_timeout_seconds kunit: allow kunit tests to be loaded as a module kunit: hide unexported try-catch interface in try-catch-impl.h kunit: move string-stream.h to lib/kunit apparmor: add AppArmor KUnit tests for policy unpack
This commit is contained in:
		
						commit
						08a3ef8f6b
					
				| @ -29,7 +29,8 @@ Yes, well, mostly. | ||||
| 
 | ||||
| For the most part, the KUnit core framework (what you use to write the tests) | ||||
| can compile to any architecture; it compiles like just another part of the | ||||
| kernel and runs when the kernel boots. However, there is some infrastructure, | ||||
| kernel and runs when the kernel boots, or when built as a module, when the | ||||
| module is loaded.  However, there is some infrastructure, | ||||
| like the KUnit Wrapper (``tools/testing/kunit/kunit.py``) that does not support | ||||
| other architectures. | ||||
| 
 | ||||
|  | ||||
| @ -49,6 +49,9 @@ to a standalone program that can be run like any other program directly inside | ||||
| of a host operating system; to be clear, it does not require any virtualization | ||||
| support; it is just a regular program. | ||||
| 
 | ||||
| Alternatively, kunit and kunit tests can be built as modules and tests will | ||||
| run when the test module is loaded. | ||||
| 
 | ||||
| KUnit is fast. Excluding build time, from invocation to completion KUnit can run | ||||
| several dozen tests in only 10 to 20 seconds; this might not sound like a big | ||||
| deal to some people, but having such fast and easy to run tests fundamentally | ||||
|  | ||||
| @ -539,6 +539,22 @@ Interspersed in the kernel logs you might see the following: | ||||
| 
 | ||||
| Congratulations, you just ran a KUnit test on the x86 architecture! | ||||
| 
 | ||||
| In a similar manner, kunit and kunit tests can also be built as modules, | ||||
| so if you wanted to run tests in this way you might add the following config | ||||
| options to your ``.config``: | ||||
| 
 | ||||
| .. code-block:: none | ||||
| 
 | ||||
| 	CONFIG_KUNIT=m | ||||
| 	CONFIG_KUNIT_EXAMPLE_TEST=m | ||||
| 
 | ||||
| Once the kernel is built and installed, a simple | ||||
| 
 | ||||
| .. code-block:: bash | ||||
| 	modprobe example-test | ||||
| 
 | ||||
| ...will run the tests. | ||||
| 
 | ||||
| Writing new tests for other architectures | ||||
| ----------------------------------------- | ||||
| 
 | ||||
|  | ||||
| @ -150,7 +150,7 @@ config DEBUG_TEST_DRIVER_REMOVE | ||||
| 
 | ||||
| config PM_QOS_KUNIT_TEST | ||||
| 	bool "KUnit Test for PM QoS features" | ||||
| 	depends on KUNIT | ||||
| 	depends on KUNIT=y | ||||
| 
 | ||||
| config HMEM_REPORTING | ||||
| 	bool | ||||
|  | ||||
| @ -114,4 +114,4 @@ static struct kunit_suite pm_qos_test_module = { | ||||
| 	.name = "qos-kunit-test", | ||||
| 	.test_cases = pm_qos_test_cases, | ||||
| }; | ||||
| kunit_test_suite(pm_qos_test_module); | ||||
| kunit_test_suites(&pm_qos_test_module); | ||||
|  | ||||
| @ -109,7 +109,7 @@ config EXT4_DEBUG | ||||
| 		echo 1 > /sys/module/ext4/parameters/mballoc_debug | ||||
| 
 | ||||
| config EXT4_KUNIT_TESTS | ||||
| 	bool "KUnit tests for ext4" | ||||
| 	tristate "KUnit tests for ext4" | ||||
| 	select EXT4_FS | ||||
| 	depends on KUNIT | ||||
| 	help | ||||
|  | ||||
| @ -13,5 +13,6 @@ ext4-y	:= balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \ | ||||
| 
 | ||||
| ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o | ||||
| ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o | ||||
| ext4-$(CONFIG_EXT4_KUNIT_TESTS)		+= inode-test.o | ||||
| ext4-inode-test-objs			+= inode-test.o | ||||
| obj-$(CONFIG_EXT4_KUNIT_TESTS)		+= ext4-inode-test.o | ||||
| ext4-$(CONFIG_FS_VERITY)		+= verity.o | ||||
|  | ||||
| @ -269,4 +269,6 @@ static struct kunit_suite ext4_inode_test_suite = { | ||||
| 	.test_cases = ext4_inode_test_cases, | ||||
| }; | ||||
| 
 | ||||
| kunit_test_suite(ext4_inode_test_suite); | ||||
| kunit_test_suites(&ext4_inode_test_suite); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  | ||||
| @ -9,10 +9,11 @@ | ||||
| #ifndef _KUNIT_ASSERT_H | ||||
| #define _KUNIT_ASSERT_H | ||||
| 
 | ||||
| #include <kunit/string-stream.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/kernel.h> | ||||
| 
 | ||||
| struct kunit; | ||||
| struct string_stream; | ||||
| 
 | ||||
| /**
 | ||||
|  * enum kunit_assert_type - Type of expectation/assertion. | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
| #include <kunit/assert.h> | ||||
| #include <kunit/try-catch.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| @ -197,31 +198,47 @@ void kunit_init_test(struct kunit *test, const char *name); | ||||
| int kunit_run_tests(struct kunit_suite *suite); | ||||
| 
 | ||||
| /**
 | ||||
|  * kunit_test_suite() - used to register a &struct kunit_suite with KUnit. | ||||
|  * kunit_test_suites() - used to register one or more &struct kunit_suite | ||||
|  *			 with KUnit. | ||||
|  * | ||||
|  * @suite: a statically allocated &struct kunit_suite. | ||||
|  * @suites: a statically allocated list of &struct kunit_suite. | ||||
|  * | ||||
|  * Registers @suite with the test framework. See &struct kunit_suite for | ||||
|  * Registers @suites with the test framework. See &struct kunit_suite for | ||||
|  * more information. | ||||
|  * | ||||
|  * NOTE: Currently KUnit tests are all run as late_initcalls; this means | ||||
|  * When builtin,  KUnit tests are all run as late_initcalls; this means | ||||
|  * that they cannot test anything where tests must run at a different init | ||||
|  * phase. One significant restriction resulting from this is that KUnit | ||||
|  * cannot reliably test anything that is initialize in the late_init phase; | ||||
|  * another is that KUnit is useless to test things that need to be run in | ||||
|  * an earlier init phase. | ||||
|  * | ||||
|  * An alternative is to build the tests as a module.  Because modules | ||||
|  * do not support multiple late_initcall()s, we need to initialize an | ||||
|  * array of suites for a module. | ||||
|  * | ||||
|  * TODO(brendanhiggins@google.com): Don't run all KUnit tests as | ||||
|  * late_initcalls.  I have some future work planned to dispatch all KUnit | ||||
|  * tests from the same place, and at the very least to do so after | ||||
|  * everything else is definitely initialized. | ||||
|  */ | ||||
| #define kunit_test_suite(suite)						       \ | ||||
| 	static int kunit_suite_init##suite(void)			       \ | ||||
| 	{								       \ | ||||
| 		return kunit_run_tests(&suite);				       \ | ||||
| 	}								       \ | ||||
| 	late_initcall(kunit_suite_init##suite) | ||||
| #define kunit_test_suites(...)						\ | ||||
| 	static struct kunit_suite *suites[] = { __VA_ARGS__, NULL};	\ | ||||
| 	static int kunit_test_suites_init(void)				\ | ||||
| 	{								\ | ||||
| 		unsigned int i;						\ | ||||
| 		for (i = 0; suites[i] != NULL; i++)			\ | ||||
| 			kunit_run_tests(suites[i]);			\ | ||||
| 		return 0;						\ | ||||
| 	}								\ | ||||
| 	late_initcall(kunit_test_suites_init);				\ | ||||
| 	static void __exit kunit_test_suites_exit(void)			\ | ||||
| 	{								\ | ||||
| 		return;							\ | ||||
| 	}								\ | ||||
| 	module_exit(kunit_test_suites_exit) | ||||
| 
 | ||||
| #define kunit_test_suite(suite)	kunit_test_suites(&suite) | ||||
| 
 | ||||
| /*
 | ||||
|  * Like kunit_alloc_resource() below, but returns the struct kunit_resource | ||||
|  | ||||
| @ -53,11 +53,6 @@ struct kunit_try_catch { | ||||
| 	void *context; | ||||
| }; | ||||
| 
 | ||||
| void kunit_try_catch_init(struct kunit_try_catch *try_catch, | ||||
| 			  struct kunit *test, | ||||
| 			  kunit_try_catch_func_t try, | ||||
| 			  kunit_try_catch_func_t catch); | ||||
| 
 | ||||
| void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context); | ||||
| 
 | ||||
| void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch); | ||||
| @ -67,9 +62,4 @@ static inline int kunit_try_catch_get_result(struct kunit_try_catch *try_catch) | ||||
| 	return try_catch->try_result; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Exposed for testing only. | ||||
|  */ | ||||
| void kunit_generic_try_catch_init(struct kunit_try_catch *try_catch); | ||||
| 
 | ||||
| #endif /* _KUNIT_TRY_CATCH_H */ | ||||
|  | ||||
| @ -389,4 +389,6 @@ static struct kunit_suite sysctl_test_suite = { | ||||
| 	.test_cases = sysctl_test_cases, | ||||
| }; | ||||
| 
 | ||||
| kunit_test_suite(sysctl_test_suite); | ||||
| kunit_test_suites(&sysctl_test_suite); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  | ||||
| @ -2025,7 +2025,7 @@ config TEST_SYSCTL | ||||
| 	  If unsure, say N. | ||||
| 
 | ||||
| config SYSCTL_KUNIT_TEST | ||||
| 	bool "KUnit test for sysctl" | ||||
| 	tristate "KUnit test for sysctl" | ||||
| 	depends on KUNIT | ||||
| 	help | ||||
| 	  This builds the proc sysctl unit test, which runs on boot. | ||||
| @ -2036,7 +2036,7 @@ config SYSCTL_KUNIT_TEST | ||||
| 	  If unsure, say N. | ||||
| 
 | ||||
| config LIST_KUNIT_TEST | ||||
| 	bool "KUnit Test for Kernel Linked-list structures" | ||||
| 	tristate "KUnit Test for Kernel Linked-list structures" | ||||
| 	depends on KUNIT | ||||
| 	help | ||||
| 	  This builds the linked list KUnit test suite. | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| # | ||||
| 
 | ||||
| menuconfig KUNIT | ||||
| 	bool "KUnit - Enable support for unit tests" | ||||
| 	tristate "KUnit - Enable support for unit tests" | ||||
| 	help | ||||
| 	  Enables support for kernel unit tests (KUnit), a lightweight unit | ||||
| 	  testing and mocking framework for the Linux kernel. These tests are | ||||
| @ -15,7 +15,7 @@ menuconfig KUNIT | ||||
| if KUNIT | ||||
| 
 | ||||
| config KUNIT_TEST | ||||
| 	bool "KUnit test for KUnit" | ||||
| 	tristate "KUnit test for KUnit" | ||||
| 	help | ||||
| 	  Enables the unit tests for the KUnit test framework. These tests test | ||||
| 	  the KUnit test framework itself; the tests are both written using | ||||
| @ -24,7 +24,7 @@ config KUNIT_TEST | ||||
| 	  expected. | ||||
| 
 | ||||
| config KUNIT_EXAMPLE_TEST | ||||
| 	bool "Example test for KUnit" | ||||
| 	tristate "Example test for KUnit" | ||||
| 	help | ||||
| 	  Enables an example unit test that illustrates some of the basic | ||||
| 	  features of KUnit. This test only exists to help new users understand | ||||
|  | ||||
| @ -1,9 +1,15 @@ | ||||
| obj-$(CONFIG_KUNIT) +=			test.o \
 | ||||
| obj-$(CONFIG_KUNIT) +=			kunit.o | ||||
| 
 | ||||
| kunit-objs +=				test.o \
 | ||||
| 					string-stream.o \
 | ||||
| 					assert.o \
 | ||||
| 					try-catch.o | ||||
| 
 | ||||
| obj-$(CONFIG_KUNIT_TEST) +=		test-test.o \
 | ||||
| 					string-stream-test.o | ||||
| obj-$(CONFIG_KUNIT_TEST) +=		kunit-test.o | ||||
| 
 | ||||
| obj-$(CONFIG_KUNIT_EXAMPLE_TEST) +=	example-test.o | ||||
| # string-stream-test compiles built-in only.
 | ||||
| ifeq ($(CONFIG_KUNIT_TEST),y) | ||||
| obj-$(CONFIG_KUNIT_TEST) +=		string-stream-test.o | ||||
| endif | ||||
| 
 | ||||
| obj-$(CONFIG_KUNIT_EXAMPLE_TEST) +=	kunit-example-test.o | ||||
|  | ||||
| @ -7,6 +7,8 @@ | ||||
|  */ | ||||
| #include <kunit/assert.h> | ||||
| 
 | ||||
| #include "string-stream.h" | ||||
| 
 | ||||
| void kunit_base_assert_format(const struct kunit_assert *assert, | ||||
| 			      struct string_stream *stream) | ||||
| { | ||||
| @ -24,6 +26,7 @@ void kunit_base_assert_format(const struct kunit_assert *assert, | ||||
| 	string_stream_add(stream, "%s FAILED at %s:%d\n", | ||||
| 			 expect_or_assert, assert->file, assert->line); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_base_assert_format); | ||||
| 
 | ||||
| void kunit_assert_print_msg(const struct kunit_assert *assert, | ||||
| 			    struct string_stream *stream) | ||||
| @ -31,6 +34,7 @@ void kunit_assert_print_msg(const struct kunit_assert *assert, | ||||
| 	if (assert->message.fmt) | ||||
| 		string_stream_add(stream, "\n%pV", &assert->message); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_assert_print_msg); | ||||
| 
 | ||||
| void kunit_fail_assert_format(const struct kunit_assert *assert, | ||||
| 			      struct string_stream *stream) | ||||
| @ -38,6 +42,7 @@ void kunit_fail_assert_format(const struct kunit_assert *assert, | ||||
| 	kunit_base_assert_format(assert, stream); | ||||
| 	string_stream_add(stream, "%pV", &assert->message); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_fail_assert_format); | ||||
| 
 | ||||
| void kunit_unary_assert_format(const struct kunit_assert *assert, | ||||
| 			       struct string_stream *stream) | ||||
| @ -56,6 +61,7 @@ void kunit_unary_assert_format(const struct kunit_assert *assert, | ||||
| 				 unary_assert->condition); | ||||
| 	kunit_assert_print_msg(assert, stream); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_unary_assert_format); | ||||
| 
 | ||||
| void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, | ||||
| 				     struct string_stream *stream) | ||||
| @ -76,6 +82,7 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, | ||||
| 	} | ||||
| 	kunit_assert_print_msg(assert, stream); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format); | ||||
| 
 | ||||
| void kunit_binary_assert_format(const struct kunit_assert *assert, | ||||
| 				struct string_stream *stream) | ||||
| @ -97,6 +104,7 @@ void kunit_binary_assert_format(const struct kunit_assert *assert, | ||||
| 			 binary_assert->right_value); | ||||
| 	kunit_assert_print_msg(assert, stream); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_binary_assert_format); | ||||
| 
 | ||||
| void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, | ||||
| 				    struct string_stream *stream) | ||||
| @ -118,6 +126,7 @@ void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, | ||||
| 			 binary_assert->right_value); | ||||
| 	kunit_assert_print_msg(assert, stream); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format); | ||||
| 
 | ||||
| void kunit_binary_str_assert_format(const struct kunit_assert *assert, | ||||
| 				    struct string_stream *stream) | ||||
| @ -139,3 +148,4 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert, | ||||
| 			 binary_assert->right_value); | ||||
| 	kunit_assert_print_msg(assert, stream); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format); | ||||
|  | ||||
| @ -85,4 +85,6 @@ static struct kunit_suite example_test_suite = { | ||||
|  * This registers the above test suite telling KUnit that this is a suite of | ||||
|  * tests that need to be run. | ||||
|  */ | ||||
| kunit_test_suite(example_test_suite); | ||||
| kunit_test_suites(&example_test_suite); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @ -7,6 +7,8 @@ | ||||
|  */ | ||||
| #include <kunit/test.h> | ||||
| 
 | ||||
| #include "try-catch-impl.h" | ||||
| 
 | ||||
| struct kunit_try_catch_test_context { | ||||
| 	struct kunit_try_catch *try_catch; | ||||
| 	bool function_called; | ||||
| @ -100,7 +102,6 @@ static struct kunit_suite kunit_try_catch_test_suite = { | ||||
| 	.init = kunit_try_catch_test_init, | ||||
| 	.test_cases = kunit_try_catch_test_cases, | ||||
| }; | ||||
| kunit_test_suite(kunit_try_catch_test_suite); | ||||
| 
 | ||||
| /*
 | ||||
|  * Context for testing test managed resources | ||||
| @ -328,4 +329,6 @@ static struct kunit_suite kunit_resource_test_suite = { | ||||
| 	.exit = kunit_resource_test_exit, | ||||
| 	.test_cases = kunit_resource_test_cases, | ||||
| }; | ||||
| kunit_test_suite(kunit_resource_test_suite); | ||||
| kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @ -6,10 +6,11 @@ | ||||
|  * Author: Brendan Higgins <brendanhiggins@google.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <kunit/string-stream.h> | ||||
| #include <kunit/test.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| #include "string-stream.h" | ||||
| 
 | ||||
| static void string_stream_test_empty_on_creation(struct kunit *test) | ||||
| { | ||||
| 	struct string_stream *stream = alloc_string_stream(test, GFP_KERNEL); | ||||
| @ -49,4 +50,4 @@ static struct kunit_suite string_stream_test_suite = { | ||||
| 	.name = "string-stream-test", | ||||
| 	.test_cases = string_stream_test_cases | ||||
| }; | ||||
| kunit_test_suite(string_stream_test_suite); | ||||
| kunit_test_suites(&string_stream_test_suite); | ||||
|  | ||||
| @ -6,11 +6,12 @@ | ||||
|  * Author: Brendan Higgins <brendanhiggins@google.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <kunit/string-stream.h> | ||||
| #include <kunit/test.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| #include "string-stream.h" | ||||
| 
 | ||||
| struct string_stream_fragment_alloc_context { | ||||
| 	struct kunit *test; | ||||
| 	int len; | ||||
|  | ||||
| @ -7,10 +7,12 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <kunit/test.h> | ||||
| #include <kunit/try-catch.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/sched/debug.h> | ||||
| 
 | ||||
| #include "string-stream.h" | ||||
| #include "try-catch-impl.h" | ||||
| 
 | ||||
| static void kunit_set_failure(struct kunit *test) | ||||
| { | ||||
| 	WRITE_ONCE(test->success, false); | ||||
| @ -171,6 +173,7 @@ void kunit_do_assertion(struct kunit *test, | ||||
| 	if (assert->type == KUNIT_ASSERTION) | ||||
| 		kunit_abort(test); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_do_assertion); | ||||
| 
 | ||||
| void kunit_init_test(struct kunit *test, const char *name) | ||||
| { | ||||
| @ -179,6 +182,7 @@ void kunit_init_test(struct kunit *test, const char *name) | ||||
| 	test->name = name; | ||||
| 	test->success = true; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_init_test); | ||||
| 
 | ||||
| /*
 | ||||
|  * Initializes and runs test case. Does not clean up or do post validations. | ||||
| @ -317,6 +321,7 @@ int kunit_run_tests(struct kunit_suite *suite) | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_run_tests); | ||||
| 
 | ||||
| struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test, | ||||
| 						    kunit_resource_init_t init, | ||||
| @ -342,6 +347,7 @@ struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test, | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource); | ||||
| 
 | ||||
| static void kunit_resource_free(struct kunit *test, struct kunit_resource *res) | ||||
| { | ||||
| @ -400,6 +406,7 @@ int kunit_resource_destroy(struct kunit *test, | ||||
| 	kunit_resource_free(test, resource); | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_resource_destroy); | ||||
| 
 | ||||
| struct kunit_kmalloc_params { | ||||
| 	size_t size; | ||||
| @ -435,6 +442,7 @@ void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) | ||||
| 				    gfp, | ||||
| 				    ¶ms); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_kmalloc); | ||||
| 
 | ||||
| void kunit_kfree(struct kunit *test, const void *ptr) | ||||
| { | ||||
| @ -447,6 +455,7 @@ void kunit_kfree(struct kunit *test, const void *ptr) | ||||
| 
 | ||||
| 	WARN_ON(rc); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_kfree); | ||||
| 
 | ||||
| void kunit_cleanup(struct kunit *test) | ||||
| { | ||||
| @ -476,3 +485,17 @@ void kunit_cleanup(struct kunit *test) | ||||
| 		kunit_resource_free(test, resource); | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_cleanup); | ||||
| 
 | ||||
| static int __init kunit_init(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| late_initcall(kunit_init); | ||||
| 
 | ||||
| static void __exit kunit_exit(void) | ||||
| { | ||||
| } | ||||
| module_exit(kunit_exit); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  | ||||
							
								
								
									
										27
									
								
								lib/kunit/try-catch-impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/kunit/try-catch-impl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
| /*
 | ||||
|  * Internal kunit try catch implementation to be shared with tests. | ||||
|  * | ||||
|  * Copyright (C) 2019, Google LLC. | ||||
|  * Author: Brendan Higgins <brendanhiggins@google.com> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _KUNIT_TRY_CATCH_IMPL_H | ||||
| #define _KUNIT_TRY_CATCH_IMPL_H | ||||
| 
 | ||||
| #include <kunit/try-catch.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct kunit; | ||||
| 
 | ||||
| static inline void kunit_try_catch_init(struct kunit_try_catch *try_catch, | ||||
| 					struct kunit *test, | ||||
| 					kunit_try_catch_func_t try, | ||||
| 					kunit_try_catch_func_t catch) | ||||
| { | ||||
| 	try_catch->test = test; | ||||
| 	try_catch->try = try; | ||||
| 	try_catch->catch = catch; | ||||
| } | ||||
| 
 | ||||
| #endif /* _KUNIT_TRY_CATCH_IMPL_H */ | ||||
| @ -8,17 +8,18 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <kunit/test.h> | ||||
| #include <kunit/try-catch.h> | ||||
| #include <linux/completion.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/kthread.h> | ||||
| #include <linux/sched/sysctl.h> | ||||
| 
 | ||||
| #include "try-catch-impl.h" | ||||
| 
 | ||||
| void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch) | ||||
| { | ||||
| 	try_catch->try_result = -EFAULT; | ||||
| 	complete_and_exit(try_catch->try_completion, -EFAULT); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_try_catch_throw); | ||||
| 
 | ||||
| static int kunit_generic_run_threadfn_adapter(void *data) | ||||
| { | ||||
| @ -31,8 +32,6 @@ static int kunit_generic_run_threadfn_adapter(void *data) | ||||
| 
 | ||||
| static unsigned long kunit_test_timeout(void) | ||||
| { | ||||
| 	unsigned long timeout_msecs; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * TODO(brendanhiggins@google.com): We should probably have some type of | ||||
| 	 * variable timeout here. The only question is what that timeout value | ||||
| @ -49,22 +48,11 @@ static unsigned long kunit_test_timeout(void) | ||||
| 	 * | ||||
| 	 * For more background on this topic, see: | ||||
| 	 * https://mike-bland.com/2011/11/01/small-medium-large.html
 | ||||
| 	 * | ||||
| 	 * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, | ||||
| 	 * the task will be killed and an oops generated. | ||||
| 	 */ | ||||
| 	if (sysctl_hung_task_timeout_secs) { | ||||
| 		/*
 | ||||
| 		 * If sysctl_hung_task is active, just set the timeout to some | ||||
| 		 * value less than that. | ||||
| 		 * | ||||
| 		 * In regards to the above TODO, if we decide on variable | ||||
| 		 * timeouts, this logic will likely need to change. | ||||
| 		 */ | ||||
| 		timeout_msecs = (sysctl_hung_task_timeout_secs - 1) * | ||||
| 				MSEC_PER_SEC; | ||||
| 	} else { | ||||
| 		timeout_msecs = 300 * MSEC_PER_SEC; /* 5 min */ | ||||
| 	} | ||||
| 
 | ||||
| 	return timeout_msecs; | ||||
| 	return 300 * MSEC_PER_SEC; /* 5 min */ | ||||
| } | ||||
| 
 | ||||
| void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) | ||||
| @ -106,13 +94,4 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) | ||||
| 
 | ||||
| 	try_catch->catch(try_catch->context); | ||||
| } | ||||
| 
 | ||||
| void kunit_try_catch_init(struct kunit_try_catch *try_catch, | ||||
| 			  struct kunit *test, | ||||
| 			  kunit_try_catch_func_t try, | ||||
| 			  kunit_try_catch_func_t catch) | ||||
| { | ||||
| 	try_catch->test = test; | ||||
| 	try_catch->try = try; | ||||
| 	try_catch->catch = catch; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kunit_try_catch_run); | ||||
|  | ||||
| @ -743,4 +743,6 @@ static struct kunit_suite list_test_module = { | ||||
| 	.test_cases = list_test_cases, | ||||
| }; | ||||
| 
 | ||||
| kunit_test_suite(list_test_module); | ||||
| kunit_test_suites(&list_test_module); | ||||
| 
 | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  | ||||
| @ -68,3 +68,19 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES | ||||
| 	  Set the default value of the apparmor.debug kernel parameter. | ||||
| 	  When enabled, various debug messages will be logged to | ||||
| 	  the kernel message buffer. | ||||
| 
 | ||||
| config SECURITY_APPARMOR_KUNIT_TEST | ||||
| 	bool "Build KUnit tests for policy_unpack.c" | ||||
| 	depends on KUNIT=y && SECURITY_APPARMOR | ||||
| 	help | ||||
| 	  This builds the AppArmor KUnit tests. | ||||
| 
 | ||||
| 	  KUnit tests run during boot and output the results to the debug log | ||||
| 	  in TAP format (http://testanything.org/). Only useful for kernel devs | ||||
| 	  running KUnit test harness and are not for inclusion into a | ||||
| 	  production build. | ||||
| 
 | ||||
| 	  For more information on KUnit and unit tests in general please refer | ||||
| 	  to the KUnit documentation in Documentation/dev-tools/kunit/. | ||||
| 
 | ||||
| 	  If unsure, say N. | ||||
|  | ||||
| @ -1228,3 +1228,7 @@ fail: | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST | ||||
| #include "policy_unpack_test.c" | ||||
| #endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */ | ||||
|  | ||||
							
								
								
									
										607
									
								
								security/apparmor/policy_unpack_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								security/apparmor/policy_unpack_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,607 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| /*
 | ||||
|  * KUnit tests for AppArmor's policy unpack. | ||||
|  */ | ||||
| 
 | ||||
| #include <kunit/test.h> | ||||
| 
 | ||||
| #include "include/policy.h" | ||||
| #include "include/policy_unpack.h" | ||||
| 
 | ||||
| #define TEST_STRING_NAME "TEST_STRING" | ||||
| #define TEST_STRING_DATA "testing" | ||||
| #define TEST_STRING_BUF_OFFSET \ | ||||
| 	(3 + strlen(TEST_STRING_NAME) + 1) | ||||
| 
 | ||||
| #define TEST_U32_NAME "U32_TEST" | ||||
| #define TEST_U32_DATA ((u32)0x01020304) | ||||
| #define TEST_NAMED_U32_BUF_OFFSET \ | ||||
| 	(TEST_STRING_BUF_OFFSET + 3 + strlen(TEST_STRING_DATA) + 1) | ||||
| #define TEST_U32_BUF_OFFSET \ | ||||
| 	(TEST_NAMED_U32_BUF_OFFSET + 3 + strlen(TEST_U32_NAME) + 1) | ||||
| 
 | ||||
| #define TEST_U16_OFFSET (TEST_U32_BUF_OFFSET + 3) | ||||
| #define TEST_U16_DATA ((u16)(TEST_U32_DATA >> 16)) | ||||
| 
 | ||||
| #define TEST_U64_NAME "U64_TEST" | ||||
| #define TEST_U64_DATA ((u64)0x0102030405060708) | ||||
| #define TEST_NAMED_U64_BUF_OFFSET (TEST_U32_BUF_OFFSET + sizeof(u32) + 1) | ||||
| #define TEST_U64_BUF_OFFSET \ | ||||
| 	(TEST_NAMED_U64_BUF_OFFSET + 3 + strlen(TEST_U64_NAME) + 1) | ||||
| 
 | ||||
| #define TEST_BLOB_NAME "BLOB_TEST" | ||||
| #define TEST_BLOB_DATA "\xde\xad\x00\xbe\xef" | ||||
| #define TEST_BLOB_DATA_SIZE (ARRAY_SIZE(TEST_BLOB_DATA)) | ||||
| #define TEST_NAMED_BLOB_BUF_OFFSET (TEST_U64_BUF_OFFSET + sizeof(u64) + 1) | ||||
| #define TEST_BLOB_BUF_OFFSET \ | ||||
| 	(TEST_NAMED_BLOB_BUF_OFFSET + 3 + strlen(TEST_BLOB_NAME) + 1) | ||||
| 
 | ||||
| #define TEST_ARRAY_NAME "ARRAY_TEST" | ||||
| #define TEST_ARRAY_SIZE 16 | ||||
| #define TEST_NAMED_ARRAY_BUF_OFFSET \ | ||||
| 	(TEST_BLOB_BUF_OFFSET + 5 + TEST_BLOB_DATA_SIZE) | ||||
| #define TEST_ARRAY_BUF_OFFSET \ | ||||
| 	(TEST_NAMED_ARRAY_BUF_OFFSET + 3 + strlen(TEST_ARRAY_NAME) + 1) | ||||
| 
 | ||||
| struct policy_unpack_fixture { | ||||
| 	struct aa_ext *e; | ||||
| 	size_t e_size; | ||||
| }; | ||||
| 
 | ||||
| struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, | ||||
| 				   struct kunit *test, size_t buf_size) | ||||
| { | ||||
| 	char *buf; | ||||
| 	struct aa_ext *e; | ||||
| 
 | ||||
| 	buf = kunit_kzalloc(test, buf_size, GFP_USER); | ||||
| 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, buf); | ||||
| 
 | ||||
| 	e = kunit_kmalloc(test, sizeof(*e), GFP_USER); | ||||
| 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, e); | ||||
| 
 | ||||
| 	e->start = buf; | ||||
| 	e->end = e->start + buf_size; | ||||
| 	e->pos = e->start; | ||||
| 
 | ||||
| 	*buf = AA_NAME; | ||||
| 	*(buf + 1) = strlen(TEST_STRING_NAME) + 1; | ||||
| 	strcpy(buf + 3, TEST_STRING_NAME); | ||||
| 
 | ||||
| 	buf = e->start + TEST_STRING_BUF_OFFSET; | ||||
| 	*buf = AA_STRING; | ||||
| 	*(buf + 1) = strlen(TEST_STRING_DATA) + 1; | ||||
| 	strcpy(buf + 3, TEST_STRING_DATA); | ||||
| 
 | ||||
| 	buf = e->start + TEST_NAMED_U32_BUF_OFFSET; | ||||
| 	*buf = AA_NAME; | ||||
| 	*(buf + 1) = strlen(TEST_U32_NAME) + 1; | ||||
| 	strcpy(buf + 3, TEST_U32_NAME); | ||||
| 	*(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32; | ||||
| 	*((u32 *)(buf + 3 + strlen(TEST_U32_NAME) + 2)) = TEST_U32_DATA; | ||||
| 
 | ||||
| 	buf = e->start + TEST_NAMED_U64_BUF_OFFSET; | ||||
| 	*buf = AA_NAME; | ||||
| 	*(buf + 1) = strlen(TEST_U64_NAME) + 1; | ||||
| 	strcpy(buf + 3, TEST_U64_NAME); | ||||
| 	*(buf + 3 + strlen(TEST_U64_NAME) + 1) = AA_U64; | ||||
| 	*((u64 *)(buf + 3 + strlen(TEST_U64_NAME) + 2)) = TEST_U64_DATA; | ||||
| 
 | ||||
| 	buf = e->start + TEST_NAMED_BLOB_BUF_OFFSET; | ||||
| 	*buf = AA_NAME; | ||||
| 	*(buf + 1) = strlen(TEST_BLOB_NAME) + 1; | ||||
| 	strcpy(buf + 3, TEST_BLOB_NAME); | ||||
| 	*(buf + 3 + strlen(TEST_BLOB_NAME) + 1) = AA_BLOB; | ||||
| 	*(buf + 3 + strlen(TEST_BLOB_NAME) + 2) = TEST_BLOB_DATA_SIZE; | ||||
| 	memcpy(buf + 3 + strlen(TEST_BLOB_NAME) + 6, | ||||
| 		TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE); | ||||
| 
 | ||||
| 	buf = e->start + TEST_NAMED_ARRAY_BUF_OFFSET; | ||||
| 	*buf = AA_NAME; | ||||
| 	*(buf + 1) = strlen(TEST_ARRAY_NAME) + 1; | ||||
| 	strcpy(buf + 3, TEST_ARRAY_NAME); | ||||
| 	*(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY; | ||||
| 	*((u16 *)(buf + 3 + strlen(TEST_ARRAY_NAME) + 2)) = TEST_ARRAY_SIZE; | ||||
| 
 | ||||
| 	return e; | ||||
| } | ||||
| 
 | ||||
| static int policy_unpack_test_init(struct kunit *test) | ||||
| { | ||||
| 	size_t e_size = TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1; | ||||
| 	struct policy_unpack_fixture *puf; | ||||
| 
 | ||||
| 	puf = kunit_kmalloc(test, sizeof(*puf), GFP_USER); | ||||
| 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, puf); | ||||
| 
 | ||||
| 	puf->e_size = e_size; | ||||
| 	puf->e = build_aa_ext_struct(puf, test, e_size); | ||||
| 
 | ||||
| 	test->priv = puf; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_inbounds_when_inbounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, inbounds(puf->e, 0)); | ||||
| 	KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size / 2)); | ||||
| 	KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size)); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_inbounds_when_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, inbounds(puf->e, puf->e_size + 1)); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	u16 array_size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_ARRAY_BUF_OFFSET; | ||||
| 
 | ||||
| 	array_size = unpack_array(puf->e, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 		puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_array_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_ARRAY_NAME; | ||||
| 	u16 array_size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET; | ||||
| 
 | ||||
| 	array_size = unpack_array(puf->e, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 		puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_ARRAY_NAME; | ||||
| 	u16 array_size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET; | ||||
| 	puf->e->end = puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16); | ||||
| 
 | ||||
| 	array_size = unpack_array(puf->e, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, array_size, (u16)0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 		puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_blob_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *blob = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_BLOB_BUF_OFFSET; | ||||
| 	size = unpack_blob(puf->e, &blob, NULL); | ||||
| 
 | ||||
| 	KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE); | ||||
| 	KUNIT_EXPECT_TRUE(test, | ||||
| 		memcmp(blob, TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE) == 0); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_blob_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *blob = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET; | ||||
| 	size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME); | ||||
| 
 | ||||
| 	KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE); | ||||
| 	KUNIT_EXPECT_TRUE(test, | ||||
| 		memcmp(blob, TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE) == 0); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_blob_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *blob = NULL; | ||||
| 	void *start; | ||||
| 	int size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET; | ||||
| 	start = puf->e->pos; | ||||
| 	puf->e->end = puf->e->start + TEST_BLOB_BUF_OFFSET | ||||
| 		+ TEST_BLOB_DATA_SIZE - 1; | ||||
| 
 | ||||
| 	size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, 0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_str_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char *string = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_STRING_BUF_OFFSET; | ||||
| 	size = unpack_str(puf->e, &string, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1); | ||||
| 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_str_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char *string = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	size = unpack_str(puf->e, &string, TEST_STRING_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1); | ||||
| 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_str_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char *string = NULL; | ||||
| 	void *start = puf->e->pos; | ||||
| 	int size; | ||||
| 
 | ||||
| 	puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET | ||||
| 		+ strlen(TEST_STRING_DATA) - 1; | ||||
| 
 | ||||
| 	size = unpack_str(puf->e, &string, TEST_STRING_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, 0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *string = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_STRING_BUF_OFFSET; | ||||
| 	size = unpack_strdup(puf->e, &string, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1); | ||||
| 	KUNIT_EXPECT_FALSE(test, | ||||
| 			   ((uintptr_t)puf->e->start <= (uintptr_t)string) | ||||
| 			   && ((uintptr_t)string <= (uintptr_t)puf->e->end)); | ||||
| 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *string = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	size = unpack_strdup(puf->e, &string, TEST_STRING_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1); | ||||
| 	KUNIT_EXPECT_FALSE(test, | ||||
| 			   ((uintptr_t)puf->e->start <= (uintptr_t)string) | ||||
| 			   && ((uintptr_t)string <= (uintptr_t)puf->e->end)); | ||||
| 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	void *start = puf->e->pos; | ||||
| 	char *string = NULL; | ||||
| 	int size; | ||||
| 
 | ||||
| 	puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET | ||||
| 		+ strlen(TEST_STRING_DATA) - 1; | ||||
| 
 | ||||
| 	size = unpack_strdup(puf->e, &string, TEST_STRING_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, 0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, string, (char *)NULL); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_nameX(puf->e, AA_U32, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			    puf->e->start + TEST_U32_BUF_OFFSET + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_nameX_with_wrong_code(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_nameX(puf->e, AA_BLOB, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			    puf->e->start + TEST_U32_BUF_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_nameX_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_U32_NAME; | ||||
| 	bool success; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_nameX(puf->e, AA_U32, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			    puf->e->start + TEST_U32_BUF_OFFSET + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_nameX_with_wrong_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	static const char name[] = "12345678"; | ||||
| 	bool success; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_nameX(puf->e, AA_U32, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			    puf->e->start + TEST_NAMED_U32_BUF_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *chunk = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U16_OFFSET; | ||||
| 	/*
 | ||||
| 	 * WARNING: For unit testing purposes, we're pushing puf->e->end past | ||||
| 	 * the end of the allocated memory. Doing anything other than comparing | ||||
| 	 * memory addresses is dangerous. | ||||
| 	 */ | ||||
| 	puf->e->end += TEST_U16_DATA; | ||||
| 
 | ||||
| 	size = unpack_u16_chunk(puf->e, &chunk); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, (void *)chunk, | ||||
| 			    puf->e->start + TEST_U16_OFFSET + 2); | ||||
| 	KUNIT_EXPECT_EQ(test, size, (size_t)TEST_U16_DATA); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (void *)(chunk + TEST_U16_DATA)); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1( | ||||
| 		struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *chunk = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos = puf->e->end - 1; | ||||
| 
 | ||||
| 	size = unpack_u16_chunk(puf->e, &chunk); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, (size_t)0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, chunk, (char *)NULL); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->end - 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2( | ||||
| 		struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	char *chunk = NULL; | ||||
| 	size_t size; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U16_OFFSET; | ||||
| 	/*
 | ||||
| 	 * WARNING: For unit testing purposes, we're pushing puf->e->end past | ||||
| 	 * the end of the allocated memory. Doing anything other than comparing | ||||
| 	 * memory addresses is dangerous. | ||||
| 	 */ | ||||
| 	puf->e->end = puf->e->pos + TEST_U16_DATA - 1; | ||||
| 
 | ||||
| 	size = unpack_u16_chunk(puf->e, &chunk); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_EQ(test, size, (size_t)0); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, chunk, (char *)NULL); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_U16_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success; | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_u32(puf->e, &data, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u32_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_U32_NAME; | ||||
| 	bool success; | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_u32(puf->e, &data, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_U32_NAME; | ||||
| 	bool success; | ||||
| 	u32 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; | ||||
| 	puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32); | ||||
| 
 | ||||
| 	success = unpack_u32(puf->e, &data, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_NAMED_U32_BUF_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success; | ||||
| 	u64 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_U64_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_u64(puf->e, &data, NULL); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u64_with_name(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_U64_NAME; | ||||
| 	bool success; | ||||
| 	u64 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; | ||||
| 
 | ||||
| 	success = unpack_u64(puf->e, &data, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64) + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	const char name[] = TEST_U64_NAME; | ||||
| 	bool success; | ||||
| 	u64 data; | ||||
| 
 | ||||
| 	puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; | ||||
| 	puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64); | ||||
| 
 | ||||
| 	success = unpack_u64(puf->e, &data, name); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, | ||||
| 			puf->e->start + TEST_NAMED_U64_BUF_OFFSET); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_X_code_match(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success = unpack_X(puf->e, AA_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_TRUE(test, success); | ||||
| 	KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start + 1); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_X_code_mismatch(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success = unpack_X(puf->e, AA_STRING); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| 	KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start); | ||||
| } | ||||
| 
 | ||||
| static void policy_unpack_test_unpack_X_out_of_bounds(struct kunit *test) | ||||
| { | ||||
| 	struct policy_unpack_fixture *puf = test->priv; | ||||
| 	bool success; | ||||
| 
 | ||||
| 	puf->e->pos = puf->e->end; | ||||
| 	success = unpack_X(puf->e, AA_NAME); | ||||
| 
 | ||||
| 	KUNIT_EXPECT_FALSE(test, success); | ||||
| } | ||||
| 
 | ||||
| static struct kunit_case apparmor_policy_unpack_test_cases[] = { | ||||
| 	KUNIT_CASE(policy_unpack_test_inbounds_when_inbounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_inbounds_when_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_array_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_array_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_array_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_blob_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_blob_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_blob_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_nameX_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_nameX_with_wrong_code), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_nameX_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_nameX_with_wrong_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_str_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_str_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_str_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_strdup_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_strdup_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_strdup_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_basic), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_out_of_bounds_1), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_out_of_bounds_2), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u32_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u32_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u32_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u64_with_null_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u64_with_name), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_u64_out_of_bounds), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_X_code_match), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_X_code_mismatch), | ||||
| 	KUNIT_CASE(policy_unpack_test_unpack_X_out_of_bounds), | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| static struct kunit_suite apparmor_policy_unpack_test_module = { | ||||
| 	.name = "apparmor_policy_unpack", | ||||
| 	.init = policy_unpack_test_init, | ||||
| 	.test_cases = apparmor_policy_unpack_test_cases, | ||||
| }; | ||||
| 
 | ||||
| kunit_test_suite(apparmor_policy_unpack_test_module); | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user