Linux內核內存檢測工具KASAN

KASAN 是 Kernel Address Sanitizer 的縮寫,它是一個動態檢測內存錯誤的工具,主要功能是檢查內存越界訪問和使用已釋放的內存等問題。KASAN 集成在 Linux 內核中,隨 Linux 內核代碼一塊兒發佈,並由內核社區維護和發展。本文簡要介紹 KASAN 的原理及使用方法。shell

1、KASAN的原理和使用方法

1. 如何打開KASAN功能

Kernel defconfig增長以下配置:函數

image

因爲1/8的內存用於shadow memory,可用內存會減小1/8,例如8GB的內存,打開KASAN後,MemTotal約爲6.72GB。工具

C:\Users>adb shell "cat /proc/meminfo | grep MemTotal"
MemTotal:        6723572 kB

2. KASAN原理概述

KASAN利用額外的內存標記可用內存的狀態,這部分額外的內存被稱做shadow memory(影子區),KASAN將1/8的內存用做shadow memory。使用特殊的magic num填充shadow memory,在每一次load/store內存的時候檢測對應的shadow memory肯定操做是否valid。連續8 bytes內存(8 bytes align)使用1 byte shadow memory標記。code

若是8 bytes內存均可以訪問,則shadow memory的值爲0;若是連續N(1 =< N <= 7) bytes能夠訪問,則shadow memory的值爲N;若是8 bytes內存訪問都是invalid,則shadow memory的值爲負數。內存

image

例如:編譯器

image

這段彙編指令是往0xffffffc08821e810地址寫5,當打開Kasan時,編譯器會自動插入紅色的bl __asan_store1指令,__asan_store1函數就是檢測一個地址對應的shadow memory的值是否容許寫1 byte,藍色彙編指令是真正的內存訪問。it

3. 如何根據shadow memory的值判斷內存訪問操做是否合法?

shadow memory檢測原理的實現主要就是__asan_load##size()和__asan_store##size()函數。KASAN如何根據訪問的address以及對應的shadow memory的狀態值來判斷訪問是否合法呢?編譯

image

image

1)當訪問8 bytes時,*shadow_memory == 0,訪問是valid,不然是invalid;社區

2)當訪問N bytes (N = 1,2,4)時,變量

if (*shadow && *shadow > ((unsigned long)addr & 7) + N),訪問valid;不然,是invalid;

4. 夥伴系統分配的內存shadow memory值如何填充

(1) 從buddy system分配內存

image

Step1:假如從buddy system分配4 pages,系統首先從order=2的鏈表中摘下一塊內存;

Step2:而後根據shadow memory address和memory address的對應關係找到對應的shadow memory;對應關係爲:

Shadow_addr = (addr >> 3) + KASAN_SHADOW_OFFSET,右移3bit的緣由是8 byte memory對應1 byte shadow memory;

Step3:填充shadow memory的內容,分配的4 pages都可訪問,填充爲0;

(2) 從buddy system釋放內存
image

Step1:從buddy system order = 2的鏈表中釋放4 pages;

Step2:根據shadow memory addr和memory addr的對應關係,找到shadow memory;

Step3:將shadow memory對應的內存區域2KB(16KB/8)填充爲0xFF(KASAN_FREE_PAGE);

5. slub分配的內存shadow memory值如何填充

(1) 從slub cache分配內存

image

Step1:kmalloc(20)會匹配到kmalloc-32的kmem_cache,實際分配的object大小是32 bytes。剩下的12 bytes KASAN會標記爲不可訪問狀態;

Step2:根據shadow memory addr和memory addr的對應關係找到shadow meory;

Step3:填充shadow memory的內容爲00 00 04 FC,具體含義爲:

1)前面2個00表示第0~15 byte都可訪問
2)04表示第16~23 byte只有前面4 bytes能夠訪問
3)FC表示第24~31 byte爲 KASAN_KMALLOC_REDZONE,不可訪問

Step4:保存內存分配的call-stack;

Step5:若是訪問了REDZONE區域,KASAN會report out-of-bounds bug;

(2) 從slub cache釋放內存
image

Step1:從slub cache(kmalloc-32) free 20 bytes內存;

Step2:根據memory addr找到shadow memory addr;

Step3:將shadow memory的4 bytes填充爲FB(KASAN_KMALLOC_FREE);

Step4:保存slub free的call-stack;

Step5:若是訪問了 FB對應的內存,KASAN會報use-after-free bug;

6. 其餘形式分配的內存shadow memory如何填充?

全局變量/棧分配的內存填充原理和前面相似,實現有些差別,這裏不一一贅述。

7. KASAN report bug舉例

image

image

2、總結

KASAN經過創建影子內存來管理內存訪問的合法性,能夠有效檢測內存越界等問題,但沒法發現因邏輯問題致使的合法內存的內容改寫問題。

相關文章
相關標籤/搜索