Skip to content

Commit dcdef4e

Browse files
committed
Discuss control-flow integrity in detail, including current fine-grained CFI implementation
1 parent 72c34aa commit dcdef4e

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

Security.md

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ runtime, WebAssembly programs are protected from control flow hijacking attacks.
3737
* [Indirect function calls](Rationale.md#indirect-calls) are subject to a type
3838
signature check at runtime; the type signature of the selected indirect
3939
function must match the type signature specified at the call site.
40-
* A shadow stack is used to maintain a trusted call stack that is invulnerable
41-
to buffer overflows in the module heap, ensuring safe function returns.
40+
* A protected call stack that is invulnerable to buffer overflows in the
41+
module heap ensures safe function returns.
4242
* [Branches](AstSemantics.md#branches-and-nesting) must point to valid
4343
destinations within the enclosing function.
4444

4545
Variables in C/C++ can be lowered to two different primitives in WebAssembly,
4646
depending on their scope. [Local variables](AstSemantics.md#local-variables)
4747
with fixed scope and [global variables](AstSemantics.md#global-variables) are
4848
represented as fixed-type values stored by index. The former are initialized
49-
to zero by default and are stored in the protected shadow stack, whereas
49+
to zero by default and are stored in the protected call stack, whereas
5050
the latter are located in the [global index space](Modules.md#global-index-space)
5151
and can be imported from external modules. Local variables with
5252
[unclear static scope](Rationale.md#locals) (e.g. are used by the address-of
@@ -80,7 +80,7 @@ affect local or global variables stored in index space, they are fixed-size and
8080
addressed by index. Data stored in linear memory can overwrite adjacent objects,
8181
since bounds checking is performed at linear memory region granularity and is
8282
not context-sensitive. However, the presence of control-flow integrity and
83-
protected shadow call stacks prevents direct code injection attacks. Thus,
83+
protected call stacks prevents direct code injection attacks. Thus,
8484
common mitigations such as [data execution prevention][] (DEP) and
8585
[stack smashing protection][] (SSP) are not needed by WebAssembly programs.
8686

@@ -108,13 +108,69 @@ in-order execution and [post-MVP atomic memory primitives](PostMVP.md#threads).
108108
Similarly, [side channel attacks][] can occur, such as timing attacks against
109109
modules. In the future, additional protections may be provided by runtimes or
110110
the toolchain, such as code diversification or memory randomization (similar to
111-
[address space layout randomization][] (ASLR)), [bounded pointers][] ("fat"
112-
pointers), or finer-grained control-flow integrity.
111+
[address space layout randomization][] (ASLR)), or [bounded pointers][] ("fat"
112+
pointers).
113+
114+
### Control-Flow Integrity
115+
The effectiveness of control-flow integrity can be measured based on its
116+
completeness. Generally, there are three types of external control-flow
117+
transitions that need to be protected, because the callee may not be trusted:
118+
1. Direct function calls,
119+
2. Indirect function calls,
120+
3. Returns.
121+
122+
Together, (1) and (2) are commonly referred to as "forward-edge", since they
123+
correspond to forward edges in a directed control-flow graph. Likewise (3) is
124+
commonly referred to as "back-edge", since it corresponds to back edges in a
125+
directed control-flow graph. More specialized function calls, such as tail
126+
calls, can be viewed as a combination of (1) and (3).
127+
128+
Typically, this is implemented using runtime instrumentation. During
129+
compilation, the compiler generates an expected control flow graph of program
130+
execution, and inserts runtime instrumentation at each call site to verify that
131+
the transition is safe. Sets of expected call targets are constructed from the
132+
set of all possible call targets in the program, unique identifiers are assigned
133+
to each set, and the instrumentation checks whether the current call target is
134+
a member of the expected call target set. If this check succeeds, then the
135+
original call is allowed to proceed, otherwise a failure handler is executed,
136+
which typically terminates the program.
137+
138+
In WebAssembly, the execution semantics implicitly guarantee the safety of (1)
139+
through usage of explicit function section indexes, and (3) through a protected
140+
call stack. Additionally, the type signature of indirect function calls is
141+
already checked at runtime, effectively implementing coarse-grained type-based
142+
control-flow integrity for (2). All of this is achieved without explicit runtime
143+
instrumentation in the module. However, as discussed
144+
[previously](#memory-safety), this protection does not prevent code reuse
145+
attacks with function-level granularity against indirect calls.
146+
147+
#### Clang/LLVM CFI
148+
The Clang/LLVM compiler infrastructure includes a [built-in implementation] of
149+
fine-grained control flow integrity, which has been extended to support the
150+
WebAssembly target. It is available in Clang/LLVM 3.9+ with the
151+
[new WebAssembly backend].
152+
153+
Enabling fine-grained control-flow integrity (by passing `-fsanitize=cfi` to
154+
emscripten) has a number of advantages over the default WebAssembly
155+
configuration. Not only does this better defend against code reuse attacks that
156+
leverage indirect function calls (2), but it also enhances the built-in function
157+
signature checks by operating at the C/C++ type level, which is semantically
158+
richer that the WebAssembly [type level](AstSemantics.md#types), which consists
159+
of only four value types. Currently, enabling this feature has a small
160+
performance cost for each indirect call, because an integer range check is
161+
used to verify that the target index is trusted, but this will be eliminated in
162+
the future by leveraging built-in support for
163+
[multiple indirect tables](Modules.md#table-index-space) with homogeneous type
164+
in WebAssembly.
165+
113166

114167
[address space layout randomization]: https://en.wikipedia.org/wiki/Address_space_layout_randomization
115168
[bounded pointers]: https://en.wikipedia.org/wiki/Bounded_pointer
169+
[built-in support]: http://clang.llvm.org/docs/ControlFlowIntegrity.html
116170
[control-flow integrity]: https://research.microsoft.com/apps/pubs/default.aspx?id=64250
117171
[data execution prevention]: https://en.wikipedia.org/wiki/Executable_space_protection
172+
[forward-edge control-flow integrity]: https://www.usenix.org/node/184460
173+
[new WebAssembly backend]: WebAssembly/binaryen#cc-source--webassembly-llvm-backend--s2wasm--webassembly
118174
[return-oriented programming]: https://en.wikipedia.org/wiki/Return-oriented_programming
119175
[same-origin policy]: https://www.w3.org/Security/wiki/Same_Origin_Policy
120176
[side channel attacks]: https://en.wikipedia.org/wiki/Side-channel_attack

0 commit comments

Comments
 (0)