Efficient Protection of Path-Sensitive Control Security Ren Ding , Chenxiong Qian, Chengyu Song*, Bill Harris, Taesoo Kim, Wenke Lee Georgia Tech, UC Riverside*
What is Control Flow? The order of instruction execution Only limited sets of valid transitions 2
What is Control Hijacking? 3
Control Flow Attacks Still Exist... ATTACK Year DEFENSE Stack smashing Reported Software Flaws - Buffer Errors 1996 Ret2libc 1997 800 Format string 1998 Stack guard canaries Heap overflow Integer overflow 700 2000 Stack cookies W^X 2001 Shadow stack 600 ASLR Info leak to bypass ASLR 2002 500 2003 ProPolice PointGuard 2005 CFI 400 Softbound 2009 CETS 2010 300 Cfimon 2011 Control-flow locking Kbouncer 2013 200 Modular CFI 2014 History-hiding ROP ROPecker Hardware-assisted CFI 100 CPI Opaque CFI 2015 Control-flow bending Per-Input CFI Missing the pointer 0 Context-Sensitive CFI Control Jujutsu 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 COOP Griffin 2017 4 FlowGuard
Control Flow Integrity (CFI) Lightweight Runtime Enforcement Pre-computed valid sets: points-to analysis Limitations: over-approximation for soundness! 5
Motivating Example 1 void dispatch() { 2 void (*handler)( struct request *) = 0; Parse request 3 struct request req; Assign “handler” fptr 4 5 while (1) { o If request from admin: 6 parse_request(&req); 7 handler() = priv — 8 if (req.auth_user == ADMIN) { o else: 9 handler = priv; handler() = unpriv 10 } else { — 11 handler = unpriv; Strip request args 12 // NOTE. buffer overflow 13 strip_args(req.args); Handle request 14 } 15 16 handler(&req); 17 } 18 } 6
Motivating Example 1 void dispatch() { high 2 void (*handler)( struct request *) = 0; 3 struct request req; 4 Shellcode 5 while (1) { req dispatch () 6 parse_request(&req); handler 7 libc.so 8 if (req.auth_user == ADMIN) { ret addr 9 handler = priv; 10 } else { 11 handler = unpriv; priv() … 12 // NOTE. buffer overflow … strip_args () 13 strip_args(req.args); 14 } unpriv() 15 low 16 handler(&req); 17 } 18 } 7
Limitation of Traditional CFI • Computes valid transfer sets at 1 void dispatch() { 2 void (*handler)( struct request *) = 0; each location (lack dynamic info) 3 struct request req; 4 5 while (1) { 6 parse_request(&req); parse_request() 7 8 if (req.auth_user == ADMIN) { 9 handler = priv; if admin: priv() else: unpriv() 10 } else { 11 handler = unpriv; 12 // NOTE. buffer overflow 13 strip_args(req.args); handler() 14 } 15 16 handler(&req); 17 } priv() & unpriv() 18 } 8
Per-Input CFI: Most Precise Known CFI • Relies on static analysis for soundness • Instrumentation required • Enable valid target based on execution history for addresses that are taken 9
Limitation of Per-Input CFI • Once transfer targets enabled, 1 void dispatch() { 2 void (*handler)( struct request *) = 0; cannot be eliminated 3 struct request req; 4 5 while (1) { 6 parse_request(&req); parse_request() 7 8 if (req.auth_user == ADMIN) { 9 handler = priv; if admin: priv() else: unpriv() 10 } else { 11 handler = unpriv; 12 // NOTE. buffer overflow 13 strip_args(req.args); handler() 14 } 15 16 handler(&req); 17 } priv() & unpriv() priv() 18 } 10
PITTYPAT: Path-Sensitive CFI • At each control transfer, verify 1 void dispatch() { 2 void (*handler)( struct request *) = 0; based on points-to analysis of 3 struct request req; whole execution path 4 5 while (1) { 6 parse_request(&req); parse_request() 7 8 if (req.auth_user == ADMIN) { 9 handler = priv; 10 } else { if admin: priv() else: unpriv() 11 handler = unpriv; 12 // NOTE. buffer overflow 13 strip_args(req.args); 14 } handler() 15 16 handler(&req); 17 } unpriv() priv() 18 } 11
Assumptions Current approach only examines control security Non-control data is out of scope Not a memory safety solution 12
Challenges Collecting executed path information and share for analysis efficiently Trace information cannot be tampered Compute points-to relations online both efficiently and precisely 13
Our Solution Per Challenge Intel Processor Trace (PT) Incremental Online Points-to Analysis 14
Intel Processor Trace Low-overhead commodity hardware Compressed packets to save bandwidth CR3 filtering Trace information shared & protected efficiently 15
Incremental Points-to Analysis Input: LLVM IR of target program o Metadata of mapping between IR and binary o Runtime execution trace o Output: points-to relations on a single execution path 16
Things Differentiate Our Analysis Traditional static points-to analysis reasons about all paths for soundness Instead, we only reasons about points-to relation on one single path Maintain shadow callstack of instructions executed Most precise enforcement based on control data only 17
System Overview Monitor Module: Kernel-space driver for PT o Shares taken branch information o Analyzer Module: User-space o Updates points-to relation based on trace o 18
Challenging Language Features • Signal handling • Setjmp/Longjmp • Exception Handling 19
Signal Handling ; Function Attrs: nounwind uwtable define void @SIGKILL_handler(i32 %signo) #0 { entry: ... if.then: ; preds = %entry ... if.else: ; preds = %entry ... if.end: ; preds = %if.else, %if.then ret void } ; Function Attrs: nounwind uwtable define i32 @main() #0 { entry: %call1 = call void (i32)* @signal(i32 9, void (i32)* @SIGKILL_handler) #3 ret i32 0 } 20
Setjmp/Longjmp ; Function Attrs: nounwind uwtable define void @hello() #0 { entry: ... call void @longjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @resume_here, i32 0, i32 0), i32 1) #4 ... } ; Function Attrs: nounwind uwtable define i32 @main() #0 { entry: ... %call1 = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @resume_here, i32 0, i32 0)) #5 ... 21
Exception Handling ; Function Attrs: norecurse uwtable define i32 @main() #4 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { entry: ... %call = invoke i32 @_Z3foov() to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry br label %try.cont lpad: ; preds = %entry %0 = landingpad { i8*, i32 } catch i8* bitcast (i8** @_ZTIi to i8*) catch i8* bitcast (i8** @_ZTIc to i8*) catch i8* null ... 22
Optimizations on Analysis Only analyzing about calling context Maintains current executing IR block along with execution To avoid decoding of PT traces and translation from binary address o to IR Only analyze control-relevant functions and instructions 23
Evaluation Are benign applications satisfying path-sensitive CFI less susceptible to control hijacking attacks? Do malicious applications that satisfy weaker CFI mechanisms fail to satisfy current solution? Can we achieve path-sensitive CFI efficiently? 24
Forward Edge Points-to Set Size 25
RIPE Contains various vulnerabilities that can be exploited to hijack control flow Passed all 264 benchmark suites that compiled in the testing environment 26
Performance Overhead 50% pi-CFI PittyPat 40% 30% 20% 12.73% 10% 3.3% 0% 27
Limitations Non-control data corruption can not be detected Not reasoning about field sensitiveness for points-to analysis Performance might not be ideal as a CFI solution 28
Conclusion Define path-sensitive CFI Deploy practical mechanism for enforcement Strictly stronger security guarantees Acceptable runtime overhead in security critical settings 29
Recommend
More recommend