標(biāo)簽: DFI
Abstract
用于防止內(nèi)存錯誤
WIT在編譯時刻用過程間指向性分析[23]計算CFG和程序中可能被每個指令寫的一系列objects客燕。然后裝備代碼防止不在靜態(tài)分析所得到的集合里的指令修改objects丁溅,并且保證間接控制跳轉(zhuǎn)符合CFG饼酿。為了提升精確度荆忍,WIT在原始的程序objects間插入小的guards秧廉。我們描述了一個實現(xiàn)生逸,降低了空間和時間損耗,并且可以實用因為它不用進行修改的編譯C和C++程序,沒有誤報艳狐。平均時間損耗7%(CPU密集型benchmarks)。
WIT使用指向性分析對每一個object和寫操作賦一個color坑傅,所有可以被一條指令進行寫操作的objects具有相同的color僵驰,裝備代碼在運行時記錄 object colors并且檢查指令寫到正確的color。存儲單元的color記錄在一個color表中唁毒,當(dāng)objects被分配和釋放時color表會相應(yīng)更新蒜茴。寫檢查在表中查閱正在被寫的存儲單元的color并且檢查是否和寫指令的color一致。如此確保了寫完整性浆西。
WIT也會給間接跳轉(zhuǎn)指令和可能間接跳轉(zhuǎn)的函數(shù)的入口點一個color粉私,由此所有可能被同一條指令call的函數(shù)有相同的color。WIT裝備代碼在color表中記錄函數(shù)colors并且檢查間接跳轉(zhuǎn)指令近零。間接跳轉(zhuǎn)在表中查找目標(biāo)地址的color诺核,并且檢查是否與間接跳轉(zhuǎn)指令的color匹配。這些檢查和寫檢查確保了CFI久信。CFI防止攻擊者繞過我們的檢查并且提供了第二道防線來防御寫檢查沒有探測到的攻擊窖杀。
優(yōu)化:
1. 靜態(tài)分析找到不違反寫完整性的訪問和只有安全訪問的objects,我們只裝備不安全的寫操作裙士,并且對所有安全的objects賦給同樣的顏色入客。這會減少寫檢查的數(shù)目和color表的損耗。降低了需要用來表示color的bit數(shù)。我們所有的實驗中桌硫,一個字節(jié)足夠表示顏色夭咬。
2. color表使用緊湊表示,可以有效率的查找铆隘。color表用一個字節(jié)表示一個8字節(jié)的存儲卓舵,降低了12.5%的空間損耗。
3. Third, we reduce the cost of updating color table entries on function calls. Since most local variables are safe, we only update entries for guards and unsafe variables on function entry and we reset these entries to the color of safe objects on function exit.
2. Overview
WIT有compile-time和runtime兩個部件膀钠。
// Example vulnerable code: simplified Web server with a buffer overflow vulnerability.
1: char cgiCommand[1024];
2: char cgiDir[1024];
3:
4: void ProcessCGIRequest(char* msg, int sz) {
5: int i=0;
6: while (i < sz) {
7: cgiCommand[i] = msg[i];
8: i++;
9: }
10:
11: ExecuteRequest(cgiDir, cgiCommand);
12: }
lines 5-9 存在緩沖區(qū)溢出漏洞掏湾,如果message過長,攻擊者可以重寫cgiDir(里面是CGI commond調(diào)用的可執(zhí)行文件的路徑)來運行任意可執(zhí)行程序(例如shell)托修。這是一個non-control-data attack忘巧,不違反CFI。
使用指向性分析[23]計算程序中每條指令可能修改的obiects睦刃,上例中,分析計算出 the set {i} for the instructions at lines 5 and 8, and the set {cgiCommand} for the instruction at line 7.
為了降低運行時的損耗十酣,提出寫安全檢查來計算安全的指令和objects涩拙。不違反寫完整性的指令為安全指令,如果所有的能修改object的指令都是安全的耸采,那么這個object是安全的兴泥。上例中, instructions 5 and 8 are safe because they can only modify i and, therefore, i is safe. ProcessCGIRequest的參數(shù)也是安全的虾宇。instruction 7 is not safe because it may modify objects other than cgiCommand depending on i’s value.
對所有的安全指令和objects的color設(shè)為0搓彻。上例中, 變量 msg, sz, and i and instructions 5 and 8 are assigned color 0 because they are safe. We assign color 3 to variable cgiCommand and instruction 7, and color 4 to variable cgiDir.
為了降低漏報率(由于指向性分析的不精確導(dǎo)致),在原始程序的不安全的objects之間插入小得guards嘱朽。 Guard objects have color 0 or 1旭贬。這些color永遠(yuǎn)不能賦給不安全的指令以確保WIT能檢測到重寫guards或者安全的objects。
函數(shù)的color集合與objects搪泳,guards的color集合不相交稀轨。這可以防止不安全的指令重寫代碼并且防止代碼區(qū)域外的控制轉(zhuǎn)移。
WIT加了額外的編譯階段來裝備以實現(xiàn)寫完整性和控制流完整性岸军。有四種類型的instrumention:to insert guards, to maintain the color table, to check writes, and to check indirect calls. Guards 8個字節(jié)大小. 上例中, add guards just before cgiCommand, between cgiCommand and cgiDir, and just after cgiDir奋刽。
當(dāng)一個object被分配時,把它存儲位置的color設(shè)為object的color艰赞。上例中, WIT adds instrumentation at the beginning of main to set the color of the storage locations occupied by cgiCommand to 3, the color of the storage for cgiDir to 4, and the color of the storage for the guards around them to 0佣谐。
為了降低更新color表的損耗,初始化所有存儲單元的color表為0方妖,當(dāng)安全的objects被分配時不更新color表狭魂。Instead, we only update the colors for locations corresponding to unsafe objects on function entry. On function exit, we reset color table entries that we updated on function entry to 0. Therefore, there is no instrumentation to update the color table on function entry or exit for ProcessCGIRequest.
上例中, WIT adds write checks only before instruction 7 to check if the location being written has color 3. It does not add write checks before lines 5 and 8 because these instructions are safe。
WIT的防御依賴于指向性分析的精度,比如兩個相同color的object可以相互賦值趁蕊。
WIT可以防御上述例子坞生。The write check before line 7 fails and raises an exception if an attacker attempts to overflow cgiCommand. When i is 1024, the color of the location being written is 0 (which is the color of the guard) rather than 3 (which is the color of cgiCommand). Even without guards, WIT would be able to detect this attack because the colors of cgiCommand and cgiDir are different。
3. Static analysis
We implemented the points-to and the write safety analysis using the Phoenix compiler framework [30]. These analysis operate on Phoenix’s medium level intermediate representation (MIR), which enables them to be applied to different languages and target architectures掷伙。
i = ASSIGN 0
$L6: t273 = COMPARE(LT) _i, _sz
CONDITIONALBRANCH(True) t273, $L8, $L7
$L8: t278 = ADD _msg, _i
t276 = ADD &_cgiCommand, _i
[t276] = ASSIGN [t278]
_i = ADD _i, 1
GOTO $L6
$L7: CALL &_ExecuteRequest,&_cgiDir,&_cgiCommand
Figure 2. Example vulnerable code in mediumlevel intermediate representation (MIR).
We use an inter-procedural points-to analysis due to Andersen [8] that is flow and context insensitive but scales to large programs. It computes a points-to set for each pointer,which is the set of logical objects the pointer may refer to. The logical objects are local and global variables and dynamically allocated objects (for example, allocated with malloc). We use a single logical object to represent all objects that are dynamically allocated at the same point in the program but we do cloning of simple allocation wrappers to improve analysis precision. Our implementation is similar to the one described in [23] but it is field-insensitive rather
than field-based (i.e., it does not distinguish between the different fields in a structure, union, or class). We use Phoenix to compile each source file to MIR and write points-to constraints to a file. The analysis reads the constraints file, computes the points-to sets, and stores them in a file.
In addition, the write safety analysis runs a simple intra-procedural pointer-range analysis to compute writes through pointers that are always in bounds. The instructions that perform these writes are marked safe.
While making the global pass over all source files to collect constraints for the points-to analysis, we also run the write safety analysis. We write unsafe pointers to a file. A pointer is unsafe if it is dereferenced for writing by an unsafe instruction.
We use an iterative process to compute color sets, which include objects and unsafe pointer dereferences that must be assigned the same color because they may alias each other.
WIT uses a similar algorithm to assign colors to functions that may be called indirectly.
4. Instrumentation
4.1 Color table
We implemented WIT for 32-bit x86 machines running Windows.We used several Phoenix plugins [30] to generate WIT’s instrumentation.
WIT maintains a color table that maps memory addresses to colors. The color table must cover the whole user virtual address space and it is accessed often by write and indirect call checks.
To keep the color table small, we divide the virtual memory of the instrumented program into aligned eight-byte slots. The color table is implemented as an array with an eight-bit color identifier for each of these slots.Therefore,it introduces a space overhead of only 12.5%.
We are able to record a single color for each eight-byte slot because we generate code such that no two objects with distinct colors ever share the same slot. It is easy to enforce this requirement for heap objects because they are eight-byte aligned and for functions because they are 16-byte aligned. But since the stack and data sections are only four-byte aligned in 32-bit x86 architectures,we cannot currently force eight byte alignment of objects in these sections without introducing runtime overhead.
Instead,we force unsafe objects and guard objects in the stack and data sections to be four-byte aligned and we insert a four-byte aligned pad after unsafe objects. For an unsafe object of size s, the pad is eight-bytes long if ?s/4? is even and four-bytes long if ?s/4? is odd. We set ?s/8? color table entries to the color of the unsafe object when the pad is four-bytes long and ?s/8?+1 when the pad is eight-bytes long. We should be able to reduce the space overhead when targeting 64-bit x86 architectures because the stack and data sections are eight-byte aligned in these architectures.
Since our points-to analysis does not distinguish between different fields in objects and between different elements in arrays,we always assign the same color to all the elements of an array and to all the fields of an object. Therefore, it is not necessary to change the layout of arrays and objects,which is important for backwards compatibility.
We only require eight bits to represent colors because the write safety analysis is very effective at reducing the number of objects that we must assign colors to. However,it is possible that more bits will be required to represent colors in very large programs. If this ever happens, there are several things we can do. For example, we can increase the size of color table entries to 16-bits and increase memory slot sizes to 16-bytes, or use 8-bit color identifiers at the expense of worse coverage.
The color table can be accessed efficiently. Since there are 2 GB of virtual address space available for the user in Windows XP and Windows Vista, we allocate 256 MB of virtual address space for the color table 2. We rely on the operating system to allocate physical pages for the color table on demand when they are first accessed. The base of the color table is currently at address 40000000h. So to compute the address of the color table entry for a storage location,we take the address of the storage location, shift it right by three, and add 40000000h.
To protect the color table from being overwritten by an attacker, we read-protect the pages in the table that contain the entries for the virtual address range occupied by the table itself. With the base of the table at 40000000h,we protect the pages in the address range 48000000h to 4A000000h (color table原地址:256MB,為40000000h-50000000h)to prevent reads and writes. Since we add checks before unsafe writes and control-flow integrity ensures that the attacker cannot bypass these checks, the attacker cannot overwrite the color table because the write check would trigger a read fault on the protected address range. This technique was first described in [44].
4.2 Inserting guards
The guards are eight-bytes long to match the size of the slots that we record colors for in the color table. The instrumentation to insert these guards is different for the stack, heap, and global data sections.
To insert guards in the stack, we replace the compiler phase that lays out local variables in a stack frame by our implementation. We segregate safe local variables from unsafe ones to reduce the space overhead. First, we allocate contiguous storage for the safe local variables. Then we allocate storage for the guards, pads, and unsafe local variables. This allows us to insert only n+1 guards and pads for n unsafe local variables: the guard that prevents overflows of a variable prevents underflows of the next variable.
In the rare case where a function argument is written by an unsafe instruction, we cannot easily insert guards and pads around it. Therefore, we copy the argument to a local variable and rewrite the instructions to refer to the copy.This local variable is marked unsafe and we insert guards and pads around it.
We mark all heap-allocated objects as unsafe but we do not insert pads or guards around them. The standard heap allocator in Windows Vista, Windows XP SP2, and Windows 2003 inserts an eight-byte header before each allocated object. We use this header as a guard by simply setting its color to 1 in the color table.
We add guards and pads between all variables in the .data section and .bss sections but not in the read-only data section (.rdata).
We plan to implement an optimization that avoids the need for most guards by laying out stack and global objects such that adjacent objects have different colors.