Skip to content

Commit dea1548

Browse files
ddccjfbastien
authored andcommitted
Discuss control-flow integrity in detail, including current fine-grained CFI implementation (WebAssembly#723)
1 parent af07a03 commit dea1548

File tree

1 file changed

+61
-6
lines changed

1 file changed

+61
-6
lines changed

Security.md

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

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

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

118170
[address space layout randomization]: https://en.wikipedia.org/wiki/Address_space_layout_randomization
119171
[bounded pointers]: https://en.wikipedia.org/wiki/Bounded_pointer
172+
[built-in implementation]: http://clang.llvm.org/docs/ControlFlowIntegrity.html
120173
[control-flow integrity]: https://research.microsoft.com/apps/pubs/default.aspx?id=64250
121174
[data execution prevention]: https://en.wikipedia.org/wiki/Executable_space_protection
175+
[forward-edge control-flow integrity]: https://www.usenix.org/node/184460
176+
[new WebAssembly backend]: https://github.com/WebAssembly/binaryen#cc-source--webassembly-llvm-backend--s2wasm--webassembly
122177
[return-oriented programming]: https://en.wikipedia.org/wiki/Return-oriented_programming
123178
[same-origin policy]: https://www.w3.org/Security/wiki/Same_Origin_Policy
124179
[side channel attacks]: https://en.wikipedia.org/wiki/Side-channel_attack

0 commit comments

Comments
 (0)