王維晟
(國家計算機網(wǎng)絡(luò)應(yīng)急技術(shù)處理協(xié)調(diào)中心,北京 100029)
專用網(wǎng)卡往往插在一臺服務(wù)器上,它在硬件上接收前端數(shù)據(jù)分發(fā)設(shè)備的數(shù)據(jù),根據(jù)負載均衡原理可以將數(shù)據(jù)發(fā)送到后臺服務(wù)器的多個線程,使服務(wù)器的每個線程都能對數(shù)據(jù)同時進行處理,同時通過專用網(wǎng)卡的軟件系統(tǒng)可以提供數(shù)據(jù)包的預處理功能。專用網(wǎng)卡在網(wǎng)絡(luò)拓撲中的位置如圖1所示。
圖1 專用網(wǎng)卡在網(wǎng)絡(luò)拓撲中的位置
研究發(fā)現(xiàn),熱補丁可以保證當前業(yè)務(wù)不中斷的前提下,對軟件故障進行調(diào)試和修復。針對熱補丁的研究,主要是基于VXWORKS 操作系統(tǒng)下的熱補丁,而專用網(wǎng)卡運行硬件環(huán)境是Intel 64位處理器,軟件是基于Linux 操作系統(tǒng)(Centos 7.2),并按功能封裝成不同動態(tài)庫。文中介紹了熱補丁的相關(guān)技術(shù),并詳細論述了動態(tài)庫熱補丁的實現(xiàn)方案,最后通過一個工程案例表明,專用網(wǎng)卡中使用動態(tài)庫熱補丁,能大大提高軟件故障修復的效率。
改變動態(tài)庫中某個函數(shù)的控制流程,可以使用LD_PRELOAD 提前加載動態(tài)庫;可以修改PLT/GOT 表;可以仿DPDK 構(gòu)造constructor 屬性。本文采用最直接的JMP 跳轉(zhuǎn)指令來實現(xiàn)改變控制流。
動態(tài)庫熱補丁的核心原理如圖2所示,先給當前進程打上動態(tài)庫libpatch.so 這一補丁文件,其中l(wèi)ibpatch.so 文件實現(xiàn)了fun1函數(shù),假設(shè)main 函數(shù)中調(diào)用fun0函數(shù),fun0函數(shù)定義在動態(tài)庫libtest0.so 中,我們通過改變fun0函數(shù)代碼入口處的匯編指令,使其通過JMP 跳轉(zhuǎn)指令,直接跳轉(zhuǎn)到補丁文件中的fun1處執(zhí)行。
圖2 動態(tài)庫熱補丁核心原理
在真實的補丁文件libpatch.so 中,我們實現(xiàn)的是fun1函數(shù),然后通過給進程打補丁,用補丁文件中的fun1 代替進程中的fun1。我們把當前進程稱為遠端環(huán)境,把打補丁的進程稱為本端環(huán)境。動態(tài)庫熱補丁技術(shù)中涉及如下幾個關(guān)鍵技術(shù):獲取遠端環(huán)境上的函數(shù)的地址;執(zhí)行遠端環(huán)境上的的函數(shù);本端補丁文件中符號的重定向。
1.1.1 獲取遠端環(huán)境上的函數(shù)的地址
前文提到,可以通過PTRACE 系統(tǒng)調(diào)用對進程進程跟蹤,另外程序還可以通過dlopen 函數(shù)憑空加載一個動態(tài)庫,并通過dlsym獲取符號地址。令人遺憾的是,dlopen函數(shù)定義在libdl.so中,而專用網(wǎng)卡軟件Linux 環(huán)境甚至都沒有l(wèi)ibdl.so 這一動態(tài)庫的存在。不過值得慶幸的是,幾乎每一個進程都會使用libc.so 這一動態(tài)庫,該動態(tài)庫中有一套__libc 打頭的dlopen 函數(shù)。
每一個動態(tài)庫中符號,在文件的重定向信息中都存在一個符號地址偏移,當加載到內(nèi)存,會給每個動態(tài)庫分配一個基地址,可以通過cat/proc/pid/maps 命令查詢,所以動態(tài)庫中符號地址就等于動態(tài)庫基地址加上重定向信息中符號地址偏移。根據(jù)這一原理,可以計算出__libc_dlopen_mode 函數(shù)在遠端環(huán)境下的地址,如圖3所示。
圖3 遠端函數(shù)地址計算原理
1.1.2 執(zhí)行遠端環(huán)境上的函數(shù)
要想執(zhí)行遠端環(huán)境上的函數(shù),僅僅知道遠端函數(shù)的地址是不夠的,還需要構(gòu)造遠端函數(shù)參數(shù),以及把函數(shù)參數(shù)傳遞給遠端。
在遠端環(huán)境打開補丁文件時,需要將補丁文件路徑作為參數(shù)傳遞給__libc_dlopen_mode 函數(shù),但是因為字符串是保存在.rodata節(jié)中的,而遠端環(huán)境肯定沒有補丁文件路徑這一字符串,所以無法進行字符串重定位。這時需要在遠端調(diào)用mmap 申請一塊遠端內(nèi)存,將函數(shù)參數(shù)字符拷貝到這塊遠端內(nèi)存中。同理,解決補丁文件中包含的所有字符串重定向問題時,都需要進行先mmap 后拷貝操作。
在Intel 64位處理下,當函數(shù)的參數(shù)小于六個時,函數(shù)參數(shù)使用寄存器保存,參數(shù)從左到右依次使用edi,esi,edx,ecx,r8d 和r9d 寄存器,當函數(shù)的參數(shù)大于六個時,多出的參數(shù)使用棧保存。根據(jù)Intel 64位處理器棧是從高地址往低地址生長的,在執(zhí)行遠端函數(shù)時,需要取遠端進程棧的最小地址開始的一片??臻g,供補丁函數(shù)內(nèi)的局部變量以及補丁函數(shù)參數(shù)大于六個時使用。
1.1.3 本端補丁文件中符號的重定向
補丁文件中的函數(shù),不可避免可能會調(diào)用遠端進程中的函數(shù)或者全局變量,這兩種類型的未定義符號需要完成重定向操作,根據(jù)PLT 表和GOT 表相關(guān)原理,需要修改補丁文件未定義符號在GOT 表中存放符號地址。如果補丁文件中未定義符號屬于函數(shù),且該函數(shù)在遠端環(huán)境的靜態(tài)庫中實現(xiàn),那么需要向GOT 表該符號地址中寫入靜態(tài)庫函數(shù)地址;如果補丁文件中未定義符號屬于函數(shù),且函數(shù)在遠端環(huán)境動態(tài)態(tài)庫中實現(xiàn),那么需要向GOT 表該符號地址中寫入動態(tài)庫基地址加上該符號在動態(tài)庫的偏移;如果補丁文件中未定義符號屬于全局變量,且該變量在遠端環(huán)境動態(tài)庫中定義,鑒于dlopen 可以自動修復這些符號的重定向問題,無需手動重定向;如果補丁文件中未定義符號屬于全局變量,且該變量在遠端環(huán)境靜態(tài)庫中實現(xiàn),因為dlopen 對靜態(tài)全局變量無法延后重定向,所以軟件中建議使用GET 或SET 函數(shù)對全局變量取值或賦值。
結(jié)合對PTRACE 相關(guān)原理和動態(tài)庫熱補丁關(guān)鍵技術(shù)的研究,動態(tài)庫熱補丁軟件流程圖如圖4所示。首先解析補丁文件,根據(jù)ELF 文件格式特點,提取補丁文件中需要打補丁的函數(shù)名,以及需要解決重定向問題的未定義符號,然后通過PTRACE 機制,對補丁文件中未定義符號進行重定向修復,最后需要對遠端進程中與補丁函數(shù)同名函數(shù)實施JMP 指令跳轉(zhuǎn)。
圖4 動態(tài)庫熱補丁軟件流程圖
針對補丁文件ELF 解析部分做細致分析,其流程圖如圖5所示。首先需要解析出補丁文件中.rela.plt 節(jié)、.dynstr 節(jié)、.dynsym節(jié)、.symtab 節(jié)和.strtab 節(jié)相關(guān)信息,然后在這些節(jié)中提取到補丁函數(shù)和未定義符號,最后需要訪問遠端進程,遍歷程序頭PHDR,提取補丁文件中函數(shù)和未定義符號對應(yīng)的地址,便于后續(xù)做重定向和函數(shù)跳轉(zhuǎn)。
圖5 補丁文件ELF解析
某公司專用網(wǎng)卡設(shè)備運行進程包含動態(tài)庫libtest.so,該動態(tài)庫中有一個發(fā)包接口中inac_alloc_pkt 函數(shù)沒對入?yún)⒆龊戏ㄐ詸z測,導致系統(tǒng)發(fā)包時會出現(xiàn)異常。
采用熱補丁方式對故障進行修復,首先編寫patch.c 文件,重寫inac_alloc_pkt 接口,新增對參數(shù)合法性檢測。根據(jù)本文的理論,我們編寫代碼制作了自己的二進制補丁工具do_patch,該工具使用方法是“do_patch[待打補丁的進程pid 號]”。接著我們把libpatch.so 和do_patch 文件拷貝到專用網(wǎng)卡所在的Linux 環(huán)境的app 目錄下,利用ps 命令查看當當前環(huán)境網(wǎng)口發(fā)包進程pid 為13456,然后執(zhí)行補丁命令,最終可以看到在沒有更換版本的前提下,遠端環(huán)境上故障得到修復,提高了故障修復的效率。
本文對動態(tài)庫熱補丁相關(guān)的關(guān)鍵技術(shù)和實現(xiàn)做了詳細的闡述,并結(jié)合實際工程案例論證了該方案的可行性。熱補丁技術(shù)不但給故障修復提供了一種手段,而且可以大大減少軟件開發(fā)成本。基于本文Intel 64位處理和Linux 操作系統(tǒng)的動態(tài)庫熱補丁方案,對于其他平臺的熱補丁研究也有一定的參考價值。