37 changes: 13 additions & 24 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,28 +2604,34 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
!CGM.HasHiddenLTOVisibility(RD))
return;

std::string TypeName = RD->getQualifiedNameAsString();
if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName))
return;

SanitizerScope SanScope(this);
SanitizerMask M;
llvm::SanitizerStatKind SSK;
switch (TCK) {
case CFITCK_VCall:
M = SanitizerKind::CFIVCall;
SSK = llvm::SanStat_CFI_VCall;
break;
case CFITCK_NVCall:
M = SanitizerKind::CFINVCall;
SSK = llvm::SanStat_CFI_NVCall;
break;
case CFITCK_DerivedCast:
M = SanitizerKind::CFIDerivedCast;
SSK = llvm::SanStat_CFI_DerivedCast;
break;
case CFITCK_UnrelatedCast:
M = SanitizerKind::CFIUnrelatedCast;
SSK = llvm::SanStat_CFI_UnrelatedCast;
break;
case CFITCK_ICall:
llvm_unreachable("not expecting CFITCK_ICall");
}

std::string TypeName = RD->getQualifiedNameAsString();
if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName))
return;

SanitizerScope SanScope(this);
EmitSanitizerStatReport(SSK);

llvm::Metadata *MD =
Expand All @@ -2636,24 +2642,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Value *TypeTest = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});

SanitizerMask M;
switch (TCK) {
case CFITCK_VCall:
M = SanitizerKind::CFIVCall;
break;
case CFITCK_NVCall:
M = SanitizerKind::CFINVCall;
break;
case CFITCK_DerivedCast:
M = SanitizerKind::CFIDerivedCast;
break;
case CFITCK_UnrelatedCast:
M = SanitizerKind::CFIUnrelatedCast;
break;
case CFITCK_ICall:
llvm_unreachable("not expecting CFITCK_ICall");
}

llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(Int8Ty, TCK),
EmitCheckSourceLocation(Loc),
Expand Down Expand Up @@ -2688,7 +2676,8 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
return false;

std::string TypeName = RD->getQualifiedNameAsString();
return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName);
return !getContext().getSanitizerBlacklist().isBlacklistedType(
SanitizerKind::CFIVCall, TypeName);
}

llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
Expand Down
30 changes: 19 additions & 11 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,17 +316,25 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow();

if (!isInSanitizerBlacklist(Fn, Loc)) {
if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (getLangOpts().Sanitize.has(SanitizerKind::Thread))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack))
Fn->addFnAttr(llvm::Attribute::SafeStack);
}
if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
!isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);

if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
!isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);

if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
!isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);

if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
!isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);

if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
!isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SafeStack);

return Fn;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,

// Blacklist based on the mangled type.
if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
Out.str())) {
SanitizerKind::Vptr, Out.str())) {
llvm::hash_code TypeHash = hash_value(Out.str());

// Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,8 +804,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");

if (CGM.isInSanitizerBlacklist(Fn, Loc))
SanOpts.clear();
// If this function has been blacklisted for any of the enabled sanitizers,
// disable the sanitizer for the function.
do {
#define SANITIZER(NAME, ID) \
if (SanOpts.empty()) \
break; \
if (SanOpts.has(SanitizerKind::ID)) \
if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc)) \
SanOpts.set(SanitizerKind::ID, false);

#include "clang/Basic/Sanitizers.def"
#undef SANITIZER
} while (0);

if (D) {
// Apply the no_sanitize* attributes to SanOpts.
Expand Down
20 changes: 11 additions & 9 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,20 +1543,21 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}

bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn,
bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind,
llvm::Function *Fn,
SourceLocation Loc) const {
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
// Blacklist by function name.
if (SanitizerBL.isBlacklistedFunction(Fn->getName()))
if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName()))
return true;
// Blacklist by location.
if (Loc.isValid())
return SanitizerBL.isBlacklistedLocation(Loc);
return SanitizerBL.isBlacklistedLocation(Kind, Loc);
// If location is unknown, this may be a compiler-generated function. Assume
// it's located in the main file.
auto &SM = Context.getSourceManager();
if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
return SanitizerBL.isBlacklistedFile(MainFile->getName());
return SanitizerBL.isBlacklistedFile(Kind, MainFile->getName());
}
return false;
}
Expand All @@ -1565,13 +1566,14 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
SourceLocation Loc, QualType Ty,
StringRef Category) const {
// For now globals can be blacklisted only in ASan and KASan.
if (!LangOpts.Sanitize.hasOneOf(
SanitizerKind::Address | SanitizerKind::KernelAddress))
const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
(SanitizerKind::Address | SanitizerKind::KernelAddress);
if (!EnabledAsanMask)
return false;
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category))
if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category))
return true;
if (SanitizerBL.isBlacklistedLocation(Loc, Category))
if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category))
return true;
// Check global type.
if (!Ty.isNull()) {
Expand All @@ -1583,7 +1585,7 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
// We allow to blacklist only record types (classes, structs etc.)
if (Ty->isRecordType()) {
std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy());
if (SanitizerBL.isBlacklistedType(TypeStr, Category))
if (SanitizerBL.isBlacklistedType(EnabledAsanMask, TypeStr, Category))
return true;
}
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);

bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const;
bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn,
SourceLocation Loc) const;

bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc,
QualType Ty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[unsigned-integer-overflow]
fun:*cfi*
[cfi]
fun:*overflow*
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fun:*cfi*
fun:*overflow*
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[cfi]
fun:*cfi*
[unsigned-integer-overflow]
fun:*overflow*
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[cfi-icall]
fun:*cfi*
[unsigned-integer-overflow]
fun:*overflow*
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[c*]
fun:*cfi*
[u*]
fun:*overflow*
26 changes: 26 additions & 0 deletions clang/test/CodeGen/sanitizer-special-case-list.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Verify that blacklist sections correctly select sanitizers to apply blacklist entries to.
//
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized1.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized2.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized3.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized4.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
//
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.sanitized.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=SANITIZED

unsigned i;

// SANITIZED: @overflow
// UNSANITIZED: @overflow
unsigned overflow() {
// SANITIZED: call {{.*}}void @__ubsan
// UNSANITIZED-NOT: call {{.*}}void @__ubsan
return i * 37;
}

// SANITIZED: @cfi
// UNSANITIZED: @cfi
void cfi(void (*fp)()) {
// SANITIZED: llvm.type.test
// UNSANITIZED-NOT: llvm.type.test
fp();
}
16 changes: 14 additions & 2 deletions clang/test/CodeGenCXX/cfi-blacklist.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
// RUN: echo "type:std::*" > %t.txt
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s

// Check that blacklisting cfi and cfi-vcall work correctly
// RUN: echo "[cfi-vcall]" > %t.vcall.txt
// RUN: echo "type:std::*" >> %t.vcall.txt
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.vcall.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
//
// RUN: echo "[cfi]" > %t.cfi.txt
// RUN: echo "type:std::*" >> %t.cfi.txt
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.cfi.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s

// Check that blacklisting non-vcall modes does not affect vcalls
// RUN: echo "[cfi-icall|cfi-nvcall|cfi-cast-strict|cfi-derived-cast|cfi-unrelated-cast]" > %t.other.txt
// RUN: echo "type:std::*" >> %t.other.txt
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.other.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s

struct S1 {
virtual void f();
Expand Down