[PATCH] D21768: Support CFI for WebAssembly target

Dominic Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 12 15:51:21 PDT 2016


ddcc added a comment.

Hmm, good question. Currently, if I compile that example with optimizations enabled, it simply gets optimized out to always return true. However, if I compile it without optimizations, it actually returns false. This is because f() gets assigned to table index 0 by s2wasm, and the check fails. Note that this is true regardless of whether the CFI pass is enabled; there are no indirect function calls being executed, so it doesn't affect the IR at all.

Now, suppose that I execute the following example code. Without CFI, it will trigger a runtime type check failure, because the indirect call table has the entries `(0: f, 1: g)`, and `fp2` is assigned index 0, but this doesn't match the expected type at the call site. Now, the behavior is different with CFI, because the indirect call table has the entries `(0: g, 1: main, 2: f)`, and `fp2` is assigned index 0, which executes successfully. This is because `{g, main}` are in the same type set and are assigned indexes `{0, 1}`, respectively, whereas f`` is skipped by the CFI pass because the type of `f` is never referenced by `llvm.type.test()` (since it is never explicitly called), but it is automatically assigned index 2 in s2wasm (since it has its address taken). However, this behavior is suboptimal and actually increases the attack surface by adding more indirect call targets, so I've modified this patch to skip index assignments for functions that are not used anywhere. With the new version of this patch, the indirect call table has the entries `(0: g, 1: f)`, and `fp2` is assigned index 0, which executes successfully. If `NULL + 1` is assigned to `fp2`, then a CFI trap is triggered, as expected.

In general, the rationale for undefined behavior is discussed in the documentation <https://github.com/WebAssembly/design/blob/master/CAndC%2B%2B.md#undefined-behavior>; essentially undefined behavior in C or C++ (e.g. dereferencing a NULL pointer) is still a bug when compiling for WebAssembly, even when the corresponding behavior in WebAssembly itself is defined.

  void f() {
  }
  
  int g() {
    return 2;
  }
  
  int main() __attribute__((optnone)) {
    int i = 0;
    void (*fp1)() = f;
    int (*fp2)() = i ? g : NULL;
    return fp2();
  }


http://reviews.llvm.org/D21768





More information about the llvm-commits mailing list