lib/test_kasan.c: add roundtrip tests

In several places we need to be able to operate on pointers which have
gone via a roundtrip:

	virt -> {phys,page} -> virt

With KASAN_SW_TAGS, we can't preserve the tag for SLUB objects, and the
{phys,page} -> virt conversion will use KASAN_TAG_KERNEL.

This patch adds tests to ensure that this works as expected, without
false positives which have recently been spotted [1,2] in testing.

[1] https://lore.kernel.org/linux-arm-kernel/20190819114420.2535-1-walter-zh.wu@mediatek.com/
[2] https://lore.kernel.org/linux-arm-kernel/20190819132347.GB9927@lakrids.cambridge.arm.com/

[akpm@linux-foundation.org: coding-style fixes]
Link: http://lkml.kernel.org/r/20190821153927.28630-1-mark.rutland@arm.com
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Andrey Konovalov <andreyknvl@google.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Mark Rutland 2019-09-23 15:34:16 -07:00 committed by Linus Torvalds
parent ae8f06b31a
commit b92a953cb7
1 changed files with 41 additions and 0 deletions

View File

@ -18,6 +18,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/page.h>
/* /*
* Note: test functions are marked noinline so that their names appear in * Note: test functions are marked noinline so that their names appear in
@ -337,6 +340,42 @@ static noinline void __init kmalloc_uaf2(void)
kfree(ptr2); kfree(ptr2);
} }
static noinline void __init kfree_via_page(void)
{
char *ptr;
size_t size = 8;
struct page *page;
unsigned long offset;
pr_info("invalid-free false positive (via page)\n");
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr) {
pr_err("Allocation failed\n");
return;
}
page = virt_to_page(ptr);
offset = offset_in_page(ptr);
kfree(page_address(page) + offset);
}
static noinline void __init kfree_via_phys(void)
{
char *ptr;
size_t size = 8;
phys_addr_t phys;
pr_info("invalid-free false positive (via phys)\n");
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr) {
pr_err("Allocation failed\n");
return;
}
phys = virt_to_phys(ptr);
kfree(phys_to_virt(phys));
}
static noinline void __init kmem_cache_oob(void) static noinline void __init kmem_cache_oob(void)
{ {
char *p; char *p;
@ -737,6 +776,8 @@ static int __init kmalloc_tests_init(void)
kmalloc_uaf(); kmalloc_uaf();
kmalloc_uaf_memset(); kmalloc_uaf_memset();
kmalloc_uaf2(); kmalloc_uaf2();
kfree_via_page();
kfree_via_phys();
kmem_cache_oob(); kmem_cache_oob();
memcg_accounted_kmem_cache(); memcg_accounted_kmem_cache();
kasan_stack_oob(); kasan_stack_oob();