forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mm/slub, kunit: add a KUnit test for SLUB debugging functionality
SLUB has resiliency_test() function which is hidden behind #ifdef SLUB_RESILIENCY_TEST that is not part of Kconfig, so nobody runs it. KUnit should be a proper replacement for it. Try changing byte in redzone after allocation and changing pointer to next free node, first byte, 50th byte and redzone byte. Check if validation finds errors. There are several differences from the original resiliency test: Tests create own caches with known state instead of corrupting shared kmalloc caches. The corruption of freepointer uses correct offset, the original resiliency test got broken with freepointer changes. Scratch changing random byte test, because it does not have meaning in this form where we need deterministic results. Add new option CONFIG_SLUB_KUNIT_TEST in Kconfig. Tests next_pointer, first_word and clobber_50th_byte do not run with KASAN option on. Because the test deliberately modifies non-allocated objects. Use kunit_resource to count errors in cache and silence bug reports. Count error whenever slab_bug() or slab_fix() is called or when the count of pages is wrong. [[email protected]: remove unused function test_exit(), from SLUB KUnit test] Link: https://lkml.kernel.org/r/[email protected] [[email protected]: export kasan_enable/disable_current to modules] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Oliver Glitta <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Acked-by: Daniel Latypov <[email protected]> Acked-by: Marco Elver <[email protected]> Cc: Brendan Higgins <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: David Rientjes <[email protected]> Cc: Joonsoo Kim <[email protected]> Cc: Pekka Enberg <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
6 changed files
with
212 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// 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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters