在使用pcaplib 做針對7號信令 TCAP層開發的時候,針對Indefinite form容易發生一個數組越界的隱性問題的一個說明。
前一段時間出了一個Release 失敗的問題,讓客戶大為光火,上線失敗的確是是非常讓人難堪的問題。
在這裡把教訓記下來,也希望看到的兄弟不要重蹈我的覆轍。
一片分析文章,因為沒有代碼可能比較生澀,希望能協助到有用的人。
參考文檔 :
[1] Q.773 : Transaction capabilities formats and encoding ——ITU (International Telecommunication Union)
1. 項目背景
我們的項目是是針對核心網的7號信令的離線pcap檔案進行解析,然後進行通訊統計的功能模組。
這個功能模組以前就有,但是以前的系統沒有針對TCAP協議的 Indefinite form進行處理。
我們這次的開發就是針對
※TCAP是 7號信令協議棧中的Transcation Control Application Part 也就是控制事務的協議層。
2.技術背景
在這裡針對 TCAP 協議裡的BER編碼做一個說明。
圖 1 TCAP層訊息構成
我們可以看到這裡面 基本上都是以 xxxTag, xxx Length, Data 三部分 構成的。
ITU定下來3種基於BER( Basic Encoding Rules)來對 TCAP層訊息的長度來進行進行編碼,也就是剛才說道的xxx Length的部分,這一部分標識的
(1) Short Form
第一種是 Short Form 顧名思義 ,這個是用來傳輸較少資料的,這個資料是多少呢?
圖 2 SHORT FORM
在BER的編碼中每一個 ANS. 1類型都被描述成一個8 bit的字串 Octet. 。圖2 就描述的是一個Octet 這個 Octet就代表著 剛才所提到 xxx Length的部分,描述著後面 Data部分的長度。
從圖上我們可以看到,Short Form 所能描述的後面Data的長度(Octet個數相當於位元組)就是。
8 bit - 1bit (最高位的0一位)= 7 bit 也就是 2的7次方 128個Octet
(2) Long Form
第二種是 Long Form
圖 3 Long FORM
和Short Form 不一樣 最高位是1,後7位則代表的是Data長度的長度。也就是說如果xxx Length位置上出現比 0x80 大的資料,那麼大出的部分也就是後7位的組成的
數位大小代表了Data長度的數值。
例: length位置開始 第一個Octet = 10000001 (0x81) 第二個 Octet = 00001111
Data長度是多少呢? 應該是 15,可是為什麼不是1呢,這是以為long form和short form一樣的地方是放的是Data長度的長度,也就是
0x81 - 0x80 = 1 ,這裡1的意思說後面的一個Octet代表的是Data長度。
(3) Indefinite Form
圖 4 INDIFINITE FORM
Indefinite Form 和 short form 和long form 不一樣的地方是,它沒有Length來標識整個Data的長度,其結構有點像XML的結構,採用定位標識來標識出資料的結尾。
從圖4上我們可以看到, Length的部分沒有,L =10000000 標識為Indefinite form資料的開始。EOC TAG和 EOC Length代表著 Indefinite form的結束。
而且Indefinite form 裡面還可以嵌套Indefinite form
3.Bug內容:
我拿到的以前代碼,因為沒有對 Indefinite form 進行處理。所以在長度上都是對Length解析,然後根據長度來取出資料。以前的代碼在取出IMSI的時候,由於TC-COTINUE是沒有IMSI的資料,這個時候IMSI TAG是並不存在。既存的處理是 以 sprintf(buf, "%.2x", pcap_data[position])嘗試判斷一下Tag是否存在,如果存在就 sprintf(buf, "%.4u", pcap_data[position])取出長度。由於TAG不存在,一般情況下會判斷Tag不存在。
但是 有些時候 pcaplib的pcap_next_ex()取出來的數組,是一個動態分配的記憶體,很有可能在IMSI Tag不存在的情況下,在IMSI TAG應該出現的地方出現一個和IMSI TAG一樣的值,這種情況下,既存的處理會認為這個地方就是IMSI TAG,然後就到後面去取長度。在Short Form,Long Form的情況下,即使錯誤取出的長度也只是128~ 2的1024次方
那麼去取資料的時候 pcap_data[position]的position 最大值衝破記憶體限制的可能性比較小。
但是對於想定情況處理了Indefinite form 之後,這個有可能出錯的長度就不可預知了。從一個0x80開始到連續 兩個 0x00 結束,那麼這個值就有可能變的無比巨大,如果再按照這個Length 從記憶體取東西就有可能出錯。
pcap_next_ex(pcapfile, &header, &pcap_data)caplen = header->caplen;
所以一定要在每次取Tag 和Length的時候用 pcaplib 提供的caplen屬性來做check ,看position超過了 pcap_data 的邊界沒有。要不然就有可能悲劇,關鍵是在資料量小的情況下,這個錯誤不一定能出來。