Solaris中檢測內存異常訪問

Solaris中檢測內存異常訪問

本文介紹了在solaris中如何利用核心內存分配的調試功能檢測內存異常(corruption)。引起內存異常的常見操作包括:
  • 越界訪問
  • 訪問未被初始化的數據
  • 訪問已被釋放的內存
我們用前一篇blog中生成的核心core文件爲例,一步步進行分析。

核心緩存(Kernel Memory Cache)

首先回憶一下,爲了發現內存泄漏運行mdb的::findleaks其輸出爲:

> ::findleaks
CACHE
LEAKED
BUFCTL
CALLER
... ...
dac32030
1
d4ec7748 tleak_open+0x35

第一列是發生了內存泄漏的cache地址。solaris的核心內存分配機制把內存分成若干cache。每一cache由一組固定大小的buffer組成。 kmem_alloc(9F)或kmem_zalloc(9F)將從cache中獲得所需內存。cache由數據結構kmem_cache_t (kmem_impl.h)定義。拿前文中的核心core文件做例子,用mdb的::kmastat命令看一下核心中有哪些cache。

> ::kmastat
cache
name
buf
size
buf
in use
buf
total
memory
in use
alloc
succeed
alloc
fail
----------
------
-------
-------
--------
------
----
... ... ...
kmem_alloc_8
8
110939
111010
2674688
205353
0
kmem_alloc_16
16
59421
59520
1904640
91402
0
kmem_alloc_24
24
25723
25806
1036288
79258
0
kmem_alloc_32
32
10552
10625
512000
28811
0
kmem_alloc_40
40
4288
4380
245760
17876
0
kmem_alloc_48
48
52219
52224
3342336
64754
0
kmem_alloc_56
56
653
672
49152
4127
0
kmem_alloc_64
64
337
352
45056
47603
0
kmem_alloc_80
80
50732
50736
4947968
60466
0
kmem_alloc_96
96
120
144
16384
1122
0
kmem_alloc_112
112
163
192
24576
1363
0
... ... ...

其中,cache的名字kmem_alloc_後面的數字是該cache中buffer的大小。如kmem_alloc_8表示這個cache中的 buffer大小是8個字節。接下來我們用::kmem_cache命令簡要查看上文中產生了內存泄漏的cache(也可以用宏%CONTENT%lt; kmem_cache打印數據結構kmem_cache_t)。

> dac32030::kmem_cache
ADDR
NAME
FLAG
CFLAG
BUFSIZE
BUFTOTL
dac32030
kmem_alloc_112
020f
200000
112
192

其中重要的字段是name、bufsize和flag。從name和bufsize可以看出緩衝大小是112字節。flag的值定義在 kmem_impl.h中。0x20f表示(KMF_HASH | KMF_AUDIT | KMF_DEADBEEF | KMF_REDZONE | KMF_CONTENTS)。
mdb的::walk freemem和::walk kmem可分別用來查看chane的空閒和被佔用的緩衝。

> dac32030::walk freemem
d7c91980
d7c91900
d4db0280
d4f05900
d4f05880
... ...
> dac32030::walk kmem
d4db0000
d4db0080
d4db0100
d4db0180
... ...


空閒緩衝(0xdeadbeef)

隨便查看一個空閒緩衝的內容

> d7c91980/32X
0xd7c91980: deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

deadbeef deadbeef deadbeef deadbeef

feedface feedface d7c9dbf8 23272f16

緩衝的內容並不是0,而是0xdeedbeef。當緩衝被釋放後,其內容會被清成0xdeedbeef。這樣,用戶就可以很容易地判斷出訪問的是否是一個已經被釋放的內存。


已分配緩衝(0xbaddcafe)

再隨便查看一個被佔用的緩衝

> d4db0000/32X
0xd4db0000: 0 0 0 0

0 0 0 0

0 0 0 0

0 0 d5077bc0 0

0 0 d20c2df8 0

d20c2dd8 d20c2dd8 d20c2e00 f5f00

0 0 baddcabb baddcafe

feedface 65f9 d4ec7a18
75fcb2f5

緩衝的內容被初始化成0xbaddcafe。根據這個特殊的0xbaddcafe,用戶可以判斷出是否訪問了未被初始化的內存。
一個特殊字段"bb"緊跟在實際要求分配的內存的後面。注意上文中的"baddcabb"而不是"bbddcafe",這是由於x86系統是little endian的系統造成的。


Redzone (0xfeedface)

空閒緩衝和被佔用緩衝有一個共同字段0xfeedface。0xfeedface是Redzone的標誌。它標識了一個buffer的邊界。這裏所說的邊界和上文bb標識的邊界不同。bb表示的是用戶請求分配的內存邊界,而0xfeedface表示的是整個buffer的邊界。0xfeedface和bb 都可用來判斷是否有內存越界訪問。緊跟Redzone的是一些調試數據,這些數據和redzone一起統稱爲buftag區(如下圖所示)。當一個 cache的KMF_AUDIT、KMF_DEADBEEF或KMF_REDZONE標誌位被設,buftag區就會被加到這個cache的每一 buffer後面。

|<------------------------ buffer ----------------------->|<---------- buftag ----------->|
User Data
bb
Unallocated RedZone
Debugging Data
|<------------------- cache_bufsize字節 ------------------->|<--- 64位 ---->|<--- 2個指針 -->|

RedZone:
0xfeedface
encoded index
User data size = encoded_index / 251 字節
Debugging Data:
bcp 指針
bxstat 指針
bcp pointer /^ bxstat pointer = a110c8ed | f4eef4ee

以kmem_alloc_8中的一段內存爲例打印其內容

> dec82b18,6/2Xna
0xdec82b18:
75746572
bb006e72
-- User Data
0xdec82b20:
feedface
6de
-- RedZone
0xdec82b28:
decd3150
7fddf9bd
-- Debugging Data




0xdec82b30:
73666e
baddcabb
-- User Data
0xdec82b38:
feedface
3ed
-- RedZone
0xdec82b40:
decd30d8
7fddf835
-- Debugging Data

RedZone的0xfeedface後面是經過編碼的用戶實際使用的緩衝大小,其計算方法是:

size = redzone_value / 251

則在上述例子中

size = 0x6de / 251 = 7 字節

注意,x86系統是little endian的。


bufctl 指針

Debugging Data中的兩個指針,前一個是指向bufctl的bcp指針,後一個是bxstat指針。bxstat用於校驗bcp指針的有效性。對於以分配的緩衝, bcp XOR bxstat = 0xa110c8ed(allocated);而對於已釋放的緩衝,bcp XOR bxstat = 0xf4eef4ee(freefree)。同樣在上面的例子中

decd3150 /^ 7fddf9bd = a110c8ed

當kmem_flags的KMF_AUDIT位被設置後,bcp指針指向一個kmem_bufctl_audit_t結構。該結構包含使該緩衝在 allocated和freed狀態之間轉換的操作的詳細信息。

>decd3150%CONTENT%lt;bufctl_audit








ADDR
BUFADDR
TIMESTAMP
THREAD

CACHE
LASTLOG
CONTENTS
decd3150
dec82b18
8f2a260f73
d5079980

dac2c030
db00cfc0
0

kmem_cache_alloc_debug+0x256

kmem_cache_alloc+0x1ac

kmem_zalloc+0x4b

dtrace_strdup+0x21

dtrace_probe_create+0x99

fbt_provide_module+0x306
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章