[llvm-bugs] [Bug 35353] New: [CFI] Codegen performs argument expansion after CFI check - invalidating CFI.

via llvm-bugs llvm-bugs at lists.llvm.org
Fri Nov 17 11:52:15 PST 2017


https://bugs.llvm.org/show_bug.cgi?id=35353

            Bug ID: 35353
           Summary: [CFI] Codegen performs argument expansion after CFI
                    check - invalidating CFI.
           Product: clang
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: LLVM Codegen
          Assignee: unassignedclangbugs at nondot.org
          Reporter: mitchphillips at outlook.com
                CC: llvm-bugs at lists.llvm.org

Clang's codegen is generating code in the following order:
 1. CFI check for vcall.
 2. Evaluation of arguments.
 3. Execution of vcall.

This severely undermines the effectiveness of CFI, as non-sequential control
flow instructions should not be present between the CFI check and the execution
of the protected indirect call/jump.

The most common instance of this issue is when we have a vcall which has at
least one argument provided by a function-returned temporary. Even if the
function which is providing the argument is a direct call, we cannot guarantee
that the register(s) used to make the protected indirect call/jump are not
clobbered through the call. Often, the compiler will save the register(s) used
by the protected call/jump to a scratch register.

This issue affects approximately 6,932 instructions in the Chrome browser
binary, representing 41.8% of all "unexpected unprotected" indirect CF
instructions.

This issue is revealed by llvm-cfi-verify. Please see below for an example:

$ clang++ -flto -fsanitize=cfi -fvisibility=hidden -g a3.cc
$ llvm-cfi-verify a.out
----------------- Begin Instruction -----------------
FAIL_KNOWN_ISSUE 0x40067c:      callq   *%r14 
  0x40067c = /tmp/a3.cc:9:6 (main)
-----------------------------------------------------
Total Indirect CF Instructions: 1
Expected Protected: 0 (0.00%)
Unexpected Protected: 0 (0.00%)
Expected Unprotected: 0 (0.00%)
Unexpected Unprotected (BAD): 1 (100.00%)

$ cat a3.cc
struct A {
  virtual void f(int) {}
};

int x() { return 0; }

int main() {
  A* a = new A();
  a->f(x());  // Should be CFI protected - x() is executed between CFI check
and execution.
}

$ objdump -d a.out
<..snip..>
  40064f:       48 b9 60 07 40 00 00    movabs $0x400760,%rcx
  400656:       00 00 00 
  400659:       48 83 c1 10             add    $0x10,%rcx
  40065d:       48 89 5d e8             mov    %rbx,-0x18(%rbp)
  400661:       48 8b 5d e8             mov    -0x18(%rbp),%rbx
  400665:       48 8b 03                mov    (%rbx),%rax
  400668:       48 39 c8                cmp    %rcx,%rax
  40066b:       74 02                   je     40066f <main+0x4f>  # cfi check
branch
  40066d:       0f 0b                   ud2                        #
cfi-failure
  40066f:       4c 8b 30                mov    (%rax),%r14
  400672:       e8 99 ff ff ff          callq  400610 <_Z1xv>      # direct
call, can clobber %r14
  400677:       48 89 df                mov    %rbx,%rdi
  40067a:       31 f6                   xor    %esi,%esi
  40067c:       41 ff d6                callq  *%r14               #
instruction that should be protected
<..snip..>

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20171117/c7ae4946/attachment-0001.html>


More information about the llvm-bugs mailing list