精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

Linux閱碼場 ? 2018-02-08 14:11 ? 次閱讀

本文簡介:SLAB內存分配器-SLUB的DEBUG功能,如何幫忙檢測內存越界(out-of-bounds)和訪問已經釋放的內存(use-after-free)。本文目錄:

1. 前言

2. SLUB DEBUG功能

3. object layout

4. SLUB DEBUG原理

5. slabinfo

1. 前言

在工作中,經常會遇到由于越界導致的各種奇怪的問題。為什么越界訪問導致的問題很奇怪呢?在工作差不多半年的時間里我就遇到了很多越界訪問導致的問題(不得不吐槽下IC廠商提供的driver,總是隱藏著bug)。比如說越界訪問導致的死機問題,這種問題的出現一般需要長時間測試才能發現,而且發現的時候即使有panic log。你也沒什么頭緒。這是為什么呢?假設驅動A通過kmalloc()申請了一段內存,不注意越界改寫了與其相鄰的object的數據(經過我之前一篇SLUB的文章分析,你應該明白kmalloc基于kmem_cache實現的),假設被改寫的object是B驅動使用的,巧合B驅動使用object存儲的是地址數據,如果B驅動訪問這個地址。那么完了,B驅動死了,panic也是怪B驅動。試想一下,這塊被改寫的object是哪個驅動使用,是不是哪個驅動就倒霉了?并且每一次死機的log中panic極有可能發生在不同的模塊。但是真正的元兇卻是A驅動,他沒事你還不知道,是不是很恐怖?簡直是借刀殺人啊!

當然,越界訪問也不一定會死機。之前就遇到一個很奇怪的問題。有兩個全局數組變量(用作存儲字符串)分別被模塊C和D使用。這兩個數組是上層需要顯示的name信息。當C和D模塊都工作的時候,發現C模塊的name顯示不對,但是D模塊的name顯示正常。將D模塊remove,發現C模塊的name顯示正確。當時看了下System.map文件,發現這兩個全局數組變量分配的內存是在一起的,由于D模塊越界寫導致的。而這種情況就不會死機。但是當你遇到這種情況的時候,你很驚訝,怎么會這樣?兩個模塊之間根本就沒關系啊!如果完全不借助檢測工具去查找問題是相當費時間的。而且有可能還沒什么頭緒。

這種問題我們該怎么定位?因此我們遇到一種debug的手段,可以檢測out-of-bounds(oob)問題。剛才的第一種情況就可以SLUB自帶debug功能。針對第二種情況就需要借助更加強大的KASAN工具(后續會有文章介紹)。

因此,我們需要一種debug手段幫助我們定位問題。SLUB DEBUG就是其中的一種。但是SLUB DEBUG僅僅針對從slub分配器分配的內存,如果你需要檢測從棧中或者數據區分配內存的問題,就不行了。當然了,你可以選擇KASAN。本文主要關注SLUB DEBUG的原理,如何定位這些問題的。

SLUB DEBUG檢測oob問題原理也很簡單,既然為了發現是否越界,那么就在分配出去的內存尾部添加一段額外的內存,填充特殊數字(magic num)。我們只需要檢測這塊額外的內存的數據是否被修改就可以知道是否發生了oob情況。而這段額外的內存就叫做Redzone。直譯過來“紅色區域”是不是有種神圣不可侵犯的感覺。

說明:slab是最早加入linux的,在那時只有slab的存在。隨著時間的推移slub出現了,slub是在slab基礎上進行的改進,在大型機上表現出色。而slob是針對小型系統設計的。由于slub實現的接口和slab接口保持一致(雖然你用的是slub分配器,但是很多函數名稱和數據結構還是依然和slab一致),所以有時候用slab來統稱slab, slub和slob。slab, slub和slob僅僅是分配內存策略不同。管理的思想基本一致。本篇文章中說的是slub分配器debug原理。但是針對分配器管理的內存,下文統稱為slab緩存池。所以文章中slub和slab會混用,表示同一個意思。

注:文章代碼分析基于linux-4.15.0-rc3。

2.SLUB DEBUG功能

SLUB DEBUG可以檢測內存越界(out-of-bounds)和訪問已經釋放的內存(use-after-free)等問題。

1.1. 如何打開功能

重新配置kernel選項,打開如下選項即可。

CONFIG_SLUB=y

CONFIG_SLUB_DEBUG=y

CONFIG_SLUB_DEBUG_ON=y

1.2. 如何使用

程序中的bug如果想用SLUB DEBUG去檢測,還需要slabinfo命令。因為,SLUB內存檢測功能在某些情況下不能立刻檢測出來,必須主動觸發,因此我們需要借助slabinfo命令觸發SLUB allocator檢測功能。和KASAN相比較而言,這也是SLUB DEBUG的一個劣勢。畢竟KASAN可以做到在越界問題出現時就報出問題。

slabinfo工具源碼位于tools/vm目錄。可以使用如下命令編譯slabinfo工具(針對ARM64 architecture)。

aarch64-linux-gnu-gcc -o slabinfo slabinfo.c

當系統開機之后,就可以運行slaninfo –v命令觸發SLUB allocator檢測所有的object,并將log信息輸出到syslog。接下來的任務就是查看log信息是否包含SLUB allocator輸出的bug log。其實有些bug是不需要運行slabinfo命令即可捕捉,但是有些卻必須使用slabinfo –v命令才可以。下一節將會介紹SLUB DEBUG的原理,為你揭開哪些bug不需要slabinfo命令。

3. object layout

配置kernel選項CONFIG_SLUB_DEBUG_ON后,在創建kmem_cache的時候會傳遞很多flags(SLAB_CONSISTENCY_CHECKS、SLAB_RED_ZONE、SLAB_POISON、SLAB_STORE_USER)。針對這些flags,SLUB allocator管理的object對象的format將會發生變化。如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

SLUB DEBUG關閉的情況下,free pointer是內嵌在object之中的,但是SLUB DEBUG打開之后,free pointer是在object之外,并且多了很多其他的內存,例如red zone、trace和red_left_pad等。這里之所以將FP后移就是因為為了檢測use-after-free問題,當free object時會在將object填充magic num(0x6b)。如果不后移的話,豈不是破壞了object之間的單鏈表關系。

3.1. Red zone有什么用

從圖中我們可以看到在object后面緊接著就是Red zone區域,那么Red zone有什么作用呢?既然緊隨其后,自然是檢測右邊界越界訪問(right out-of-bounds access)。原理很簡單,在Red zone區域填充magic num,檢查Red zone區域數據是否被修改即可知道是否發生right oob。

可能你會想到如果越過Redzone,直接改寫了FP,豈不是檢測不到oob了,并且鏈表結構也被破壞了。其實在check_object()函數中會調用check_valid_pointer()來檢查FP是否valid,如果invalid,同樣會print error syslog。

3.2. padding有什么用

padding是sizeof(void *) bytes的填充區域,在分配slab緩存池時,會將所有的內存填充0x5a。同樣在free/alloc object的時候作為檢測的一種途徑。如果padding區域的數據不是0x5a,就代表發生了“Object padding overwritten”問題。這也是有可能,越界跨度很大。

3.3. red_left_pad有什么用

red_left_pad和Red zone的作用一致。都是為了檢測oob。區別就是Red zone檢測right oob,而red_left_pad是檢測left oob。如果僅僅看到上面圖片中object layout。你可能會好奇,如果發生left oob,那么應該是前一個object的red_left_pad區域被改寫,而不是當前object的red_left_pad。如果你注意到這個問題,還是很機智的,這都被你發現了。為了避免這種情況的發生,SLUB allocator在初始化slab緩存池的時候會做一個轉換。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

如果你去追蹤kmem_cache_create(),在calculate_sizes()中布局object。區域劃分的layout就如同你看到上圖的上半部分。當我第一次看到這段代碼的時候,我也這么認為。實際上卻不是這樣的。在struct page結構中有一個freelist指針,freelist會指向第一個available object。在構建object之間的單鏈表的時候,object首地址實際上都會加上一個red_left_pad的偏移,這樣實際的layout就如同圖片中轉換之后的layout。為什么會這樣呢?因為在有SLUB DEBUG功能的時候,并沒有檢測left oob功能。這種轉換是后續一個補丁的修改。補丁就是為了增加left oob檢測功能。

做了轉換之后的red_left_pad就可以檢測leftoob。檢測的方法和Red zone區域一樣,填充的magic num也一樣,差別只是檢測的區域不一樣而已。

4. SLUB DEBUG原理

經過上一節分析應該很清楚了大概的原理了。從high level考慮,SLUB就是利用特殊區域填充特殊的magic num,在每一次alloc/free的時候檢查magic num是否被意外修改。

4.1. magic num

SLUB 中有哪些magic num呢?所有使用的magic num都宏定義在include/linux/poison.h文件。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

SLUB_RED_INACTIVE和SLUB_RED_ACTIVE用來填充Red zone和red_left_pad,目的是檢測oob。POISON_INUSE用來填充padding區域,同樣可以用來檢測oob,只不過是poison overwrite。POISON_FREE作用是檢測use-after-free問題。POISON_END是object可用區域的最后一個字節填充。

4.2. slab緩存池填充

當SLUB allocator申請一塊內存作為slab 緩存池的時候,會將整塊內存填充POISON_INUSE。如下圖所示。

然后通過init_object()函數將相關的區域填充成free object的情況,并且建立單鏈表。注意freelist指針指向的位置,SLUB_DEBUG on和off的情況下是不一樣的。主要就是3.3節提到的轉換關系。為什么這里填充成freeobject的情況呢?其實就是為了假裝我這里都是free的object,也是符合情理的。object初始化流程如下。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

4.3. free objectlayout

剛分配slab緩存池和free object之后,系統都會通過調用init_object()函數初始化object各個區域,主要是填充magic num。free object layout如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

red_left_pad和Red zone填充了SLUB_RED_INACTIVE(0xbb);

object填充了POISON_FREE(0x6b),但是最后一個byte填充POISON_END(0xa5);

padding在allocate_slab的時候就已經被填充POISON_INUSE(0x5a),如果程序意外改變,當檢測到padding被改變的時候,會output error syslog并繼續填充0x5a。

4.4. alloc object layout

當從SLUB allocator申請一個object時,系統同樣會調用init_object()初始化成想要的模樣。alloc object layout如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

red_left_pad和Red zone填充了SLUB_RED_ACTIVE(0xcc);

object填充了POISON_FREE(0x6b),但是最后一個byte填充POISON_END(0xa5);

padding在allocate_slab的時候就已經被填充POISON_INUSE(0x5a),如果程序意外改變,當檢測到padding被改變的時候,會output error syslog并繼續填充0x5a。

alloc object layout和free object layout相比較而言,也僅僅是red_left_pad和Red zone的不同。既然該填充的數據都搞定了,下面就是如何檢查oob、use-after-free等問題了。

4.5. out-of-bounds bugs detect

下面使用demo例程來說明oob檢測。我們使用kmalloc分配32 bytes內存,然后制造越界訪問第33個元素,必然會越界訪問。由于kmalloc是基于SLUB allocator,因此此bug可以檢測。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

運行后的object layout如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

我們可以看到,Red zone區域本來應該0xcc的地方被修改成了0x88。很明顯這是一個Redzone overwritten問題。那么系統什么時候會檢測到這個嚴重的bug呢?就在你kfree()之后。kfree()中會去檢測釋放的object中各個區域的值是否valid。Redzone區域的值全是0xcc就是valid,因此這里會檢測0x88不是0xcc,進而輸出errorsyslog。kfree()最終會調用free_consistency_checks()檢測object。free_consistency_checks()函數如下。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

check_valid_pointer()負責檢測object的free pointer指針數據是否valid。oob是有可能導致這種情況得到發生。

on_freelist()檢測object是否已經free,可以檢測多次free的bug。

check_object()會檢測Red zone區域的數值是否被改變,因此這里就會報出bug。

如果是左邊界越界訪問,是否也同樣可以檢測出呢?可以測試以下demo例程。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

運行后的object layout如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

檢測方法大同小異,這里也是最終在free_consistency_checks()函數中通過檢測red_left_pad區域發現left oob問題。

可能你會想如果我只申請內存不釋放的話,這個bug還能檢測到嗎?其實這里是不行的。我們只能借助slabinfo工具主動觸發檢測功能。所以,這也是SLUB DEBUG的一個劣勢,它不能做到動態監測。它的檢測機制是被動的。

4.6. use-after-free bugs detect

如果是use-after-free問題,我們該如何檢測呢?首先上demo例程。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

運行之后object layout如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

還記得上面說的嗎?SLUB DEBUG是被動的。因此這里就要選擇slabinfo工具了。命令中斷輸入slabinfo –v即可。slabinfo檢測的原理也很簡單,便利所有已經釋放的object,檢查object區域是否全是0x6b(最后一個字節oxa5)即可,如果不是的話,自然就是use-after-free。

5. slabinfo

我們看一下slabinfo –v命令的實現方式以及檢查的流程。slabinfo源碼位于tools/vm/slabinfo.c文件。slabinfo –v命令執行流程如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

針對系統中每一個slab都會執行set_obj()函數。set_obj()代碼如下:

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

set_obj()參數name傳遞的是“validate”,n傳遞的是1。作用就是向/sys/kernel/slab// validate節點寫“1”觸發slab檢測功能。根據validate節點找到寫入口函數validate_store()。調用函數執行流如下圖所示。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

validate_slab()代碼如下:

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

check_slab()會調用slab_pad_check()檢查slab padding區域。slab padding和object里面的pading不是一回事。如果說從buddy system分配的頁按照SLUB規則平分成很多object,那么有可能不能整除,那么剩下的unused區域就是slab padding。valid的數值是0x5a。如下圖所示。

get_map()利用bitmap標記所有的available object。例如,slab緩存池一共有10個對象,按地址大小排序標號0-9(相當于index)。假設5和8號object已經被分配出去。那么bitmap中除了bit5和bit8以為,其余位為1。

第一個for循環遍歷所有的available object是否有oob、use-after-free、object padding overwritten等問題發生。

第二個for循環遍歷所有已經分配出去的object是否發生oob問題。

基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11229

    瀏覽量

    208927
  • 內存
    +關注

    關注

    8

    文章

    3002

    瀏覽量

    73885
  • DEBUG
    +關注

    關注

    3

    文章

    90

    瀏覽量

    19886

原文標題:宋牧春: Linux內核slab內存的越界檢查——SLUB_DEBUG

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    深度解析內存管理SLUB DEBUG原理

     SLUB DEBUG檢測oob問題原理也很簡單,既然為了發現是否越界,那么就在分配出去的內存尾部添加一段額外的
    發表于 10-02 11:30 ?3926次閱讀
     深度解析<b class='flag-5'>內存</b>管理<b class='flag-5'>SLUB</b> <b class='flag-5'>DEBUG</b>原理

    關于內存釋放

    剛看到壇子里有個朋友說兩個while循環就讓內存占用達到100%,而一個就沒問題,我懷疑是死循環或者內存釋放,大家有興趣的也來討論下,關于labview內存
    發表于 06-15 09:05

    linux的內存釋放操作

    在Linux系統下,我們一般不需要去釋放內存,因為系統已經內存管理的很好。但是凡事也有例外,有的時候內存會被緩存占用掉,導致系統使用SWA
    發表于 07-26 07:05

    C語言內存操作的陷阱!你踩過坑嗎?

    1、返回局部變量的地址,或者返回指向局部變量的指針int *stackref(){ int val; return &val;}2、引用已經釋放了的堆內存(野指針)int
    發表于 09-26 16:02

    【原創】常見的內存錯誤及對策

    ,這是很危險的,也是經常出錯的地方。4、內存已經釋放了,但是繼續通過指針來使用一般會有以下三種情況:①就是上面所說的,free(p)之后,繼續通過p指針來訪問
    發表于 08-24 11:34

    如何在Win 2003中安全的釋放內存

    如何在Win 2003中安全的釋放內存 經常看到有朋友在論壇上訴苦說需要釋放內存,其實如果你安裝了Windows 2003的話,那么并不需要尋求
    發表于 01-29 11:36 ?676次閱讀

    如何釋放電腦內存

    如何釋放電腦內存 電腦在用久以后,大家是不是感覺到速度越來越慢?想釋放內存還必須重啟計算機,是不是很麻煩?本人介紹一種
    發表于 03-01 10:23 ?2605次閱讀

    內存泄漏的檢測方法

    內存泄露(Memory leak)指的是,在程序中動態申請的內存,在使用完后既沒有釋放,又無法被程序的其他部分訪問內存泄露是在開發大型程序
    的頭像 發表于 06-20 11:01 ?3124次閱讀

    進程虛擬內存布局以及進程的虛擬內存分配釋放流程,涉及的代碼

    我們計劃通過一系列文章來介紹虛擬內存分配/釋放,缺頁處理,內存壓縮/回收,內存分配器等知識,梳理虛擬內存的管理。本章節結合代碼介紹進程虛擬
    的頭像 發表于 06-28 09:38 ?4050次閱讀

    一文詳解Linux內存檢測技術

    不同的工具有不同的側重點,本章主要從slub_debug、kmemleak、kasan三個工具介紹。
    的頭像 發表于 05-20 18:00 ?3081次閱讀
    一文詳解Linux<b class='flag-5'>內存</b><b class='flag-5'>檢測</b>技術

    slub分配內存原理 slub數據結構之間關系

    slub的數據結構相對于slab來說要簡單很多。并且對外接口和slab兼容。所以說,從slab的系統更換到slub,可以說是易如反掌。
    發表于 04-03 09:20 ?599次閱讀

    valgrind檢測內存問題的原理

    valgrind 是一個提供了一些 debug 和優化的工具的工具箱,可以使得你的程序減少內存泄漏或者錯誤訪問。valgrind 默認使用 memcheck 去檢查內存問題。memch
    的頭像 發表于 05-23 09:30 ?2281次閱讀
    valgrind<b class='flag-5'>檢測</b><b class='flag-5'>內存</b>問題的原理

    free在釋放內存的時候,為什么不需要指定內存的大小?

    malloc在申請內存的時候,需要指定內存的大小,申請成功則返回這塊內存的地址,但是free的時候,只需要指定釋放內存的起始地址,系統就知
    的頭像 發表于 09-15 17:05 ?1605次閱讀
    free在<b class='flag-5'>釋放</b><b class='flag-5'>內存</b>的時候,為什么不需要指定<b class='flag-5'>內存</b>的大小?

    如何使用valgrind對代碼進行內存泄露檢測

    代碼可能存在 內存泄露 怎么辦? 使用 valgrind 可以對代碼進行內存泄露檢測。 valgrind下載安裝 安裝: 1 、tar –jxvf valgrind- 3 . 21 . 0
    的頭像 發表于 10-04 14:56 ?798次閱讀
    如何使用valgrind對代碼進行<b class='flag-5'>內存</b>泄露<b class='flag-5'>檢測</b>

    常用的解決內存錯誤的方法

    1. 內存管理功能問題 由于C++語言對內存有主動控制權,內存使用靈活和效率高,但代價是不小心使用就會導致以下內存錯誤: ? memory
    的頭像 發表于 11-10 15:29 ?1453次閱讀
    常用的解決<b class='flag-5'>內存</b>錯誤的方法