130x Filetype PDF File size 0.63 MB Source: www.usenix.org
SanRazoR: Reducing Redundant Sanitizer Checks in C/C++ Programs Jiang Zhang, University of Southern California; Shuai Wang, HKUST; Manuel Rigger, Pinjia He, and Zhendong Su, ETH Zurich https://www.usenix.org/conference/osdi21/presentation/zhang This paper is included in the Proceedings of the 15th USENIX Symposium on Operating Systems Design and Implementation. July 14–16, 2021 978-1-939133-22-9 Open access to the Proceedings of the 15th USENIX Symposium on Operating Systems Design and Implementation is sponsored by USENIX. SANRAZOR:ReducingRedundantSanitizerChecksinC/C++Programs 1 2∗ 3 3 3 Jiang Zhang Shuai Wang ManuelRigger Pingjia He ZhendongSu 1 2 3 University of Southern California HKUST ETHZurich Abstract Sanitizers are commonly used by developers to find bugs Sanitizers detect unsafe actions such as invalid memory ac- before software deployment. In principle, they could also be cesses by inserting checks that are validated during a pro- used in deployed software, where they terminate program gram’s execution. Despite their extensive use for debugging executions to prevent vulnerabilities from being exploited. and vulnerability discovery, sanitizer checks often induce a In practice, however, the high runtime overhead of sanitizers high runtime cost. One important reason for the high cost is, inhibits their adoption in this application scenario [33,40]. as we observe in this paper, that many sanitizer checks are For example, our study on SPEC CPU2006 benchmarks [34] redundant — the same safety property is repeatedly checked shows that the geometric mean overheads induced by Ad- —leadingtounnecessarily wasted computing resources. dressSanitizer (ASan) [32] and UndefinedBehaviorSanitizer To help more profitably utilize sanitizers, we introduce (UBSan) [8] are, respectively, 73.8% and 160.1% (cf. Sec. 6). SANRAZOR,apracticaltool aiming to effectively detect and It is difficult to reduce the overhead of sanitizer checks and remove redundant sanitizer checks. SANRAZOR adopts a therefore accelerate the execution of sanitization-enabled pro- novel hybrid approach — it captures both dynamic code cov- grams. To date, a number of approaches have been proposed erage and static data dependencies of checks, and uses the aiming at finding unnecessary sanitizer checks with static extracted information to perform a redundant check analysis. analysis [6,9,11,12,15,25,37,39,44,45]. For example, some Ourevaluation on the SPEC benchmarks shows that SANRA- approaches remove array bound checks by checking whether ZORcanreducetheoverhead of sanitizers significantly, from the value range of an index falls within the array size. They 73.8%to28.0–62.0%for AddressSanitizer, and from 160.1% usually perform heavyweight, specialized program analyses to 36.6–124.4% for UndefinedBehaviorSanitizer (depending to reduce specific sanitizer checks. In contrast, ASAP [40], onthe applied reduction scheme). Our further evaluation on the most closely related work to ours, elides sanitizer checks 38 CVEsfrom10commonly-usedprogramsshowsthat SAN- deemedthe most costly based on a user-provided overhead RAZOR-reduced checks suffice to detect at least 33 out of budget. Despite being general and supporting sanitizers of dif- the 38 CVEs. Furthermore, by combining SANRAZOR with ferent implementations, ASAP removes checks irrespective an existing sanitizer reduction tool ASAP, we show synergis- of their importance and may overoptimisitcally remove them, tic effect by reducing the runtime cost to only 7.0% with a resulting in missed vulnerabilities. Thus, prior approaches for reasonable tradeoff of security. reducing sanitizer checks use either sanitizer-specific static analyses (e.g., [9,37]) to remove only semantically redundant 1 Introduction checks, or general heuristics [40] to remove costly sanitizer checks irrespective of their semantics. Software sanitizers are designed to detect software bugs This work explores a new, novel design point — it intro- and vulnerabilities in code written in unsafe languages like duces a general framework, SANRAZOR, for effectively re- C/C++ [33]. A sanitizer typically inserts additional checks movinglikely redundant checks. SANRAZOR is designed as into the program during compilation; at run time, the sani- a hybrid approach. First, it gathers coverage statistics during tizer check terminates the program if it detects unsafe actions a profiling phase (e.g., based on a program’s test suite). It or states (e.g., a buffer overflow). To date, various sanitizers then performs a correlation analysis, employing both the pro- have been designed to help detect vulnerabilities in C/C++ filed coverage patterns as well as static data dependencies, programs [4,8,24,32,35]. to pinpoint and remove checks identified as likely redundant. Like ASAP [40], SANRAZOR is general and orthogonal to ∗Corresponding author. existing sanitizer reduction approaches that focus on specific USENIX Association 15th USENIX Symposium on Operating Systems Design and Implementation 479 sanitizer check implementations [9, 37, 44]. Distinct from ASan. Memory access errors like buffer overflow and use- ASAP,SANRAZORidentifiesandremovessanitizerchecks after-free are severe vulnerabilities in C/C++ programs. ASan that repeatedly checkthesameprogramproperty,whileASAP is designed to detect memory errors [32], and consists of an removes sanitizer checks of high cost and may miss vulnera- instrumentation module and a runtime library. The instru- bilities. Although, like ASAP, SANRAZOR is unsound, i.e., it mentation module allocates shadow memory regions for each mayremovechecksevenwhentheyareunique,inpractice, memoryaddressusedbytheprogram.Italsoinstrumentseach our evaluation results show that it accurately maintains the memoryloadandstoreoperation such that before a memory sanitizer’s effectiveness in discovering defects and provides address a is used to access memory, a will be mapped to its significantly reduced runtime overhead. corresponding shadow memory address sa; the value stored Weevaluate the performance gain of SANRAZOR on the in sa is then loaded and checked to decide whether the access SPECCPU2006benchmark.Theresultsshowthat SANRA- via a is safe. The instrumentation module also allocates a ZOR reduces geometric mean runtime overhead caused by “bad” region for each shadow memory region; directly using ASan from 73.8% to 28.0–62.0% (depending on the differ- a shadow memory address sa in the application code will be ent reduction schemes in SANRAZOR). Similarly, geometric redirected to the “bad” region, which is inaccessible via page meanoverheadincurred by UBSan on SPEC programs is re- protection. The runtime library hooks the malloc function ducedfrom160.1%to36.6–124.4%.Tomeasuretheaccuracy to create poisoned “redzones” next to allocated memories to of SANRAZOR,weevaluate10popularprogramswithatotal detect memory access errors. Similarly, the free function is of 38 known CVEs. Results show that after removing redun- instrumented to put the entire deallocated memory region into dant sanitizer checks, at least 33 CVEs can still be discovered. “redzones.” This ensures that the recently-freed region will ComparedwithASAP,SANRAZORsignificantlyoutperforms not be used by malloc for reallocation. ASAPbydiscoveringmoreCVEswhenachievingthesame UBSan.Undefinedbehaviorscanincurseveresoftware vul- amountofcostreduction. We also explored practical methods nerabilities [41]. UBSan [8] detects a large set of common to combine SANRAZOR and ASAPandreduceruntimecost undefined behaviors in C/C++ code, such as out-of-bounds to only 7.0% with a reasonable tradeoff of security. These access, divided by zero, and invalid shift. We briefly introduce promising results suggest that SANRAZOR could help pro- one undefined behavior that UBSan can detect: motetheadoption of sanitizers in production usage. In sum, Out-of-bounds Array Access Unlike ASan, which relies on wemakethefollowingmaincontributions: shadowmemory,UBSandetectsout-of-boundsarrayaccesses • Attheconceptual level, we introduce the novel approach by comparing each array index with the array size. Consider to reducing performance overhead incurred by sanitizers the sample code below: byidentifying and removing likely redundant checks. By 1 UChar buf[32]; // buf size is 32 reducing sanitizer cost, sanitization-enabled programs can 2 for(i = 0; i < nBuf; i++) be executed faster, making sanitizer adoption in production 3 out[i] = buf[nBuf-i-1]; use more practical. • Atthetechnical level, we design and implement a practical where buf has 32 elements. When nBuf is greater than 32, tool, SANRAZOR, to reduce sanitizer checks. SANRAZOR executing buf[nBuf-i-1] may trigger an out-of-bounds ac- performs a hybrid analysis by leveraging both coverage cess (e.g. when i is 0). UBSan identifies this by placing an patterns and static data dependency features to identify extra if condition to compare the array index nBuf-i-1 with sanitizer checks as likely redundant. the array size 32 before executing the loop body. • Atthe empirical level, our evaluation on the SPEC bench- 3 ProblemFormulation marks shows that SANRAZOR can significantly reduce runtime overhead caused by ASan and UBSan. Moreover, Conceptually, a sanitizer check c(v) (v is the input parameter) our evaluation on real-world software with known CVEs can be defined as follows: shows that after applying SANRAZOR to reduce sanitizer checks, almost all CVEs can still be discovered. if(P(v) does not hold) abort_or_alert(); We have publicly released SANRAZOR on GitHub at where c checks whether a property P holds w.r.t. parameter https://github.com/SanRazor-repo/SanRazor. v. Usually, v denotes critical program information (e.g., code 2 Preliminaries pointers), and by violating property P, e.g., a null pointer dereference, c either aborts program execution or alerts the Sanitizers are dynamic tools for finding software defects [33]. user. Considering a program p with N sanitizer checks in- Sanitizers insert sanitizer checks, which are statements for serted, we use ci.v and ci.P to denote the parameter of the ith monitoring program behaviors and validating whether they check ci and its checked property throughout this section. violate certain properties. We now introduce two sanitizers AsintroducedinSec.2,computationoverheadcanbeintro- provided by the LLVM framework, ASan and UBSan, which duced by each c , since c performs complex safety property i i have helped to detect many vulnerabilities [33]. checking, and may require extra memory to store metadata. 480 15th USENIX Symposium on Operating Systems Design and Implementation USENIX Association Workload Instrumented SanRazor t Instrument each LLVM IR Profile instrumented Lis eck identified check code LLVM IR Identify Ch Dynamic LLVM IRwith with sanitizer checks Che Static Patterns Redundant reduced sanitizer checks ck Constructdata Patterns Check redundancy Check List Check checks Lis t dependencygraph analysis reduction Figure 1: Workflow of SANRAZOR. Nevertheless, a large portion of sanitizer checks repeatedly as- still be detected, either by another sanitizer check cj or by a sert identical properties, thus wasting computing resources on user-defined check, then c is a redundant sanitizer check. i properties deemed safe. We aim to remove redundant checks Moreformally, given a nontrivial, single-threaded program to reduce cost, thus making the production adoption of san- pwithasetofchecksc∈C,twochecksc andc aredeemed itizer checks more practically feasible. Next, we present a i j motivating example, and then formulate the notion of “redun- identical, when the following condition holds: dant sanitizer checks” from a functionality perspective. (c ∈dom(c )∨c ∈dom(c))∧[[c.v]]=[[c .v]]∧c .P=c .P i j j i i j i j wherec ∈dom(c )andc ∈dom(c)denotethatc dominates 3.1 SampleRedundantChecksinbzip2 i j j i i cj in the control flow graph or vice versa. Therefore, every Weshowanexampleofchecksinbzip2thatrepeatedlyvali- execution from the program entry point to cj goes through date the same array index as follows: ci or vice versa [5]. [[ci.v]] = [[cj.v]] represents that ci.v and c .v are semantically equivalent. c .P = c .P means that c for(i=0; i < nblock; i++) { j i j i j = eclass8[i]; //ASan1 and cj are the same kind of checks (e.g., they are both ASan k = ftab[j] - 1; //ASan2; checks, which can be recognized with pattern matching; cf. ftab[j] = k; //ASan3; ASan2 and ASan3 identical? Sec. 4.1). When ci and cj satisfy the given condition and fmap[k] = i; //ASan4; k < fmap_size always hold? ci ∈ dom(cj), cj can be removed because if cj is executed, WhenASanisenabled,foursanitizer checks are inserted ci must be executed and they check the same property. The to detect out-of-bound array access. Existing research could given condition specifies the functional equivalence of ci and remove ASan4, by asserting k always falls within the size cj. However, computability theory (e.g., Rice’s theorem [29]) of fmap. In contrast, SANRAZOR advocates a new and or- suggests that it could be very difficult, if possible at all, to assert [[c .v]] = [[c .v]] for nontrivial programs. Moreover, per- thogonal focus by deciding that ASan2 and ASan3 validate i j the same index, and therefore, ASan3 can be removed without forming control flow analysis to recover the dominator tree 1 (e.g., dom(cj)) information can be challenging and lead to missingpotential defects. Indeed,ourstudy shows that check false alarms, especially for cases where points-to analyses are redundancy is a general concern in real-world software (see extensively used in performing control flow analysis. Sec. 6), motivating a strong need for optimization. Also, to Given the theoretical challenge of identifying redundant the best of our knowledge, standard compiler optimizations sanitizer checks, we instead propose a practical approxima- andpreviousresearchinthisfield(e.g.,[6,9,11,12,15,28]) do tion to identify likely redundant checks. Our approximation notstrive to use “similarity analysis” to reveal the equalivance extracts both code coverage patterns and static input depen- of ASan2 and ASan3 and shave ASan3 accordingly. In fact, dency patterns of checks (cf. Sec. 4); two checks are deemed our study shows that, when full optimizations (-O3) of clang “redundant” when they yield identical dynamic and static pat- are enabled, no sanitizers can be shaved for this case. This terns. Specifically, we search for a pair of checks ci and cj and observation underlies the key novelty of SANRAZOR, whose flagthemasredundantif all the following conditions hold: design will be introduced in Sec. 4. • c and c have correlated dynamic code coverage patterns, i j whenexecuting the software with a nontrivial amount of 3.2 RedundantSanitizer Checks workload inputs. Here, coverage patterns are checked re- garding their “correlation”, such that they can be identical, Westart by giving a general definition of what a redundant or one check’s coverage pattern can subsume the other’s check is, before refining the notion in an operational way: pattern (see Sec. 4.4 for details). • c .P(c .v) andc .P(c .v) are approximately equivalentw.r.t. Definition 1. Assume that a sanitizer check c that could i i j j i static data dependency patterns deduced by our technique: detect a hypothetical bug B in program p is removed. If B can [[c .P(c .v)]] ≈ [[c .P(c .v)]]. i i j j 1WescopeSANRAZORtosinglethreadedprograms.SeeSec.4forfurther The first condition can be determined by instrumenting discussion of application scope. and profiling the program, and for the second, we assert USENIX Association 15th USENIX Symposium on Operating Systems Design and Implementation 481
no reviews yet
Please Login to review.