Linux內核內存檢測工具KASAN


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

一、KASAN的原理和使用方法

1. 如何打開KASAN功能

 

Kernel defconfig增加如下配置:

由於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標記。

如果8 bytes內存都可以訪問,則shadow memory的值為0;如果連續N(1 =< N <= 7) bytes可以訪問,則shadow memory的值為N;如果8 bytes內存訪問都是invalid,則shadow memory的值為負數。

圖片摘自 http://www.wowotech.net/memory_management/424.html

例如:

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

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

 

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

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分配內存

圖片摘自 http://www.wowotech.net/memory_management/424.html

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釋放內存

圖片摘自 http://www.wowotech.net/memory_management/424.html

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分配內存

圖片摘自 http://www.wowotech.net/memory_management/424.html

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釋放內存

圖片摘自 http://www.wowotech.net/memory_management/424.html

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舉例

 

二、總結

KASAN通過建立影子內存來管理內存訪問的合法性,可以有效檢測內存越界等問題,但無法發現因邏輯問題導致的合法內存的內容改寫問題。

 

 

參考文獻:

1. http://www.wowotech.net/memory_management/424.html

2. https://www.kernel.org/doc/html/latest/dev-tools/kasan.html

3. KernelAddressSanitizer (KASan) a fast memory error detector for the Linux kernel.pdf

掃碼關注
“內核工匠”微信公眾號
Linux 內核黑科技 | 技術文章 | 精選教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM