diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2018-06-26 02:15:47 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2018-06-26 02:15:47 +0000 |
commit | 2d0b060aaf31bfad01827f8af15f8f5af2ae072b (patch) | |
tree | bac083fc96016e0e7ff4adb2a0bdf9aea7db616f /lib | |
parent | 2a1852a7218178ecdbd2cfd28970cb65941cea82 (diff) |
Implement CFI for indirect calls via a member function pointer.
Similarly to CFI on virtual and indirect calls, this implementation
tries to use program type information to make the checks as precise
as possible. The basic way that it works is as follows, where `C`
is the name of the class being defined or the target of a call and
the function type is assumed to be `void()`.
For virtual calls:
- Attach type metadata to the addresses of function pointers in vtables
(not the functions themselves) of type `void (B::*)()` for each `B`
that is a recursive dynamic base class of `C`, including `C` itself.
This type metadata has an annotation that the type is for virtual
calls (to distinguish it from the non-virtual case).
- At the call site, check that the computed address of the function
pointer in the vtable has type `void (C::*)()`.
For non-virtual calls:
- Attach type metadata to each non-virtual member function whose address
can be taken with a member function pointer. The type of a function
in class `C` of type `void()` is each of the types `void (B::*)()`
where `B` is a most-base class of `C`. A most-base class of `C`
is defined as a recursive base class of `C`, including `C` itself,
that does not have any bases.
- At the call site, check that the function pointer has one of the types
`void (B::*)()` where `B` is a most-base class of `C`.
Differential Revision: https://reviews.llvm.org/D47567
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@335569 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ubsan/ubsan_handlers.cc | 14 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers.h | 2 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.cc | 4 |
3 files changed, 14 insertions, 6 deletions
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index de2cc0ff2..2fe83f2bb 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -637,7 +637,7 @@ void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data, static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, ReportOptions Opts) { - if (Data->CheckKind != CFITCK_ICall) + if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall) Die(); SourceLocation Loc = Data->Loc.acquire(); @@ -648,10 +648,12 @@ static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, ScopedReport R(Opts, Loc, ET); + const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall + ? "non-virtual pointer to member function call" + : "indirect function call"; Diag(Loc, DL_Error, ET, - "control flow integrity check for type %0 failed during " - "indirect function call") - << Data->Type; + "control flow integrity check for type %0 failed during %1") + << Data->Type << CheckKindStr; SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); const char *FName = FLoc.get()->info.function; @@ -693,7 +695,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, ValueHandle Value, uptr ValidVtable) { GET_REPORT_OPTIONS(false); - if (Data->CheckKind == CFITCK_ICall) + if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall) handleCFIBadIcall(Data, Value, Opts); else __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); @@ -703,7 +705,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data, ValueHandle Value, uptr ValidVtable) { GET_REPORT_OPTIONS(true); - if (Data->CheckKind == CFITCK_ICall) + if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall) handleCFIBadIcall(Data, Value, Opts); else __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 311776b9f..ed3c8f0b1 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -181,6 +181,8 @@ enum CFITypeCheckKind : unsigned char { CFITCK_DerivedCast, CFITCK_UnrelatedCast, CFITCK_ICall, + CFITCK_NVMFCall, + CFITCK_VMFCall, }; struct CFICheckFailData { diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index 3bc7fe4d1..6b205c2c6 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -123,7 +123,11 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, case CFITCK_UnrelatedCast: CheckKindStr = "cast to unrelated type"; break; + case CFITCK_VMFCall: + CheckKindStr = "virtual pointer to member function call"; + break; case CFITCK_ICall: + case CFITCK_NVMFCall: Die(); } |