2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-02-14 01:39:53 +03:00
/*
*
* Copyright ( c ) 2014 Samsung Electronics Co . , Ltd .
* Author : Andrey Ryabinin < a . ryabinin @ samsung . com >
*/
# define pr_fmt(fmt) "kasan test: %s " fmt, __func__
2019-07-12 06:53:52 +03:00
# include <linux/bitops.h>
2017-02-25 02:00:08 +03:00
# include <linux/delay.h>
2019-07-12 06:53:52 +03:00
# include <linux/kasan.h>
2015-02-14 01:39:53 +03:00
# include <linux/kernel.h>
2016-05-21 02:59:34 +03:00
# include <linux/mm.h>
2019-07-12 06:53:52 +03:00
# include <linux/mman.h>
# include <linux/module.h>
2015-02-14 01:39:53 +03:00
# include <linux/printk.h>
# include <linux/slab.h>
# include <linux/string.h>
2016-05-21 02:59:34 +03:00
# include <linux/uaccess.h>
2019-09-24 01:34:16 +03:00
# include <linux/io.h>
2019-12-01 04:54:53 +03:00
# include <linux/vmalloc.h>
2019-09-24 01:34:16 +03:00
# include <asm/page.h>
2015-02-14 01:39:53 +03:00
2016-12-01 02:54:16 +03:00
/*
* Note : test functions are marked noinline so that their names appear in
* reports .
*/
2015-02-14 01:39:53 +03:00
static noinline void __init kmalloc_oob_right ( void )
{
char * ptr ;
size_t size = 123 ;
pr_info ( " out-of-bounds to right \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
ptr [ size ] = ' x ' ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_oob_left ( void )
{
char * ptr ;
size_t size = 15 ;
pr_info ( " out-of-bounds to left \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
* ptr = * ( ptr - 1 ) ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_node_oob_right ( void )
{
char * ptr ;
size_t size = 4096 ;
pr_info ( " kmalloc_node(): out-of-bounds to right \n " ) ;
ptr = kmalloc_node ( size , GFP_KERNEL , 0 ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
ptr [ size ] = 0 ;
kfree ( ptr ) ;
}
2016-03-26 00:21:56 +03:00
# ifdef CONFIG_SLUB
static noinline void __init kmalloc_pagealloc_oob_right ( void )
2015-02-14 01:39:53 +03:00
{
char * ptr ;
size_t size = KMALLOC_MAX_CACHE_SIZE + 10 ;
2016-03-26 00:21:56 +03:00
/* Allocate a chunk that does not fit into a SLUB cache to trigger
* the page allocator fallback .
*/
pr_info ( " kmalloc pagealloc allocation: out-of-bounds to right \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
ptr [ size ] = 0 ;
kfree ( ptr ) ;
}
2018-02-07 02:36:23 +03:00
static noinline void __init kmalloc_pagealloc_uaf ( void )
{
char * ptr ;
size_t size = KMALLOC_MAX_CACHE_SIZE + 10 ;
pr_info ( " kmalloc pagealloc allocation: use-after-free \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kfree ( ptr ) ;
ptr [ 0 ] = 0 ;
}
static noinline void __init kmalloc_pagealloc_invalid_free ( void )
{
char * ptr ;
size_t size = KMALLOC_MAX_CACHE_SIZE + 10 ;
pr_info ( " kmalloc pagealloc allocation: invalid-free \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kfree ( ptr + 1 ) ;
}
2016-03-26 00:21:56 +03:00
# endif
static noinline void __init kmalloc_large_oob_right ( void )
{
char * ptr ;
size_t size = KMALLOC_MAX_CACHE_SIZE - 256 ;
/* Allocate a chunk that is large enough, but still fits into a slab
* and does not trigger the page allocator fallback in SLUB .
*/
2015-02-14 01:39:53 +03:00
pr_info ( " kmalloc large allocation: out-of-bounds to right \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
ptr [ size ] = 0 ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_oob_krealloc_more ( void )
{
char * ptr1 , * ptr2 ;
size_t size1 = 17 ;
size_t size2 = 19 ;
pr_info ( " out-of-bounds after krealloc more \n " ) ;
ptr1 = kmalloc ( size1 , GFP_KERNEL ) ;
ptr2 = krealloc ( ptr1 , size2 , GFP_KERNEL ) ;
if ( ! ptr1 | | ! ptr2 ) {
pr_err ( " Allocation failed \n " ) ;
kfree ( ptr1 ) ;
2020-01-31 09:13:51 +03:00
kfree ( ptr2 ) ;
2015-02-14 01:39:53 +03:00
return ;
}
ptr2 [ size2 ] = ' x ' ;
kfree ( ptr2 ) ;
}
static noinline void __init kmalloc_oob_krealloc_less ( void )
{
char * ptr1 , * ptr2 ;
size_t size1 = 17 ;
size_t size2 = 15 ;
pr_info ( " out-of-bounds after krealloc less \n " ) ;
ptr1 = kmalloc ( size1 , GFP_KERNEL ) ;
ptr2 = krealloc ( ptr1 , size2 , GFP_KERNEL ) ;
if ( ! ptr1 | | ! ptr2 ) {
pr_err ( " Allocation failed \n " ) ;
kfree ( ptr1 ) ;
return ;
}
2015-09-10 01:37:22 +03:00
ptr2 [ size2 ] = ' x ' ;
2015-02-14 01:39:53 +03:00
kfree ( ptr2 ) ;
}
static noinline void __init kmalloc_oob_16 ( void )
{
struct {
u64 words [ 2 ] ;
} * ptr1 , * ptr2 ;
pr_info ( " kmalloc out-of-bounds for 16-bytes access \n " ) ;
ptr1 = kmalloc ( sizeof ( * ptr1 ) - 3 , GFP_KERNEL ) ;
ptr2 = kmalloc ( sizeof ( * ptr2 ) , GFP_KERNEL ) ;
if ( ! ptr1 | | ! ptr2 ) {
pr_err ( " Allocation failed \n " ) ;
kfree ( ptr1 ) ;
kfree ( ptr2 ) ;
return ;
}
* ptr1 = * ptr2 ;
kfree ( ptr1 ) ;
kfree ( ptr2 ) ;
}
2015-11-06 05:51:15 +03:00
static noinline void __init kmalloc_oob_memset_2 ( void )
{
char * ptr ;
size_t size = 8 ;
pr_info ( " out-of-bounds in memset2 \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
memset ( ptr + 7 , 0 , 2 ) ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_oob_memset_4 ( void )
{
char * ptr ;
size_t size = 8 ;
pr_info ( " out-of-bounds in memset4 \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
memset ( ptr + 5 , 0 , 4 ) ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_oob_memset_8 ( void )
{
char * ptr ;
size_t size = 8 ;
pr_info ( " out-of-bounds in memset8 \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
memset ( ptr + 1 , 0 , 8 ) ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_oob_memset_16 ( void )
{
char * ptr ;
size_t size = 16 ;
pr_info ( " out-of-bounds in memset16 \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
memset ( ptr + 1 , 0 , 16 ) ;
kfree ( ptr ) ;
}
2015-02-14 01:39:53 +03:00
static noinline void __init kmalloc_oob_in_memset ( void )
{
char * ptr ;
size_t size = 666 ;
pr_info ( " out-of-bounds in memset \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
memset ( ptr , 0 , size + 5 ) ;
kfree ( ptr ) ;
}
static noinline void __init kmalloc_uaf ( void )
{
char * ptr ;
size_t size = 10 ;
pr_info ( " use-after-free \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kfree ( ptr ) ;
* ( ptr + 8 ) = ' x ' ;
}
static noinline void __init kmalloc_uaf_memset ( void )
{
char * ptr ;
size_t size = 33 ;
pr_info ( " use-after-free in memset \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kfree ( ptr ) ;
memset ( ptr , 0 , size ) ;
}
static noinline void __init kmalloc_uaf2 ( void )
{
char * ptr1 , * ptr2 ;
size_t size = 43 ;
pr_info ( " use-after-free after another kmalloc \n " ) ;
ptr1 = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr1 ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kfree ( ptr1 ) ;
ptr2 = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr2 ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
ptr1 [ 40 ] = ' x ' ;
2016-03-26 00:22:11 +03:00
if ( ptr1 = = ptr2 )
pr_err ( " Could not detect use-after-free: ptr1 == ptr2 \n " ) ;
2015-02-14 01:39:53 +03:00
kfree ( ptr2 ) ;
}
2019-09-24 01:34:16 +03:00
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 ) ) ;
}
2015-02-14 01:39:53 +03:00
static noinline void __init kmem_cache_oob ( void )
{
char * p ;
size_t size = 200 ;
struct kmem_cache * cache = kmem_cache_create ( " test_cache " ,
size , 0 ,
0 , NULL ) ;
if ( ! cache ) {
pr_err ( " Cache allocation failed \n " ) ;
return ;
}
pr_info ( " out-of-bounds in kmem_cache_alloc \n " ) ;
p = kmem_cache_alloc ( cache , GFP_KERNEL ) ;
if ( ! p ) {
pr_err ( " Allocation failed \n " ) ;
kmem_cache_destroy ( cache ) ;
return ;
}
* p = p [ size ] ;
kmem_cache_free ( cache , p ) ;
kmem_cache_destroy ( cache ) ;
}
2017-02-25 02:00:08 +03:00
static noinline void __init memcg_accounted_kmem_cache ( void )
{
int i ;
char * p ;
size_t size = 200 ;
struct kmem_cache * cache ;
cache = kmem_cache_create ( " test_cache " , size , 0 , SLAB_ACCOUNT , NULL ) ;
if ( ! cache ) {
pr_err ( " Cache allocation failed \n " ) ;
return ;
}
pr_info ( " allocate memcg accounted object \n " ) ;
/*
* Several allocations with a delay to allow for lazy per memcg kmem
* cache creation .
*/
for ( i = 0 ; i < 5 ; i + + ) {
p = kmem_cache_alloc ( cache , GFP_KERNEL ) ;
2017-11-18 02:28:00 +03:00
if ( ! p )
2017-02-25 02:00:08 +03:00
goto free_cache ;
2017-11-18 02:28:00 +03:00
2017-02-25 02:00:08 +03:00
kmem_cache_free ( cache , p ) ;
msleep ( 100 ) ;
}
free_cache :
kmem_cache_destroy ( cache ) ;
}
2015-02-14 01:39:53 +03:00
static char global_array [ 10 ] ;
static noinline void __init kasan_global_oob ( void )
{
volatile int i = 3 ;
char * p = & global_array [ ARRAY_SIZE ( global_array ) + i ] ;
pr_info ( " out-of-bounds global variable \n " ) ;
* ( volatile char * ) p ;
}
static noinline void __init kasan_stack_oob ( void )
{
char stack_array [ 10 ] ;
volatile int i = 0 ;
char * p = & stack_array [ ARRAY_SIZE ( stack_array ) + i ] ;
pr_info ( " out-of-bounds on stack \n " ) ;
* ( volatile char * ) p ;
}
2016-05-21 02:59:17 +03:00
static noinline void __init ksize_unpoisons_memory ( void )
{
char * ptr ;
2018-02-07 02:36:48 +03:00
size_t size = 123 , real_size ;
2016-05-21 02:59:17 +03:00
pr_info ( " ksize() unpoisons the whole allocated chunk \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
real_size = ksize ( ptr ) ;
/* This access doesn't trigger an error. */
ptr [ size ] = ' x ' ;
/* This one does. */
ptr [ real_size ] = ' y ' ;
kfree ( ptr ) ;
}
2016-05-21 02:59:34 +03:00
static noinline void __init copy_user_test ( void )
{
char * kmem ;
char __user * usermem ;
size_t size = 10 ;
int unused ;
kmem = kmalloc ( size , GFP_KERNEL ) ;
if ( ! kmem )
return ;
usermem = ( char __user * ) vm_mmap ( NULL , 0 , PAGE_SIZE ,
PROT_READ | PROT_WRITE | PROT_EXEC ,
MAP_ANONYMOUS | MAP_PRIVATE , 0 ) ;
if ( IS_ERR ( usermem ) ) {
pr_err ( " Failed to allocate user memory \n " ) ;
kfree ( kmem ) ;
return ;
}
pr_info ( " out-of-bounds in copy_from_user() \n " ) ;
unused = copy_from_user ( kmem , usermem , size + 1 ) ;
pr_info ( " out-of-bounds in copy_to_user() \n " ) ;
unused = copy_to_user ( usermem , kmem , size + 1 ) ;
pr_info ( " out-of-bounds in __copy_from_user() \n " ) ;
unused = __copy_from_user ( kmem , usermem , size + 1 ) ;
pr_info ( " out-of-bounds in __copy_to_user() \n " ) ;
unused = __copy_to_user ( usermem , kmem , size + 1 ) ;
pr_info ( " out-of-bounds in __copy_from_user_inatomic() \n " ) ;
unused = __copy_from_user_inatomic ( kmem , usermem , size + 1 ) ;
pr_info ( " out-of-bounds in __copy_to_user_inatomic() \n " ) ;
unused = __copy_to_user_inatomic ( usermem , kmem , size + 1 ) ;
pr_info ( " out-of-bounds in strncpy_from_user() \n " ) ;
unused = strncpy_from_user ( kmem , usermem , size + 1 ) ;
vm_munmap ( ( unsigned long ) usermem , PAGE_SIZE ) ;
kfree ( kmem ) ;
}
2018-02-07 02:36:16 +03:00
static noinline void __init kasan_alloca_oob_left ( void )
{
volatile int i = 10 ;
char alloca_array [ i ] ;
char * p = alloca_array - 1 ;
pr_info ( " out-of-bounds to left on alloca \n " ) ;
* ( volatile char * ) p ;
}
static noinline void __init kasan_alloca_oob_right ( void )
{
volatile int i = 10 ;
char alloca_array [ i ] ;
char * p = alloca_array + i ;
pr_info ( " out-of-bounds to right on alloca \n " ) ;
* ( volatile char * ) p ;
}
2018-02-07 02:36:37 +03:00
static noinline void __init kmem_cache_double_free ( void )
{
char * p ;
size_t size = 200 ;
struct kmem_cache * cache ;
cache = kmem_cache_create ( " test_cache " , size , 0 , 0 , NULL ) ;
if ( ! cache ) {
pr_err ( " Cache allocation failed \n " ) ;
return ;
}
pr_info ( " double-free on heap object \n " ) ;
p = kmem_cache_alloc ( cache , GFP_KERNEL ) ;
if ( ! p ) {
pr_err ( " Allocation failed \n " ) ;
kmem_cache_destroy ( cache ) ;
return ;
}
kmem_cache_free ( cache , p ) ;
kmem_cache_free ( cache , p ) ;
kmem_cache_destroy ( cache ) ;
}
static noinline void __init kmem_cache_invalid_free ( void )
{
char * p ;
size_t size = 200 ;
struct kmem_cache * cache ;
cache = kmem_cache_create ( " test_cache " , size , 0 , SLAB_TYPESAFE_BY_RCU ,
NULL ) ;
if ( ! cache ) {
pr_err ( " Cache allocation failed \n " ) ;
return ;
}
pr_info ( " invalid-free of heap object \n " ) ;
p = kmem_cache_alloc ( cache , GFP_KERNEL ) ;
if ( ! p ) {
pr_err ( " Allocation failed \n " ) ;
kmem_cache_destroy ( cache ) ;
return ;
}
2018-04-11 02:30:35 +03:00
/* Trigger invalid free, the object doesn't get freed */
2018-02-07 02:36:37 +03:00
kmem_cache_free ( cache , p + 1 ) ;
2018-04-11 02:30:35 +03:00
/*
* Properly free the object to prevent the " Objects remaining in
* test_cache on __kmem_cache_shutdown " BUG failure.
*/
kmem_cache_free ( cache , p ) ;
2018-02-07 02:36:37 +03:00
kmem_cache_destroy ( cache ) ;
}
2018-10-27 01:02:34 +03:00
static noinline void __init kasan_memchr ( void )
{
char * ptr ;
size_t size = 24 ;
pr_info ( " out-of-bounds in memchr \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL | __GFP_ZERO ) ;
if ( ! ptr )
return ;
memchr ( ptr , ' 1 ' , size + 1 ) ;
kfree ( ptr ) ;
}
static noinline void __init kasan_memcmp ( void )
{
char * ptr ;
size_t size = 24 ;
int arr [ 9 ] ;
pr_info ( " out-of-bounds in memcmp \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL | __GFP_ZERO ) ;
if ( ! ptr )
return ;
memset ( arr , 0 , sizeof ( arr ) ) ;
memcmp ( ptr , arr , size + 1 ) ;
kfree ( ptr ) ;
}
static noinline void __init kasan_strings ( void )
{
char * ptr ;
size_t size = 24 ;
pr_info ( " use-after-free in strchr \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL | __GFP_ZERO ) ;
if ( ! ptr )
return ;
kfree ( ptr ) ;
/*
* Try to cause only 1 invalid access ( less spam in dmesg ) .
* For that we need ptr to point to zeroed byte .
* Skip metadata that could be stored in freed object so ptr
* will likely point to zeroed byte .
*/
ptr + = 16 ;
strchr ( ptr , ' 1 ' ) ;
pr_info ( " use-after-free in strrchr \n " ) ;
strrchr ( ptr , ' 1 ' ) ;
pr_info ( " use-after-free in strcmp \n " ) ;
strcmp ( ptr , " 2 " ) ;
pr_info ( " use-after-free in strncmp \n " ) ;
strncmp ( ptr , " 2 " , 1 ) ;
pr_info ( " use-after-free in strlen \n " ) ;
strlen ( ptr ) ;
pr_info ( " use-after-free in strnlen \n " ) ;
strnlen ( ptr , 1 ) ;
}
2019-07-12 06:53:52 +03:00
static noinline void __init kasan_bitops ( void )
{
/*
* Allocate 1 more byte , which causes kzalloc to round up to 16 - bytes ;
* this way we do not actually corrupt other memory .
*/
long * bits = kzalloc ( sizeof ( * bits ) + 1 , GFP_KERNEL ) ;
if ( ! bits )
return ;
/*
* Below calls try to access bit within allocated memory ; however , the
* below accesses are still out - of - bounds , since bitops are defined to
* operate on the whole long the bit is in .
*/
pr_info ( " out-of-bounds in set_bit \n " ) ;
set_bit ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in __set_bit \n " ) ;
__set_bit ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in clear_bit \n " ) ;
clear_bit ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in __clear_bit \n " ) ;
__clear_bit ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in clear_bit_unlock \n " ) ;
clear_bit_unlock ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in __clear_bit_unlock \n " ) ;
__clear_bit_unlock ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in change_bit \n " ) ;
change_bit ( BITS_PER_LONG , bits ) ;
pr_info ( " out-of-bounds in __change_bit \n " ) ;
__change_bit ( BITS_PER_LONG , bits ) ;
/*
* Below calls try to access bit beyond allocated memory .
*/
pr_info ( " out-of-bounds in test_and_set_bit \n " ) ;
test_and_set_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in __test_and_set_bit \n " ) ;
__test_and_set_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in test_and_set_bit_lock \n " ) ;
test_and_set_bit_lock ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in test_and_clear_bit \n " ) ;
test_and_clear_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in __test_and_clear_bit \n " ) ;
__test_and_clear_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in test_and_change_bit \n " ) ;
test_and_change_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in __test_and_change_bit \n " ) ;
__test_and_change_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
pr_info ( " out-of-bounds in test_bit \n " ) ;
( void ) test_bit ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
# if defined(clear_bit_unlock_is_negative_byte)
pr_info ( " out-of-bounds in clear_bit_unlock_is_negative_byte \n " ) ;
clear_bit_unlock_is_negative_byte ( BITS_PER_LONG + BITS_PER_BYTE , bits ) ;
# endif
kfree ( bits ) ;
}
2019-07-12 06:54:11 +03:00
static noinline void __init kmalloc_double_kzfree ( void )
{
char * ptr ;
size_t size = 16 ;
pr_info ( " double-free (kzfree) \n " ) ;
ptr = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ptr ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
kzfree ( ptr ) ;
kzfree ( ptr ) ;
}
2019-12-01 04:54:53 +03:00
# ifdef CONFIG_KASAN_VMALLOC
static noinline void __init vmalloc_oob ( void )
{
void * area ;
pr_info ( " vmalloc out-of-bounds \n " ) ;
/*
* We have to be careful not to hit the guard page .
* The MMU will catch that and crash us .
*/
area = vmalloc ( 3000 ) ;
if ( ! area ) {
pr_err ( " Allocation failed \n " ) ;
return ;
}
( ( volatile char * ) area ) [ 3100 ] ;
vfree ( area ) ;
}
# else
static void __init vmalloc_oob ( void ) { }
# endif
2015-02-14 01:39:53 +03:00
static int __init kmalloc_tests_init ( void )
{
2017-04-01 01:12:04 +03:00
/*
* Temporarily enable multi - shot mode . Otherwise , we ' d only get a
* report for the first case .
*/
bool multishot = kasan_save_enable_multi_shot ( ) ;
2015-02-14 01:39:53 +03:00
kmalloc_oob_right ( ) ;
kmalloc_oob_left ( ) ;
kmalloc_node_oob_right ( ) ;
2016-03-26 00:21:56 +03:00
# ifdef CONFIG_SLUB
kmalloc_pagealloc_oob_right ( ) ;
2018-02-07 02:36:23 +03:00
kmalloc_pagealloc_uaf ( ) ;
kmalloc_pagealloc_invalid_free ( ) ;
2016-03-26 00:21:56 +03:00
# endif
2015-09-10 01:37:19 +03:00
kmalloc_large_oob_right ( ) ;
2015-02-14 01:39:53 +03:00
kmalloc_oob_krealloc_more ( ) ;
kmalloc_oob_krealloc_less ( ) ;
kmalloc_oob_16 ( ) ;
kmalloc_oob_in_memset ( ) ;
2015-11-06 05:51:15 +03:00
kmalloc_oob_memset_2 ( ) ;
kmalloc_oob_memset_4 ( ) ;
kmalloc_oob_memset_8 ( ) ;
kmalloc_oob_memset_16 ( ) ;
2015-02-14 01:39:53 +03:00
kmalloc_uaf ( ) ;
kmalloc_uaf_memset ( ) ;
kmalloc_uaf2 ( ) ;
2019-09-24 01:34:16 +03:00
kfree_via_page ( ) ;
kfree_via_phys ( ) ;
2015-02-14 01:39:53 +03:00
kmem_cache_oob ( ) ;
2017-02-25 02:00:08 +03:00
memcg_accounted_kmem_cache ( ) ;
2015-02-14 01:39:53 +03:00
kasan_stack_oob ( ) ;
kasan_global_oob ( ) ;
2018-02-07 02:36:16 +03:00
kasan_alloca_oob_left ( ) ;
kasan_alloca_oob_right ( ) ;
2016-05-21 02:59:17 +03:00
ksize_unpoisons_memory ( ) ;
2016-05-21 02:59:34 +03:00
copy_user_test ( ) ;
2018-02-07 02:36:37 +03:00
kmem_cache_double_free ( ) ;
kmem_cache_invalid_free ( ) ;
2018-10-27 01:02:34 +03:00
kasan_memchr ( ) ;
kasan_memcmp ( ) ;
kasan_strings ( ) ;
2019-07-12 06:53:52 +03:00
kasan_bitops ( ) ;
2019-07-12 06:54:11 +03:00
kmalloc_double_kzfree ( ) ;
2019-12-01 04:54:53 +03:00
vmalloc_oob ( ) ;
2017-04-01 01:12:04 +03:00
kasan_restore_multi_shot ( multishot ) ;
2015-02-14 01:39:53 +03:00
return - EAGAIN ;
}
module_init ( kmalloc_tests_init ) ;
MODULE_LICENSE ( " GPL " ) ;