aboutsummaryrefslogtreecommitdiff
path: root/Security.md
diff options
context:
space:
mode:
authorDominic Chen <d.c.ddcc@gmail.com>2017-05-11 23:37:04 -0400
committerJF Bastien <github@jfbastien.com>2017-05-11 20:37:04 -0700
commitdea1548ce2099d87bac8e9b10cdc62dc4f659bc0 (patch)
treeac72955d80ef13d229687c7ef3674be549dd9fcb /Security.md
parentaf07a03ff09df183b1a8105076670c205d02b9d2 (diff)
downloadnanowasm-design-dea1548ce2099d87bac8e9b10cdc62dc4f659bc0.tar.gz
Discuss control-flow integrity in detail, including current fine-grained CFI implementation (#723)
Diffstat (limited to 'Security.md')
-rw-r--r--Security.md67
1 files changed, 61 insertions, 6 deletions
diff --git a/Security.md b/Security.md
index 486a28d..d373423 100644
--- a/Security.md
+++ b/Security.md
@@ -39,8 +39,8 @@ runtime, WebAssembly programs are protected from control flow hijacking attacks.
* [Indirect function calls](Rationale.md#indirect-calls) are subject to a type
signature check at runtime; the type signature of the selected indirect
function must match the type signature specified at the call site.
- * A shadow stack is used to maintain a trusted call stack that is invulnerable
- to buffer overflows in the module heap, ensuring safe function returns.
+ * A protected call stack that is invulnerable to buffer overflows in the
+ module heap ensures safe function returns.
* [Branches](Semantics.md#branches-and-nesting) must point to valid
destinations within the enclosing function.
@@ -48,7 +48,7 @@ Variables in C/C++ can be lowered to two different primitives in WebAssembly,
depending on their scope. [Local variables](Semantics.md#local-variables)
with fixed scope and [global variables](Semantics.md#global-variables) are
represented as fixed-type values stored by index. The former are initialized
-to zero by default and are stored in the protected shadow stack, whereas
+to zero by default and are stored in the protected call stack, whereas
the latter are located in the [global index space](Modules.md#global-index-space)
and can be imported from external modules. Local variables with
[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
addressed by index. Data stored in linear memory can overwrite adjacent objects,
since bounds checking is performed at linear memory region granularity and is
not context-sensitive. However, the presence of control-flow integrity and
-protected shadow call stacks prevents direct code injection attacks. Thus,
+protected call stacks prevents direct code injection attacks. Thus,
common mitigations such as [data execution prevention][] (DEP) and
[stack smashing protection][] (SSP) are not needed by WebAssembly programs.
@@ -112,13 +112,68 @@ in-order execution and [post-MVP atomic memory primitives
Similarly, [side channel attacks][] can occur, such as timing attacks against
modules. In the future, additional protections may be provided by runtimes or
the toolchain, such as code diversification or memory randomization (similar to
-[address space layout randomization][] (ASLR)), [bounded pointers][] ("fat"
-pointers), or finer-grained control-flow integrity.
+[address space layout randomization][] (ASLR)), or [bounded pointers][] ("fat"
+pointers).
+
+### Control-Flow Integrity
+The effectiveness of control-flow integrity can be measured based on its
+completeness. Generally, there are three types of external control-flow
+transitions that need to be protected, because the callee may not be trusted:
+ 1. Direct function calls,
+ 2. Indirect function calls,
+ 3. Returns.
+
+Together, (1) and (2) are commonly referred to as "forward-edge", since they
+correspond to forward edges in a directed control-flow graph. Likewise (3) is
+commonly referred to as "back-edge", since it corresponds to back edges in a
+directed control-flow graph. More specialized function calls, such as tail
+calls, can be viewed as a combination of (1) and (3).
+
+Typically, this is implemented using runtime instrumentation. During
+compilation, the compiler generates an expected control flow graph of program
+execution, and inserts runtime instrumentation at each call site to verify that
+the transition is safe. Sets of expected call targets are constructed from the
+set of all possible call targets in the program, unique identifiers are assigned
+to each set, and the instrumentation checks whether the current call target is
+a member of the expected call target set. If this check succeeds, then the
+original call is allowed to proceed, otherwise a failure handler is executed,
+which typically terminates the program.
+
+In WebAssembly, the execution semantics implicitly guarantee the safety of (1)
+through usage of explicit function section indexes, and (3) through a protected
+call stack. Additionally, the type signature of indirect function calls is
+already checked at runtime, effectively implementing coarse-grained type-based
+control-flow integrity for (2). All of this is achieved without explicit runtime
+instrumentation in the module. However, as discussed
+[previously](#memory-safety), this protection does not prevent code reuse
+attacks with function-level granularity against indirect calls.
+
+#### Clang/LLVM CFI
+The Clang/LLVM compiler infrastructure includes a [built-in implementation] of
+fine-grained control flow integrity, which has been extended to support the
+WebAssembly target. It is available in Clang/LLVM 3.9+ with the
+[new WebAssembly backend].
+
+Enabling fine-grained control-flow integrity (by passing `-fsanitize=cfi` to
+emscripten) has a number of advantages over the default WebAssembly
+configuration. Not only does this better defend against code reuse attacks that
+leverage indirect function calls (2), but it also enhances the built-in function
+signature checks by operating at the C/C++ type level, which is semantically
+richer that the WebAssembly [type level](AstSemantics.md#types), which consists
+of only four value types. Currently, enabling this feature has a small
+performance cost for each indirect call, because an integer range check is
+used to verify that the target index is trusted, but this will be eliminated in
+the future by leveraging built-in support for
+[multiple indirect tables](Modules.md#table-index-space) with homogeneous type
+in WebAssembly.
[address space layout randomization]: https://en.wikipedia.org/wiki/Address_space_layout_randomization
[bounded pointers]: https://en.wikipedia.org/wiki/Bounded_pointer
+ [built-in implementation]: http://clang.llvm.org/docs/ControlFlowIntegrity.html
[control-flow integrity]: https://research.microsoft.com/apps/pubs/default.aspx?id=64250
[data execution prevention]: https://en.wikipedia.org/wiki/Executable_space_protection
+ [forward-edge control-flow integrity]: https://www.usenix.org/node/184460
+ [new WebAssembly backend]: https://github.com/WebAssembly/binaryen#cc-source--webassembly-llvm-backend--s2wasm--webassembly
[return-oriented programming]: https://en.wikipedia.org/wiki/Return-oriented_programming
[same-origin policy]: https://www.w3.org/Security/wiki/Same_Origin_Policy
[side channel attacks]: https://en.wikipedia.org/wiki/Side-channel_attack