Skip to content

Commit

Permalink
hwasan: add -fsanitize=kernel-hwaddress flag
Browse files Browse the repository at this point in the history
This patch adds -fsanitize=kernel-hwaddress flag, that essentially enables
-hwasan-kernel=1 -hwasan-recover=1 -hwasan-match-all-tag=0xff.

Differential Revision: https://reviews.llvm.org/D45046

llvm-svn: 330044
  • Loading branch information
xairy committed Apr 13, 2018
1 parent 24fff24 commit 1ba9d9c
Show file tree
Hide file tree
Showing 19 changed files with 157 additions and 45 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Expand Up @@ -44,8 +44,12 @@ SANITIZER("address", Address)
// Kernel AddressSanitizer (KASan)
SANITIZER("kernel-address", KernelAddress)

// Hardware-assisted AddressSanitizer
SANITIZER("hwaddress", HWAddress)

// Kernel Hardware-assisted AddressSanitizer (KHWASan)
SANITIZER("kernel-hwaddress", KernelHWAddress)

// MemorySanitizer
SANITIZER("memory", Memory)

Expand Down
22 changes: 17 additions & 5 deletions clang/lib/CodeGen/BackendUtil.cpp
Expand Up @@ -233,10 +233,9 @@ static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
PM.add(createAddressSanitizerFunctionPass(
/*CompileKernel*/ true,
/*Recover*/ true, /*UseAfterScope*/ false));
PM.add(createAddressSanitizerModulePass(/*CompileKernel*/true,
/*Recover*/true));
/*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false));
PM.add(createAddressSanitizerModulePass(
/*CompileKernel*/ true, /*Recover*/ true));
}

static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
Expand All @@ -245,7 +244,13 @@ static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
static_cast<const PassManagerBuilderWrapper &>(Builder);
const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
PM.add(createHWAddressSanitizerPass(Recover));
PM.add(createHWAddressSanitizerPass(/*CompileKernel*/ false, Recover));
}

static void addKernelHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
PM.add(createHWAddressSanitizerPass(
/*CompileKernel*/ true, /*Recover*/ true));
}

static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
Expand Down Expand Up @@ -581,6 +586,13 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
addHWAddressSanitizerPasses);
}

if (LangOpts.Sanitize.has(SanitizerKind::KernelHWAddress)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addKernelHWAddressSanitizerPasses);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addKernelHWAddressSanitizerPasses);
}

if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addMemorySanitizerPass);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Expand Up @@ -332,6 +332,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
!isInSanitizerBlacklist(SanitizerKind::HWAddress, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);

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

if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
!isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.cpp
Expand Up @@ -856,13 +856,17 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
SanOpts.set(SanitizerKind::KernelAddress, false);
if (mask & SanitizerKind::KernelAddress)
SanOpts.set(SanitizerKind::Address, false);
if (mask & SanitizerKind::HWAddress)
SanOpts.set(SanitizerKind::KernelHWAddress, false);
if (mask & SanitizerKind::KernelHWAddress)
SanOpts.set(SanitizerKind::HWAddress, false);
}
}

// Apply sanitizer attributes to the function.
if (SanOpts.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress))
Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
if (SanOpts.hasOneOf(SanitizerKind::HWAddress))
if (SanOpts.hasOneOf(SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress))
Fn->addFnAttr(llvm::Attribute::SanitizeHWAddress);
if (SanOpts.has(SanitizerKind::Thread))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -1817,7 +1817,8 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
StringRef Category) const {
// For now globals can be blacklisted only in ASan and KASan.
const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
(SanitizerKind::Address | SanitizerKind::KernelAddress | SanitizerKind::HWAddress);
(SanitizerKind::Address | SanitizerKind::KernelAddress |
SanitizerKind::HWAddress | SanitizerKind::KernelHWAddress);
if (!EnabledAsanMask)
return false;
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/SanitizerMetadata.cpp
Expand Up @@ -27,7 +27,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
bool IsBlacklisted) {
if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress |
SanitizerKind::HWAddress))
SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress))
return;
IsDynInit &= !CGM.isInSanitizerBlacklist(GV, Loc, Ty, "init");
IsBlacklisted |= CGM.isInSanitizerBlacklist(GV, Loc, Ty);
Expand Down Expand Up @@ -60,7 +61,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
const VarDecl &D, bool IsDynInit) {
if (!CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress |
SanitizerKind::HWAddress))
SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress))
return;
std::string QualName;
llvm::raw_string_ostream OS(QualName);
Expand All @@ -79,7 +81,8 @@ void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
// instrumentation.
if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress |
SanitizerKind::HWAddress))
SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress))
reportGlobalToASan(GV, SourceLocation(), "", QualType(), false, true);
}

Expand Down
28 changes: 22 additions & 6 deletions clang/lib/Driver/SanitizerArgs.cpp
Expand Up @@ -33,11 +33,12 @@ enum : SanitizerMask {
NotAllowedWithMinimalRuntime = Vptr,
RequiresPIE = DataFlow | HWAddress | Scudo,
NeedsUnwindTables = Address | HWAddress | Thread | Memory | DataFlow,
SupportsCoverage = Address | HWAddress | KernelAddress | Memory | Leak |
Undefined | Integer | Nullability | DataFlow | Fuzzer |
FuzzerNoLink,
SupportsCoverage = Address | HWAddress | KernelAddress | KernelHWAddress |
Memory | Leak | Undefined | Integer | Nullability |
DataFlow | Fuzzer | FuzzerNoLink,
RecoverableByDefault = Undefined | Integer | Nullability,
Unrecoverable = Unreachable | Return,
AlwaysRecoverable = KernelAddress | KernelHWAddress,
LegacyFsanitizeRecoverMask = Undefined | Integer,
NeedsLTO = CFI,
TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow |
Expand Down Expand Up @@ -347,7 +348,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
KernelAddress | Efficiency),
std::make_pair(ShadowCallStack, Address | HWAddress | Leak | Thread |
Memory | KernelAddress | Efficiency |
SafeStack)};
SafeStack),
std::make_pair(KernelHWAddress, Address | HWAddress | Leak | Thread |
Memory | KernelAddress | Efficiency |
SafeStack | ShadowCallStack)};

// Enable toolchain specific default sanitizers if not explicitly disabled.
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
Expand Down Expand Up @@ -422,8 +426,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// default in ASan?

// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = RecoverableByDefault;
SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
SanitizerMask DiagnosedUnrecoverableKinds = 0;
SanitizerMask DiagnosedAlwaysRecoverableKinds = 0;
for (const auto *Arg : Args) {
const char *DeprecatedReplacement = nullptr;
if (Arg->getOption().matches(options::OPT_fsanitize_recover)) {
Expand Down Expand Up @@ -451,7 +456,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
RecoverableKinds |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true));
SanitizerMask Remove = parseArgValues(D, Arg, true);
// Report error if user explicitly tries to disable recovery from
// always recoverable sanitizer.
if (SanitizerMask KindsToDiagnose =
Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getOption().getName() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
Arg->claim();
}
if (DeprecatedReplacement) {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Driver/ToolChains/Linux.cpp
Expand Up @@ -900,8 +900,10 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Function;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch)
Res |= SanitizerKind::Scudo;
if (IsX86_64 || IsAArch64)
if (IsX86_64 || IsAArch64) {
Res |= SanitizerKind::HWAddress;
Res |= SanitizerKind::KernelHWAddress;
}
return Res;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Lex/PPMacroExpansion.cpp
Expand Up @@ -1105,7 +1105,8 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
LangOpts.Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress))
.Case("hwaddress_sanitizer",
LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress))
LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress))
.Case("assume_nonnull", true)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CodeGen/address-safety-attr-flavors.cpp
Expand Up @@ -2,6 +2,8 @@
// HWASan. Either __attribute__((no_sanitize("address")) or
// __attribute__((no_sanitize("kernel-address")) disables both ASan and KASan
// instrumentation.
// Same for __attribute__((no_sanitize("hwaddress")) and
// __attribute__((no_sanitize("kernel-hwddress")) and HWASan and KHWASan.

// RUN: %clang_cc1 -triple i386-unknown-linux -disable-O0-optnone \
// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NOASAN %s
Expand All @@ -18,11 +20,16 @@
// RUN: -disable-O0-optnone -emit-llvm -o - %s | \
// RUN: FileCheck -check-prefix=CHECK-HWASAN %s

// RUN: %clang_cc1 -triple i386-unknown-linux -fsanitize=kernel-hwaddress \
// RUN: -disable-O0-optnone -emit-llvm -o - %s | \
// RUN: FileCheck -check-prefix=CHECK-KHWASAN %s

int HasSanitizeAddress() { return 1; }
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: Function Attrs: noinline nounwind sanitize_address
// CHECK-KASAN: Function Attrs: noinline nounwind sanitize_address
// CHECK-HWASAN: Function Attrs: noinline nounwind sanitize_hwaddress
// CHECK-KHWASAN: Function Attrs: noinline nounwind sanitize_hwaddress

__attribute__((no_sanitize("address"))) int NoSanitizeQuoteAddress() {
return 0;
Expand All @@ -31,12 +38,14 @@ __attribute__((no_sanitize("address"))) int NoSanitizeQuoteAddress() {
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}

__attribute__((no_sanitize_address)) int NoSanitizeAddress() { return 0; }
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}

__attribute__((no_sanitize("kernel-address"))) int NoSanitizeKernelAddress() {
return 0;
Expand All @@ -45,6 +54,7 @@ __attribute__((no_sanitize("kernel-address"))) int NoSanitizeKernelAddress() {
// CHECK-ASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-HWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind sanitize_hwaddress$}}

__attribute__((no_sanitize("hwaddress"))) int NoSanitizeHWAddress() {
return 0;
Expand All @@ -53,3 +63,13 @@ __attribute__((no_sanitize("hwaddress"))) int NoSanitizeHWAddress() {
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
// CHECK-HWASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind$}}

__attribute__((no_sanitize("kernel-hwaddress"))) int NoSanitizeKernelHWAddress() {
return 0;
}
// CHECK-NOASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-ASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
// CHECK-KASAN: {{Function Attrs: noinline nounwind sanitize_address$}}
// CHECK-HWASAN: {{Function Attrs: noinline nounwind$}}
// CHECK-KHWASAN: {{Function Attrs: noinline nounwind$}}
7 changes: 6 additions & 1 deletion clang/test/Driver/asan.c
Expand Up @@ -10,9 +10,14 @@
// RUN: %clang -O1 -target aarch64-unknown-linux -fsanitize=hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-HWASAN
// RUN: %clang -O2 -target aarch64-unknown-linux -fsanitize=hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-HWASAN
// RUN: %clang -O3 -target aarch64-unknown-linux -fsanitize=hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-HWASAN
// Verify that -fsanitize={address,kernel-address} invoke ASan and KASan instrumentation.
// RUN: %clang -target aarch64-unknown-linux -fsanitize=kernel-hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-KHWASAN
// RUN: %clang -O1 -target aarch64-unknown-linux -fsanitize=kernel-hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-KHWASAN
// RUN: %clang -O2 -target aarch64-unknown-linux -fsanitize=kernel-hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-KHWASAN
// RUN: %clang -O3 -target aarch64-unknown-linux -fsanitize=kernel-hwaddress %s -S -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-KHWASAN
// Verify that -fsanitize={address,hwaddres,kernel-address,kernel-hwaddress} invokes ASan, HWAsan, KASan or KHWASan instrumentation.

int foo(int *a) { return *a; }
// CHECK-ASAN: __asan_init
// CHECK-KASAN: __asan_load4_noabort
// CHECK-HWASAN: __hwasan_init
// CHECK-KHWASAN: __hwasan_load4_noabort
1 change: 1 addition & 0 deletions clang/test/Driver/fsanitize-coverage.c
Expand Up @@ -7,6 +7,7 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=kernel-address -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=hwaddress -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=kernel-hwaddress -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
Expand Down

0 comments on commit 1ba9d9c

Please sign in to comment.