Efficient CFI Enforcement for C++ Dynamic Dispatch Dimitar Bounov , - - PowerPoint PPT Presentation

efficient cfi enforcement for c dynamic dispatch
SMART_READER_LITE
LIVE PREVIEW

Efficient CFI Enforcement for C++ Dynamic Dispatch Dimitar Bounov , - - PowerPoint PPT Presentation

Efficient CFI Enforcement for C++ Dynamic Dispatch Dimitar Bounov , Rami Kici, Sorin Lerner UCSD Why A:ack Dynamic Dispatch? Valuable targets (e.g. browsers) 11M LOC ~30M LOC 7M LOC ?M LOC C/C++ C/C++ C/C++ C/C++ Why A:ack Dynamic


slide-1
SLIDE 1

Efficient CFI Enforcement for C++ Dynamic Dispatch

Dimitar Bounov, Rami Kici, Sorin Lerner UCSD

slide-2
SLIDE 2

Why A:ack Dynamic Dispatch?

  • Valuable targets (e.g. browsers)

11M LOC C/C++ 7M LOC C/C++ ?M LOC C/C++ ~30M LOC C/C++

slide-3
SLIDE 3

Why A:ack Dynamic Dispatch?

  • Valuable targets (e.g. browsers)
  • Prevalence of Dynamic Dispatch
  • 91.8 % of Indirect Calls in Chrome [ Tice ’14 ]
slide-4
SLIDE 4

Why A:ack Dynamic Dispatch?

  • Valuable targets (e.g. browsers)
  • Prevalence of Dynamic Dispatch
  • Exploited in the wild
slide-5
SLIDE 5

Prior Work and ContribuAon

  • Prior defenses

vfGuard [Prakash’15], VTInt [Zhao’15], SafeDispatch [Jang’14], VTV [Tice’14] ...

  • Our contribu^on: novel VTable layouts
  • Lower overhead & no profiling
slide-6
SLIDE 6

Example

class A { virtual void foo(); } class B : public A { virtual void foo(); virtual void bar(); } class C : public A { virtual void baz(); } class D : public B { virtual void foo(); virtual void boo(); }

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo()

slide-7
SLIDE 7

C++ Memory Layout

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo()

slide-8
SLIDE 8

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

C++ Memory Layout

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

Virtual Table Object Instance

slide-9
SLIDE 9

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

A* a = (A*) … a->foo() vptr = (*a) fn_ptr = (*(vptr + 0)) (*fn_ptr)();

Method Index

slide-10
SLIDE 10

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ExploiAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)();

exec

vptr = (*a)

slide-11
SLIDE 11

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); vptr = (*a)

slide-12
SLIDE 12

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A, B, C, D }) vptr = (*a)

slide-13
SLIDE 13

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A, B, C, D }) vptr = (*a)

Inline Constant Read-Only

slide-14
SLIDE 14

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A, B, C, D }) vptr = (*a)

How to implement safety check efficiently?

slide-15
SLIDE 15

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { 0x0, 0x8, 0x18, 0x28 }) vptr = (*a)

Non-regular values Hard to test

slide-16
SLIDE 16

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A … Afoo Bfoo

ProtecAng Dynamic Dispatch

B … Bbar C … Afoo Cbaz D … Dfoo Bbar Dboo

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); vptr = (*a) assert (vptr ∈ { 0x0, 0x8, 0x18, 0x28 })

Non-regular values Hard to test

Key idea 1: Order and Pad VTables

slide-17
SLIDE 17

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

  • 1. Traverse in pre-order: A, B, D, C
  • 2. For each class layout vtable and pad
slide-18
SLIDE 18

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A,B,C,D }) vptr = (*a)

  • 1. Traverse in pre-order: A, B, D, C
  • 2. For each class layout vtable and pad
slide-19
SLIDE 19

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A,B,C,D }) vptr = (*a)

slide-20
SLIDE 20

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { 0x0, 0x20, 0x40, 0x60 }) vptr = (*a)

Regular Address Points

slide-21
SLIDE 21

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { 0x0, 0x20, 0x40, 0x60 }) vptr = (*a)

Efficient Check

slide-22
SLIDE 22

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x0 ≤ vptr ≤ 0x60 ∧ vptr % 0x20 = 0) vptr = (*a)

Efficient Check

slide-23
SLIDE 23

A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { B, D }) vptr = (*b) A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo()

slide-24
SLIDE 24

A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { 0x20, 0x40 }) vptr = (*b) A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo()

slide-25
SLIDE 25

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x20 ≤ vptr ≤ 0x40 ∧ vptr % 0x20 = 0) vptr = (*b)

slide-26
SLIDE 26

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B 16 B 8 B

Wasteful Extra Padding

slide-27
SLIDE 27

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Ordered Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo 24 B

Wasteful Extra Padding

16 B 16 B

Key idea 2: Interleave VTables

slide-28
SLIDE 28

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Memory Layout

B … C … D …

  • 1. Traverse in pre-order: A, B, D, C
  • 2. Layout each method
slide-29
SLIDE 29

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Memory Layout

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

  • 1. Traverse in pre-order: A, B, D, C
  • 2. Layout each method
slide-30
SLIDE 30

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

  • 1. Traverse in pre-order: A, B, D, C
  • 2. Layout each method

vptr = (*a) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A,B,C,D })

slide-31
SLIDE 31

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*a) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { A,B,C,D })

slide-32
SLIDE 32

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*a) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (vptr ∈ { 0x0, 0x8, 0x10, 0x18 })

Address Points Consecu^ve Addrs.

slide-33
SLIDE 33

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*a) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x0 ≤ vptr ≤ 0x18 ∧ vptr % 0x8 = 0)

Same Check Different range & alignment

slide-34
SLIDE 34

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*b) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x0 ≤ vptr ≤ 0x18 ∧ vptr % 0x8 = 0)

slide-35
SLIDE 35

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*b) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x8 ≤ vptr ≤ 0x10 ∧ vptr % 0x8 = 0)

slide-36
SLIDE 36

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*b) fn_ptr = (*(vptr + 0)) (*fn_ptr)(); assert (0x8 ≤ vptr ≤ 0x10 ∧ vptr % 0x8 = 0)

slide-37
SLIDE 37

A B C D

Afoo() Afoo() Cbaz() Bfoo() Bbar() Dfoo() Bbar() Dboo() A …

Interleaved Dynamic Dispatch

B … C … D … Afoo Bfoo Bbar Afoo Cbaz Dfoo Bbar Dboo

vptr = (*b) fn_ptr = (*(vptr + 0x18)) (*fn_ptr)(); assert (0x8 ≤ vptr ≤ 0x10 ∧ vptr % 0x8 = 0) Same index in all vtables

slide-38
SLIDE 38

Where are the Vtables?

Afoo Bfoo Dfoo Afoo A B C D Bbar Dboo Cbaz Bbar

1 1 2 2 3 3

Bar method index same VTable Dynamic Dispatch s^ll works!

slide-39
SLIDE 39

ImplementaAon

  • Implemented technique in LLVM
  • Handled all cases of C++ inheritance
  • Algorithms with proofs of correctness
slide-40
SLIDE 40

EvaluaAon

  • Evaluated on SPEC 2006/Chrome
  • Compared to state-of-the-art industry CFI
  • One (benign) CFI viola^on in SPEC 2006
slide-41
SLIDE 41

Results: RunAme Overhead

1% IVT vs. 2% LLVM-VCFI Interleaved VTables Ordered VTables Industry State-of-The-Art

slide-42
SLIDE 42

Results: Size Overhead

IVT 1.7% Size Overhead

slide-43
SLIDE 43

Future Work

  • Dynamic linking/loading
  • Handle C++ member pointers
  • Hardware assisted range checks
slide-44
SLIDE 44

Summary

  • New approach based on VTable layouts
  • Efficient range checks for dynamic

dispatch

  • hyps://github.com/UCSD-PL/ivt

THANK YOU!

slide-45
SLIDE 45

Backup

slide-46
SLIDE 46
slide-47
SLIDE 47

Dynamic Linking

C B A Afoo()

Afoo() Bfoo() Bbar()

D Dfoo()

Dbar()

lib.so

D … A … B … C … Afoo Bfoo Bbar Afoo 8 B 8 B Dfoo Dbar

main lib.so main D

  • >foo()

Only 0.012% of dynamic Firefox virtual calls!

A

slide-48
SLIDE 48

Dynamic Fault Handlers

D … A … B … C … Afoo Bfoo Bbar Afoo 8 B 8 B Dfoo Dbar

vptr = (*a) if (0x00 ≤ vptr ≤ 0x20 ∧ vptr % 0x10 = 0) goto S; fn_ptr = (*(vptr + 0)) (fn_ptr*)(); S : assert(false);

slide-49
SLIDE 49

Dynamic Fault Handlers

D … A … B … C … Afoo Bfoo Bbar Afoo 8 B 8 B Dfoo Dbar

vptr = (*a) if (0x00 ≤ vptr ≤ 0x20 ∧ vptr % 0x10 = 0) goto S; fn_ptr = (*(vptr + 0)) (fn_ptr*)(); S : L = link_unit (vptr) // e.g. dladddr() if vptr_safe(L, vptr, class A) goto S assert(false);

slide-50
SLIDE 50

MulAple Inheritance

A Afoo()

Abar()

C

Cfoo() Cbar() Cbaz()

A-in-C … B-in-C … Cfoo CBaz Cbar

B Bbaz() A subobject B subobject

Object Instance Vtable (Group)

slide-51
SLIDE 51

MulAple Inheritance

A Afoo()

Abar()

C

Cfoo() Cbar() Cbaz()

A-in-C … B-in-C … Cfoo CBaz Cbar

B Bbaz()

slide-52
SLIDE 52

MulAple Inheritance

A Afoo()

Abar()

A-in-C … B-in-C … Cfoo CBaz Cbar

B Bbaz() C

Cfoo() Cbar() Cbaz()

slide-53
SLIDE 53

MulAple Inheritance

A Afoo()

Abar()

A-in-C … B-in-C … Cfoo CBaz Cbar

B Bbaz() A-in-C

Cfoo() Cbar()

B-in-C Cbaz()