mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
![Andrey Ryabinin](/assets/img/avatar_default.png)
This feature let us to detect accesses out of bounds of global variables. This will work as for globals in kernel image, so for globals in modules. Currently this won't work for symbols in user-specified sections (e.g. __init, __read_mostly, ...) The idea of this is simple. Compiler increases each global variable by redzone size and add constructors invoking __asan_register_globals() function. Information about global variable (address, size, size with redzone ...) passed to __asan_register_globals() so we could poison variable's redzone. This patch also forces module_alloc() to return 8*PAGE_SIZE aligned address making shadow memory handling ( kasan_module_alloc()/kasan_module_free() ) more simple. Such alignment guarantees that each shadow page backing modules address space correspond to only one module_alloc() allocation. Signed-off-by: Andrey Ryabinin <a.ryabinin@samsung.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Konstantin Serebryany <kcc@google.com> Cc: Dmitry Chernenkov <dmitryc@google.com> Signed-off-by: Andrey Konovalov <adech.fo@gmail.com> Cc: Yuri Gribov <tetra2005@gmail.com> Cc: Konstantin Khlebnikov <koct9i@gmail.com> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: Christoph Lameter <cl@linux.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
170 lines
7.9 KiB
Text
170 lines
7.9 KiB
Text
Kernel address sanitizer
|
|
================
|
|
|
|
0. Overview
|
|
===========
|
|
|
|
Kernel Address sanitizer (KASan) is a dynamic memory error detector. It provides
|
|
a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
|
bugs.
|
|
|
|
KASan uses compile-time instrumentation for checking every memory access,
|
|
therefore you will need a certain version of GCC > 4.9.2
|
|
|
|
Currently KASan is supported only for x86_64 architecture and requires that the
|
|
kernel be built with the SLUB allocator.
|
|
|
|
1. Usage
|
|
=========
|
|
|
|
To enable KASAN configure kernel with:
|
|
|
|
CONFIG_KASAN = y
|
|
|
|
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
|
|
is compiler instrumentation types. The former produces smaller binary the
|
|
latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
|
|
latter.
|
|
|
|
Currently KASAN works only with the SLUB memory allocator.
|
|
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
|
|
at least 'slub_debug=U' in the boot cmdline.
|
|
|
|
To disable instrumentation for specific files or directories, add a line
|
|
similar to the following to the respective kernel Makefile:
|
|
|
|
For a single file (e.g. main.o):
|
|
KASAN_SANITIZE_main.o := n
|
|
|
|
For all files in one directory:
|
|
KASAN_SANITIZE := n
|
|
|
|
1.1 Error reports
|
|
==========
|
|
|
|
A typical out of bounds access report looks like this:
|
|
|
|
==================================================================
|
|
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
|
|
Write of size 1 by task modprobe/1689
|
|
=============================================================================
|
|
BUG kmalloc-128 (Not tainted): kasan error
|
|
-----------------------------------------------------------------------------
|
|
|
|
Disabling lock debugging due to kernel taint
|
|
INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
|
|
__slab_alloc+0x4b4/0x4f0
|
|
kmem_cache_alloc_trace+0x10b/0x190
|
|
kmalloc_oob_right+0x3d/0x75 [test_kasan]
|
|
init_module+0x9/0x47 [test_kasan]
|
|
do_one_initcall+0x99/0x200
|
|
load_module+0x2cb3/0x3b20
|
|
SyS_finit_module+0x76/0x80
|
|
system_call_fastpath+0x12/0x17
|
|
INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
|
|
INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
|
|
|
|
Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
|
|
Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
|
Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
|
|
Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
|
|
Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
|
|
CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
|
|
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
|
|
ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
|
|
ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
|
|
ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
|
|
Call Trace:
|
|
[<ffffffff81cc68ae>] dump_stack+0x46/0x58
|
|
[<ffffffff811fd848>] print_trailer+0xf8/0x160
|
|
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
|
[<ffffffff811ff0f5>] object_err+0x35/0x40
|
|
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
[<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
|
|
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
|
[<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
|
|
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
|
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
|
[<ffffffff8120a995>] __asan_store1+0x75/0xb0
|
|
[<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
|
|
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
[<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
|
|
[<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
|
|
[<ffffffff810002d9>] do_one_initcall+0x99/0x200
|
|
[<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
|
|
[<ffffffff81114f63>] load_module+0x2cb3/0x3b20
|
|
[<ffffffff8110fd70>] ? m_show+0x240/0x240
|
|
[<ffffffff81115f06>] SyS_finit_module+0x76/0x80
|
|
[<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
|
|
Memory state around the buggy address:
|
|
ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
|
|
ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
|
|
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
|
|
^
|
|
ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
|
ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
|
|
ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
|
ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
|
==================================================================
|
|
|
|
First sections describe slub object where bad access happened.
|
|
See 'SLUB Debug output' section in Documentation/vm/slub.txt for details.
|
|
|
|
In the last section the report shows memory state around the accessed address.
|
|
Reading this part requires some more understanding of how KASAN works.
|
|
|
|
Each 8 bytes of memory are encoded in one shadow byte as accessible,
|
|
partially accessible, freed or they can be part of a redzone.
|
|
We use the following encoding for each shadow byte: 0 means that all 8 bytes
|
|
of the corresponding memory region are accessible; number N (1 <= N <= 7) means
|
|
that the first N bytes are accessible, and other (8 - N) bytes are not;
|
|
any negative value indicates that the entire 8-byte word is inaccessible.
|
|
We use different negative values to distinguish between different kinds of
|
|
inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
|
|
|
|
In the report above the arrows point to the shadow byte 03, which means that
|
|
the accessed address is partially accessible.
|
|
|
|
|
|
2. Implementation details
|
|
========================
|
|
|
|
From a high level, our approach to memory error detection is similar to that
|
|
of kmemcheck: use shadow memory to record whether each byte of memory is safe
|
|
to access, and use compile-time instrumentation to check shadow memory on each
|
|
memory access.
|
|
|
|
AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
|
|
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
|
|
offset to translate a memory address to its corresponding shadow address.
|
|
|
|
Here is the function witch translate an address to its corresponding shadow
|
|
address:
|
|
|
|
static inline void *kasan_mem_to_shadow(const void *addr)
|
|
{
|
|
return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
|
|
+ KASAN_SHADOW_OFFSET;
|
|
}
|
|
|
|
where KASAN_SHADOW_SCALE_SHIFT = 3.
|
|
|
|
Compile-time instrumentation used for checking memory accesses. Compiler inserts
|
|
function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
|
|
access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
|
|
valid or not by checking corresponding shadow memory.
|
|
|
|
GCC 5.0 has possibility to perform inline instrumentation. Instead of making
|
|
function calls GCC directly inserts the code to check the shadow memory.
|
|
This option significantly enlarges kernel but it gives x1.1-x2 performance
|
|
boost over outline instrumented kernel.
|