• 沒有找到結果。

3. 系統架構與設計

3.2. 建立基礎資料

本階段主要目的在於建立實驗環境以供後續階段之使用,在此分為四個部份解說。

3.2.1. 架立版本資料庫

由於開放原始碼運動近幾年來廣為發展,有愈來愈多的專案公開於網路上,除了特 定版本的原始碼公開外,更有許多專案將其開發歷程(revision history)完全公開,而這些 歷程通常存於版本資料庫(revision history repository)中,目前開放原始碼常見的版本控制 系統(Version Control System)如第二章相關研究所述,有 CVS(concurrent version

system)[30]、SVN(subversion)[11]以及 git(使用於 linux kernel 發展)[31]等,每個專案有其不 同的發展歷史、環境與成員,因此可能會使用不同的系統。

由於本研究需使用原始碼與版本資訊,並於其中進作大量的操作行為,由於其資料 庫幾乎都架設於國外,若使用外界版本資料庫做為直接資料來源,將會使本研究所需之 動作在執行時間上造成困難,因此本研究需在本地端重新複製一份資料庫,而 SVN 在 資料庫複製上較 CVS 有其優勢,只要數行指令即可將遠端資料庫複製回本地,而 CVS 則不提供複製之功能,通常還需要其它工具的協助,如 CVSup[31]或 SVN-Mirror[32]。

基於以下的幾個原因,本研究以 OpenSSH[8]做為分析標的:

1. 開發歷史長且完整。從 1999 年開始發展,至 2006 年六月廿二日止總計有 151307 次的更動紀錄,平均每週約有四百餘次更動發生;

2. OpenSSH 在程式安全上較被關注,因此有眾多資料可供參考並據以分析,另外 也有相關的研究[4]是針對 OpenSSH 進行,可供本文分析之參考;

3. 提供 CVSup 之服務,在實驗環境架設上較為便利。

OpenSSH 目前版本(4.3-p2)的總行數(Line Of Code, LOC)約為十四萬行。

3.2.2. 修改與編譯原始碼

本階段的重點在於將原始碼中插入監測用的函式,用以紀錄程式中的部份語句 (statement)。在第二章相關研究中曾討論數種修改(instrumentation)工具,各項工具有其侷 限,其中如

1. GCC 雖便於使用,但是無法用以監控變數(如函式參數或回傳值);

2. TXL 需針對程式中各種情況(scenario)而撰寫不同的轉換方式,當程式碼稍有變 化即需要增加撰寫工作,故所需之作業甚為繁複;

3. 使用商用軟體成本過高。

故本研究經比較後決定使用 CIL[25]做為本階段使用之工具,並以 CIL 所內建之模 組為基礎,擴充其內容以符合本研究之需求,修改增加的功能如下段所述。

本研究注意的語句為以下二種情形:

1. 語句中含有函式呼叫(function call);

2. 承上之情形,和該函式呼叫相關之變數(variable)。

對於情形二所述變數,本文著重在同一語句內與函式呼叫有關的參數及函式回傳值 (或稱 L-value)。

3.2.2.1.

演算法設計與實作

本演算法以 Ocaml 實作於 CIL 系統中,以模組化的方式寫成,以供日後方便使用,

其設計如下:

以下舉實例說明:

While (not finishing traverse) {

If (statement contains function_calls) { foreach function_calls:

write2log(“CALL %s”, function_name) foreach argument in function:

if argument is symbol:

write2log(“ARGU %s”, argument) write2log(“DEP %s”, return_value)

}

Next statement;

}

圖 10 instrumentation 演算法

圖 11 instrumentation 實施例

如上圖所示, 研究者自行撰寫一函示(write2log,即圖中反白之部份)供監測使用,

其功能在於記錄執行時期之訊息,並儲存於磁碟機等永久性儲存裝置上。目前本研究記 string 之困擾,舉例來說,當 instrumentation 程式遇到 foo("PRINT THIS")時,

照上述之演算法會轉換成:

write2log("CALL %s", "foo");

write2log("ARGU %s", ""PRINT THIS"" ); //invalid statement foo("PRINT THIS");

顯而易見的是第二行為不合法之語句,此情形將會造成 instrumentation 失敗,

在此所提出的解決方法是不記錄某些型態的參數,例如含有雙引號或單引號之 參數。

2. 在實作自行撰寫之 write2log 時,最早的做法是一有事件發生時即將內容記錄於 檔案中,然而因為寫入動作太頻繁,導致程式執行速度大為降低,為改善效能,

之後改為累積一定數量的事件後,再行寫入記錄檔,但這時卻造成另一個問題。

當程式結束前,留在記憶體(memory)中的 log 尚未累積到可寫入記錄檔的 量,然而程式一結束時,記憶體中的資料即行消失,留存於記憶體中的事件 int flag, *index;

flag = lock(index) if (flag) {

… //Do Something unlock(index) }

instrumentation

int flag, *index;

write2log(“CALL %s”, “lock”);

write2log(“ARGU %s”, “index”);

write2log(“DEP %s”, “flag”);

flag = lock(index) if (flag) {

… //Do Something

write2log(“CALL %s”, “lock”);

write2log(“ARGU %s”, “index”);

unlock(index) }

記錄也跟著消失,此時 log 檔便佚失最後的一次應寫入記錄。為了解決此問 題,研究者使用 atexit()函式,其工作原理是在程式執行中先規劃結束前所要 執行的函式,當程式快結束時,即行呼叫事先所規劃之函式。我們在程式結 束前透過 atexit()函式將記憶體中的事件記錄強制寫入磁碟,而後結束程式。

3.2.2.3. OPENSSH COMPILATION

本小節的目的在說明如何將以上發展的監測工具應用到實際專案中,這裡我們擇選 以 OpenSSH 做為分析的對象,在實作上有二個需克服的問題:

1. 由於研究者自行撰寫之監測函式,其內部也含有個多個函式呼叫,其呼叫是不

在 OpenSSH 之正常執行序列中,為避免監測程式監測其本身,故在

instrumentation 之前即將監測程式編譯(compiler)成目的檔(object file)格式,且不 進行 Link。

2. OpenSSH 使用 GCC 中 attribute 的功能,但是有些語法並不是 CIL 所支援的,所 以在 CIL 分析分程中會造成 CIL 錯誤。在專案中共有五處地方發生此類問題,

在刪除這些 attribute 標示後,專案即可正常編譯。

3.2.3. 執行程式

使用動態分析需注意測試資料對整體程式碼的涵蓋率,惟目前並無針對整體程式的 自動化測試工具,近年來發展的自動化測試工具,如 DART[33],僅能針對單一函式做 單元測試(unit test),無法自動化進行整體程式測試,在衡諸現實情況後,使用 openssh 內建迴歸測試工具做為測試資料的來源。

相關文件