11f9f78b1SOliver Glitta // SPDX-License-Identifier: GPL-2.0
21f9f78b1SOliver Glitta #include <kunit/test.h>
3909c6475SDavid Gow #include <kunit/test-bug.h>
41f9f78b1SOliver Glitta #include <linux/mm.h>
51f9f78b1SOliver Glitta #include <linux/slab.h>
61f9f78b1SOliver Glitta #include <linux/module.h>
71f9f78b1SOliver Glitta #include <linux/kernel.h>
81f9f78b1SOliver Glitta #include "../mm/slab.h"
91f9f78b1SOliver Glitta
101f9f78b1SOliver Glitta static struct kunit_resource resource;
111f9f78b1SOliver Glitta static int slab_errors;
121f9f78b1SOliver Glitta
134d9dd4b0SFeng Tang /*
144d9dd4b0SFeng Tang * Wrapper function for kmem_cache_create(), which reduces 2 parameters:
154d9dd4b0SFeng Tang * 'align' and 'ctor', and sets SLAB_SKIP_KFENCE flag to avoid getting an
164d9dd4b0SFeng Tang * object from kfence pool, where the operation could be caught by both
174d9dd4b0SFeng Tang * our test and kfence sanity check.
184d9dd4b0SFeng Tang */
test_kmem_cache_create(const char * name,unsigned int size,slab_flags_t flags)194d9dd4b0SFeng Tang static struct kmem_cache *test_kmem_cache_create(const char *name,
204d9dd4b0SFeng Tang unsigned int size, slab_flags_t flags)
214d9dd4b0SFeng Tang {
224d9dd4b0SFeng Tang struct kmem_cache *s = kmem_cache_create(name, size, 0,
234d9dd4b0SFeng Tang (flags | SLAB_NO_USER_FLAGS), NULL);
244d9dd4b0SFeng Tang s->flags |= SLAB_SKIP_KFENCE;
254d9dd4b0SFeng Tang return s;
264d9dd4b0SFeng Tang }
274d9dd4b0SFeng Tang
test_clobber_zone(struct kunit * test)281f9f78b1SOliver Glitta static void test_clobber_zone(struct kunit *test)
291f9f78b1SOliver Glitta {
304d9dd4b0SFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_alloc", 64,
314d9dd4b0SFeng Tang SLAB_RED_ZONE);
321f9f78b1SOliver Glitta u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
331f9f78b1SOliver Glitta
341f9f78b1SOliver Glitta kasan_disable_current();
351f9f78b1SOliver Glitta p[64] = 0x12;
361f9f78b1SOliver Glitta
371f9f78b1SOliver Glitta validate_slab_cache(s);
381f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 2, slab_errors);
391f9f78b1SOliver Glitta
401f9f78b1SOliver Glitta kasan_enable_current();
411f9f78b1SOliver Glitta kmem_cache_free(s, p);
421f9f78b1SOliver Glitta kmem_cache_destroy(s);
431f9f78b1SOliver Glitta }
441f9f78b1SOliver Glitta
451f9f78b1SOliver Glitta #ifndef CONFIG_KASAN
test_next_pointer(struct kunit * test)461f9f78b1SOliver Glitta static void test_next_pointer(struct kunit *test)
471f9f78b1SOliver Glitta {
484d9dd4b0SFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_next_ptr_free",
494d9dd4b0SFeng Tang 64, SLAB_POISON);
501f9f78b1SOliver Glitta u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
511f9f78b1SOliver Glitta unsigned long tmp;
521f9f78b1SOliver Glitta unsigned long *ptr_addr;
531f9f78b1SOliver Glitta
541f9f78b1SOliver Glitta kmem_cache_free(s, p);
551f9f78b1SOliver Glitta
561f9f78b1SOliver Glitta ptr_addr = (unsigned long *)(p + s->offset);
571f9f78b1SOliver Glitta tmp = *ptr_addr;
58*d8c42a6eSGuenter Roeck p[s->offset] = ~p[s->offset];
591f9f78b1SOliver Glitta
601f9f78b1SOliver Glitta /*
611f9f78b1SOliver Glitta * Expecting three errors.
621f9f78b1SOliver Glitta * One for the corrupted freechain and the other one for the wrong
631f9f78b1SOliver Glitta * count of objects in use. The third error is fixing broken cache.
641f9f78b1SOliver Glitta */
651f9f78b1SOliver Glitta validate_slab_cache(s);
661f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 3, slab_errors);
671f9f78b1SOliver Glitta
681f9f78b1SOliver Glitta /*
691f9f78b1SOliver Glitta * Try to repair corrupted freepointer.
701f9f78b1SOliver Glitta * Still expecting two errors. The first for the wrong count
711f9f78b1SOliver Glitta * of objects in use.
721f9f78b1SOliver Glitta * The second error is for fixing broken cache.
731f9f78b1SOliver Glitta */
741f9f78b1SOliver Glitta *ptr_addr = tmp;
751f9f78b1SOliver Glitta slab_errors = 0;
761f9f78b1SOliver Glitta
771f9f78b1SOliver Glitta validate_slab_cache(s);
781f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 2, slab_errors);
791f9f78b1SOliver Glitta
801f9f78b1SOliver Glitta /*
811f9f78b1SOliver Glitta * Previous validation repaired the count of objects in use.
821f9f78b1SOliver Glitta * Now expecting no error.
831f9f78b1SOliver Glitta */
841f9f78b1SOliver Glitta slab_errors = 0;
851f9f78b1SOliver Glitta validate_slab_cache(s);
861f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 0, slab_errors);
871f9f78b1SOliver Glitta
881f9f78b1SOliver Glitta kmem_cache_destroy(s);
891f9f78b1SOliver Glitta }
901f9f78b1SOliver Glitta
test_first_word(struct kunit * test)911f9f78b1SOliver Glitta static void test_first_word(struct kunit *test)
921f9f78b1SOliver Glitta {
934d9dd4b0SFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_1th_word_free",
944d9dd4b0SFeng Tang 64, SLAB_POISON);
951f9f78b1SOliver Glitta u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
961f9f78b1SOliver Glitta
971f9f78b1SOliver Glitta kmem_cache_free(s, p);
981f9f78b1SOliver Glitta *p = 0x78;
991f9f78b1SOliver Glitta
1001f9f78b1SOliver Glitta validate_slab_cache(s);
1011f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 2, slab_errors);
1021f9f78b1SOliver Glitta
1031f9f78b1SOliver Glitta kmem_cache_destroy(s);
1041f9f78b1SOliver Glitta }
1051f9f78b1SOliver Glitta
test_clobber_50th_byte(struct kunit * test)1061f9f78b1SOliver Glitta static void test_clobber_50th_byte(struct kunit *test)
1071f9f78b1SOliver Glitta {
1084d9dd4b0SFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_50th_word_free",
1094d9dd4b0SFeng Tang 64, SLAB_POISON);
1101f9f78b1SOliver Glitta u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
1111f9f78b1SOliver Glitta
1121f9f78b1SOliver Glitta kmem_cache_free(s, p);
1131f9f78b1SOliver Glitta p[50] = 0x9a;
1141f9f78b1SOliver Glitta
1151f9f78b1SOliver Glitta validate_slab_cache(s);
1161f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 2, slab_errors);
1171f9f78b1SOliver Glitta
1181f9f78b1SOliver Glitta kmem_cache_destroy(s);
1191f9f78b1SOliver Glitta }
1201f9f78b1SOliver Glitta #endif
1211f9f78b1SOliver Glitta
test_clobber_redzone_free(struct kunit * test)1221f9f78b1SOliver Glitta static void test_clobber_redzone_free(struct kunit *test)
1231f9f78b1SOliver Glitta {
1244d9dd4b0SFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_free", 64,
1254d9dd4b0SFeng Tang SLAB_RED_ZONE);
1261f9f78b1SOliver Glitta u8 *p = kmem_cache_alloc(s, GFP_KERNEL);
1271f9f78b1SOliver Glitta
1281f9f78b1SOliver Glitta kasan_disable_current();
1291f9f78b1SOliver Glitta kmem_cache_free(s, p);
1301f9f78b1SOliver Glitta p[64] = 0xab;
1311f9f78b1SOliver Glitta
1321f9f78b1SOliver Glitta validate_slab_cache(s);
1331f9f78b1SOliver Glitta KUNIT_EXPECT_EQ(test, 2, slab_errors);
1341f9f78b1SOliver Glitta
1351f9f78b1SOliver Glitta kasan_enable_current();
1361f9f78b1SOliver Glitta kmem_cache_destroy(s);
1371f9f78b1SOliver Glitta }
1381f9f78b1SOliver Glitta
test_kmalloc_redzone_access(struct kunit * test)1396cd6d33cSFeng Tang static void test_kmalloc_redzone_access(struct kunit *test)
1406cd6d33cSFeng Tang {
1416cd6d33cSFeng Tang struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_kmalloc", 32,
1426cd6d33cSFeng Tang SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE);
1436cd6d33cSFeng Tang u8 *p = kmalloc_trace(s, GFP_KERNEL, 18);
1446cd6d33cSFeng Tang
1456cd6d33cSFeng Tang kasan_disable_current();
1466cd6d33cSFeng Tang
1476cd6d33cSFeng Tang /* Suppress the -Warray-bounds warning */
1486cd6d33cSFeng Tang OPTIMIZER_HIDE_VAR(p);
1496cd6d33cSFeng Tang p[18] = 0xab;
1506cd6d33cSFeng Tang p[19] = 0xab;
1516cd6d33cSFeng Tang
1526cd6d33cSFeng Tang validate_slab_cache(s);
1536cd6d33cSFeng Tang KUNIT_EXPECT_EQ(test, 2, slab_errors);
1546cd6d33cSFeng Tang
1556cd6d33cSFeng Tang kasan_enable_current();
1566cd6d33cSFeng Tang kmem_cache_free(s, p);
1576cd6d33cSFeng Tang kmem_cache_destroy(s);
1586cd6d33cSFeng Tang }
1596cd6d33cSFeng Tang
test_init(struct kunit * test)1601f9f78b1SOliver Glitta static int test_init(struct kunit *test)
1611f9f78b1SOliver Glitta {
1621f9f78b1SOliver Glitta slab_errors = 0;
1631f9f78b1SOliver Glitta
1641f9f78b1SOliver Glitta kunit_add_named_resource(test, NULL, NULL, &resource,
1651f9f78b1SOliver Glitta "slab_errors", &slab_errors);
1661f9f78b1SOliver Glitta return 0;
1671f9f78b1SOliver Glitta }
1681f9f78b1SOliver Glitta
1691f9f78b1SOliver Glitta static struct kunit_case test_cases[] = {
1701f9f78b1SOliver Glitta KUNIT_CASE(test_clobber_zone),
1711f9f78b1SOliver Glitta
1721f9f78b1SOliver Glitta #ifndef CONFIG_KASAN
1731f9f78b1SOliver Glitta KUNIT_CASE(test_next_pointer),
1741f9f78b1SOliver Glitta KUNIT_CASE(test_first_word),
1751f9f78b1SOliver Glitta KUNIT_CASE(test_clobber_50th_byte),
1761f9f78b1SOliver Glitta #endif
1771f9f78b1SOliver Glitta
1781f9f78b1SOliver Glitta KUNIT_CASE(test_clobber_redzone_free),
1796cd6d33cSFeng Tang KUNIT_CASE(test_kmalloc_redzone_access),
1801f9f78b1SOliver Glitta {}
1811f9f78b1SOliver Glitta };
1821f9f78b1SOliver Glitta
1831f9f78b1SOliver Glitta static struct kunit_suite test_suite = {
1841f9f78b1SOliver Glitta .name = "slub_test",
1851f9f78b1SOliver Glitta .init = test_init,
1861f9f78b1SOliver Glitta .test_cases = test_cases,
1871f9f78b1SOliver Glitta };
1881f9f78b1SOliver Glitta kunit_test_suite(test_suite);
1891f9f78b1SOliver Glitta
1901f9f78b1SOliver Glitta MODULE_LICENSE("GPL");
191