| // SPDX-License-Identifier: GPL-2.0 | 
 | #include <kunit/test.h> | 
 | #include <linux/mm.h> | 
 | #include <linux/slab.h> | 
 | #include <linux/module.h> | 
 | #include <linux/kernel.h> | 
 | #include "../mm/slab.h" | 
 |  | 
 | static struct kunit_resource resource; | 
 | static int slab_errors; | 
 |  | 
 | static void test_clobber_zone(struct kunit *test) | 
 | { | 
 | 	struct kmem_cache *s = kmem_cache_create("TestSlub_RZ_alloc", 64, 0, | 
 | 				SLAB_RED_ZONE, NULL); | 
 | 	u8 *p = kmem_cache_alloc(s, GFP_KERNEL); | 
 |  | 
 | 	kasan_disable_current(); | 
 | 	p[64] = 0x12; | 
 |  | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 2, slab_errors); | 
 |  | 
 | 	kasan_enable_current(); | 
 | 	kmem_cache_free(s, p); | 
 | 	kmem_cache_destroy(s); | 
 | } | 
 |  | 
 | #ifndef CONFIG_KASAN | 
 | static void test_next_pointer(struct kunit *test) | 
 | { | 
 | 	struct kmem_cache *s = kmem_cache_create("TestSlub_next_ptr_free", 64, 0, | 
 | 				SLAB_POISON, NULL); | 
 | 	u8 *p = kmem_cache_alloc(s, GFP_KERNEL); | 
 | 	unsigned long tmp; | 
 | 	unsigned long *ptr_addr; | 
 |  | 
 | 	kmem_cache_free(s, p); | 
 |  | 
 | 	ptr_addr = (unsigned long *)(p + s->offset); | 
 | 	tmp = *ptr_addr; | 
 | 	p[s->offset] = 0x12; | 
 |  | 
 | 	/* | 
 | 	 * Expecting three errors. | 
 | 	 * One for the corrupted freechain and the other one for the wrong | 
 | 	 * count of objects in use. The third error is fixing broken cache. | 
 | 	 */ | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 3, slab_errors); | 
 |  | 
 | 	/* | 
 | 	 * Try to repair corrupted freepointer. | 
 | 	 * Still expecting two errors. The first for the wrong count | 
 | 	 * of objects in use. | 
 | 	 * The second error is for fixing broken cache. | 
 | 	 */ | 
 | 	*ptr_addr = tmp; | 
 | 	slab_errors = 0; | 
 |  | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 2, slab_errors); | 
 |  | 
 | 	/* | 
 | 	 * Previous validation repaired the count of objects in use. | 
 | 	 * Now expecting no error. | 
 | 	 */ | 
 | 	slab_errors = 0; | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 0, slab_errors); | 
 |  | 
 | 	kmem_cache_destroy(s); | 
 | } | 
 |  | 
 | static void test_first_word(struct kunit *test) | 
 | { | 
 | 	struct kmem_cache *s = kmem_cache_create("TestSlub_1th_word_free", 64, 0, | 
 | 				SLAB_POISON, NULL); | 
 | 	u8 *p = kmem_cache_alloc(s, GFP_KERNEL); | 
 |  | 
 | 	kmem_cache_free(s, p); | 
 | 	*p = 0x78; | 
 |  | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 2, slab_errors); | 
 |  | 
 | 	kmem_cache_destroy(s); | 
 | } | 
 |  | 
 | static void test_clobber_50th_byte(struct kunit *test) | 
 | { | 
 | 	struct kmem_cache *s = kmem_cache_create("TestSlub_50th_word_free", 64, 0, | 
 | 				SLAB_POISON, NULL); | 
 | 	u8 *p = kmem_cache_alloc(s, GFP_KERNEL); | 
 |  | 
 | 	kmem_cache_free(s, p); | 
 | 	p[50] = 0x9a; | 
 |  | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 2, slab_errors); | 
 |  | 
 | 	kmem_cache_destroy(s); | 
 | } | 
 | #endif | 
 |  | 
 | static void test_clobber_redzone_free(struct kunit *test) | 
 | { | 
 | 	struct kmem_cache *s = kmem_cache_create("TestSlub_RZ_free", 64, 0, | 
 | 				SLAB_RED_ZONE, NULL); | 
 | 	u8 *p = kmem_cache_alloc(s, GFP_KERNEL); | 
 |  | 
 | 	kasan_disable_current(); | 
 | 	kmem_cache_free(s, p); | 
 | 	p[64] = 0xab; | 
 |  | 
 | 	validate_slab_cache(s); | 
 | 	KUNIT_EXPECT_EQ(test, 2, slab_errors); | 
 |  | 
 | 	kasan_enable_current(); | 
 | 	kmem_cache_destroy(s); | 
 | } | 
 |  | 
 | static int test_init(struct kunit *test) | 
 | { | 
 | 	slab_errors = 0; | 
 |  | 
 | 	kunit_add_named_resource(test, NULL, NULL, &resource, | 
 | 					"slab_errors", &slab_errors); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static struct kunit_case test_cases[] = { | 
 | 	KUNIT_CASE(test_clobber_zone), | 
 |  | 
 | #ifndef CONFIG_KASAN | 
 | 	KUNIT_CASE(test_next_pointer), | 
 | 	KUNIT_CASE(test_first_word), | 
 | 	KUNIT_CASE(test_clobber_50th_byte), | 
 | #endif | 
 |  | 
 | 	KUNIT_CASE(test_clobber_redzone_free), | 
 | 	{} | 
 | }; | 
 |  | 
 | static struct kunit_suite test_suite = { | 
 | 	.name = "slub_test", | 
 | 	.init = test_init, | 
 | 	.test_cases = test_cases, | 
 | }; | 
 | kunit_test_suite(test_suite); | 
 |  | 
 | MODULE_LICENSE("GPL"); |