diff options
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/ubsan/ubsan_handlers.cc | 14 | ||||
-rw-r--r-- | compiler-rt/lib/ubsan/ubsan_handlers.h | 2 | ||||
-rw-r--r-- | compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc | 4 | ||||
-rw-r--r-- | compiler-rt/test/cfi/mfcall.cpp | 94 |
4 files changed, 108 insertions, 6 deletions
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc index de2cc0ff216..2fe83f2bb76 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cc +++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h index 311776b9f22..ed3c8f0b1b0 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc index 3bc7fe4d18a..6b205c2c653 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc +++ b/compiler-rt/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(); } diff --git a/compiler-rt/test/cfi/mfcall.cpp b/compiler-rt/test/cfi/mfcall.cpp new file mode 100644 index 00000000000..d101054673b --- /dev/null +++ b/compiler-rt/test/cfi/mfcall.cpp @@ -0,0 +1,94 @@ +// RUN: %clangxx_cfi -o %t %s +// RUN: %expect_crash %run %t a +// RUN: %expect_crash %run %t b +// RUN: %expect_crash %run %t c +// RUN: %expect_crash %run %t d +// RUN: %expect_crash %run %t e +// RUN: %run %t f +// RUN: %run %t g + +// RUN: %clangxx_cfi_diag -o %t2 %s +// RUN: %run %t2 a 2>&1 | FileCheck --check-prefix=A %s +// RUN: %run %t2 b 2>&1 | FileCheck --check-prefix=B %s +// RUN: %run %t2 c 2>&1 | FileCheck --check-prefix=C %s +// RUN: %run %t2 d 2>&1 | FileCheck --check-prefix=D %s +// RUN: %run %t2 e 2>&1 | FileCheck --check-prefix=E %s + +#include <assert.h> +#include <string.h> + +struct SBase1 { + void b1() {} +}; + +struct SBase2 { + void b2() {} +}; + +struct S : SBase1, SBase2 { + void f1() {} + int f2() { return 1; } + virtual void g1() {} + virtual int g2() { return 1; } + virtual int g3() { return 1; } +}; + +struct T { + void f1() {} + int f2() { return 2; } + virtual void g1() {} + virtual int g2() { return 2; } + virtual void g3() {} +}; + +typedef void (S::*S_void)(); + +typedef int (S::*S_int)(); +typedef int (T::*T_int)(); + +template <typename To, typename From> +To bitcast(From f) { + assert(sizeof(To) == sizeof(From)); + To t; + memcpy(&t, &f, sizeof(f)); + return t; +} + +int main(int argc, char **argv) { + S s; + T t; + + switch (argv[1][0]) { + case 'a': + // A: runtime error: control flow integrity check for type 'int (S::*)()' failed during non-virtual pointer to member function call + // A: note: S::f1() defined here + (s.*bitcast<S_int>(&S::f1))(); + break; + case 'b': + // B: runtime error: control flow integrity check for type 'int (T::*)()' failed during non-virtual pointer to member function call + // B: note: S::f2() defined here + (t.*bitcast<T_int>(&S::f2))(); + break; + case 'c': + // C: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call + // C: note: vtable is of type 'S' + (s.*bitcast<S_int>(&S::g1))(); + break; + case 'd': + // D: runtime error: control flow integrity check for type 'int (S::*)()' failed during virtual pointer to member function call + // D: note: vtable is of type 'T' + (reinterpret_cast<S &>(t).*&S::g2)(); + break; + case 'e': + // E: runtime error: control flow integrity check for type 'void (S::*)()' failed during virtual pointer to member function call + // E: note: vtable is of type 'S' + (s.*bitcast<S_void>(&T::g3))(); + break; + case 'f': + (s.*&SBase1::b1)(); + break; + case 'g': + (s.*&SBase2::b2)(); + break; + } +} |