Skip to content

Commit 8acdc98

Browse files
author
Kostya Kortchinsky
committedNov 3, 2017
[Driver] Add Scudo as a possible -fsanitize= option
Summary: This change adds Scudo as a possible Sanitizer option via -fsanitize=. This allows for easier static & shared linking of the Scudo library, it allows us to enforce PIE (otherwise the security of the allocator is moot), and check for incompatible Sanitizers combo. In its current form, Scudo is not compatible with any other Sanitizer, but the plan is to make it work in conjunction with UBsan (-fsanitize=scudo,undefined), which will require additional work outside of the scope of this change. Reviewers: eugenis, kcc, alekseyshl Reviewed By: eugenis, alekseyshl Subscribers: llvm-commits, srhines Differential Revision: https://reviews.llvm.org/D39334 llvm-svn: 317337
1 parent 594d217 commit 8acdc98

File tree

8 files changed

+101
-16
lines changed

8 files changed

+101
-16
lines changed
 

‎clang/include/clang/Basic/Sanitizers.def

+3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ SANITIZER("efficiency-working-set", EfficiencyWorkingSet)
135135
SANITIZER_GROUP("efficiency-all", Efficiency,
136136
EfficiencyCacheFrag | EfficiencyWorkingSet)
137137

138+
// Scudo hardened allocator
139+
SANITIZER("scudo", Scudo)
140+
138141
// Magic group, containing all sanitizers. For example, "-fno-sanitize=all"
139142
// can be used to disable all the sanitizers.
140143
SANITIZER_GROUP("all", All, ~0ULL)

‎clang/include/clang/Driver/SanitizerArgs.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class SanitizerArgs {
7272
bool needsEsanRt() const {
7373
return Sanitizers.hasOneOf(SanitizerKind::Efficiency);
7474
}
75+
bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); }
7576

7677
bool requiresPIE() const;
7778
bool needsUnwindTables() const;

‎clang/lib/Driver/SanitizerArgs.cpp

+10-13
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ enum : SanitizerMask {
3030
NeedsUbsanCxxRt = Vptr | CFI,
3131
NotAllowedWithTrap = Vptr,
3232
NotAllowedWithMinimalRuntime = Vptr,
33-
RequiresPIE = DataFlow,
33+
RequiresPIE = DataFlow | Scudo,
3434
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
3535
SupportsCoverage = Address | KernelAddress | Memory | Leak | Undefined |
3636
Integer | Nullability | DataFlow | Fuzzer | FuzzerNoLink,
@@ -173,7 +173,7 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
173173
bool SanitizerArgs::needsUbsanRt() const {
174174
// All of these include ubsan.
175175
if (needsAsanRt() || needsMsanRt() || needsTsanRt() || needsDfsanRt() ||
176-
needsLsanRt() || needsCfiDiagRt())
176+
needsLsanRt() || needsCfiDiagRt() || needsScudoRt())
177177
return false;
178178

179179
return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
@@ -370,17 +370,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
370370

371371
// Warn about incompatible groups of sanitizers.
372372
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
373-
std::make_pair(Address, Thread), std::make_pair(Address, Memory),
374-
std::make_pair(Thread, Memory), std::make_pair(Leak, Thread),
375-
std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address),
376-
std::make_pair(KernelAddress, Leak),
377-
std::make_pair(KernelAddress, Thread),
378-
std::make_pair(KernelAddress, Memory),
379-
std::make_pair(Efficiency, Address),
380-
std::make_pair(Efficiency, Leak),
381-
std::make_pair(Efficiency, Thread),
382-
std::make_pair(Efficiency, Memory),
383-
std::make_pair(Efficiency, KernelAddress)};
373+
std::make_pair(Address, Thread | Memory),
374+
std::make_pair(Thread, Memory),
375+
std::make_pair(Leak, Thread | Memory),
376+
std::make_pair(KernelAddress, Address| Leak | Thread | Memory),
377+
std::make_pair(Efficiency, Address | Leak | Thread | Memory |
378+
KernelAddress),
379+
std::make_pair(Scudo, Address | Leak | Thread | Memory | KernelAddress |
380+
Efficiency) };
384381
for (auto G : IncompatibleGroups) {
385382
SanitizerMask Group = G.first;
386383
if (Kinds & Group) {

‎clang/lib/Driver/ToolChains/CommonArgs.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -566,14 +566,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
566566
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
567567
HelperStaticRuntimes.push_back("asan-preinit");
568568
}
569-
570569
if (SanArgs.needsUbsanRt()) {
571570
if (SanArgs.requiresMinimalRuntime()) {
572571
SharedRuntimes.push_back("ubsan_minimal");
573572
} else {
574573
SharedRuntimes.push_back("ubsan_standalone");
575574
}
576575
}
576+
if (SanArgs.needsScudoRt())
577+
SharedRuntimes.push_back("scudo");
577578
}
578579

579580
// The stats_client library is also statically linked into DSOs.
@@ -630,6 +631,11 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
630631
}
631632
if (SanArgs.needsEsanRt())
632633
StaticRuntimes.push_back("esan");
634+
if (SanArgs.needsScudoRt()) {
635+
StaticRuntimes.push_back("scudo");
636+
if (SanArgs.linkCXXRuntimes())
637+
StaticRuntimes.push_back("scudo_cxx");
638+
}
633639
}
634640

635641
// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,

‎clang/lib/Driver/ToolChains/Linux.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -845,9 +845,10 @@ SanitizerMask Linux::getSupportedSanitizers() const {
845845
Res |= SanitizerKind::Memory;
846846
if (IsX86_64 || IsMIPS64)
847847
Res |= SanitizerKind::Efficiency;
848-
if (IsX86 || IsX86_64) {
848+
if (IsX86 || IsX86_64)
849849
Res |= SanitizerKind::Function;
850-
}
850+
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch)
851+
Res |= SanitizerKind::Scudo;
851852
return Res;
852853
}
853854

‎clang/lib/Lex/PPMacroExpansion.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
11381138
.Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow))
11391139
.Case("efficiency_sanitizer",
11401140
LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency))
1141+
.Case("scudo", LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
11411142
// Objective-C features
11421143
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
11431144
.Case("objc_arc", LangOpts.ObjCAutoRefCount)

‎clang/test/Driver/fsanitize.c

+26
Original file line numberDiff line numberDiff line change
@@ -608,3 +608,29 @@
608608
// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
609609
// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize-trap=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
610610
// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize-minimal-runtime"
611+
612+
// RUN: %clang -target aarch64-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO
613+
// RUN: %clang -target arm-linux-androideabi -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO
614+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO
615+
// RUN: %clang -target i386-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO
616+
// CHECK-SCUDO: "-fsanitize=scudo"
617+
618+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-PIE
619+
// RUN: %clang -target arm-linux-androideabi -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-PIE
620+
// CHECK-SCUDO-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie"
621+
// CHECK-SCUDO-PIE: "-pie"
622+
623+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo,undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-UBSAN
624+
// CHECK-SCUDO-UBSAN: "-fsanitize={{.*}}scudo"
625+
626+
// RUN: %clang -target powerpc-unknown-linux -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SCUDO
627+
// CHECK-NO-SCUDO: unsupported option
628+
629+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo,address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-ASAN
630+
// CHECK-SCUDO-ASAN: error: invalid argument '-fsanitize=scudo' not allowed with '-fsanitize=address'
631+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo,leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-LSAN
632+
// CHECK-SCUDO-LSAN: error: invalid argument '-fsanitize=scudo' not allowed with '-fsanitize=leak'
633+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo,memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-MSAN
634+
// CHECK-SCUDO-MSAN: error: invalid argument '-fsanitize=scudo' not allowed with '-fsanitize=memory'
635+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo,thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-TSAN
636+
// CHECK-SCUDO-TSAN: error: invalid argument '-fsanitize=scudo' not allowed with '-fsanitize=thread'

‎clang/test/Driver/sanitizer-ld.c

+50
Original file line numberDiff line numberDiff line change
@@ -644,3 +644,53 @@
644644
//
645645
// CHECK-ESAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
646646
// CHECK-ESAN-LINUX: libclang_rt.esan-x86_64.a
647+
648+
// RUN: %clang -fsanitize=scudo %s -### -o %t.o 2>&1 \
649+
// RUN: -target i386-unknown-linux -fuse-ld=ld \
650+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
651+
// RUN: | FileCheck --check-prefix=CHECK-SCUDO-LINUX %s
652+
// CHECK-SCUDO-LINUX: "{{.*}}ld{{(.exe)?}}"
653+
// CHECK-SCUDO-LINUX: "-pie"
654+
// CHECK-SCUDO-LINUX: "-whole-archive" "{{.*}}libclang_rt.scudo-i386.a" "-no-whole-archive"
655+
// CHECK-SCUDO-LINUX-NOT: "-lstdc++"
656+
// CHECK-SCUDO-LINUX: "-lpthread"
657+
// CHECK-SCUDO-LINUX: "-ldl"
658+
659+
// RUN: %clang -no-canonical-prefixes %s -### -o %t.so -shared 2>&1 \
660+
// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=scudo -shared-libsan \
661+
// RUN: -resource-dir=%S/Inputs/resource_dir \
662+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
663+
// RUN: | FileCheck --check-prefix=CHECK-SCUDO-SHARED-LINUX %s
664+
//
665+
// CHECK-SCUDO-SHARED-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
666+
// CHECK-SCUDO-SHARED-LINUX-NOT: "-lc"
667+
// CHECK-SCUDO-SHARED-LINUX-NOT: libclang_rt.scudo-i386.a"
668+
// CHECK-SCUDO-SHARED-LINUX: libclang_rt.scudo-i386.so"
669+
// CHECK-SCUDO-SHARED-LINUX-NOT: "-lpthread"
670+
// CHECK-SCUDO-SHARED-LINUX-NOT: "-lrt"
671+
// CHECK-SCUDO-SHARED-LINUX-NOT: "-ldl"
672+
// CHECK-SCUDO-SHARED-LINUX-NOT: "-export-dynamic"
673+
// CHECK-SCUDO-SHARED-LINUX-NOT: "--dynamic-list"
674+
675+
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
676+
// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=scudo \
677+
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
678+
// RUN: | FileCheck --check-prefix=CHECK-SCUDO-ANDROID %s
679+
//
680+
// CHECK-SCUDO-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
681+
// CHECK-SCUDO-ANDROID-NOT: "-lc"
682+
// CHECK-SCUDO-ANDROID: "-pie"
683+
// CHECK-SCUDO-ANDROID-NOT: "-lpthread"
684+
// CHECK-SCUDO-ANDROID: libclang_rt.scudo-arm-android.so"
685+
// CHECK-SCUDO-ANDROID-NOT: "-lpthread"
686+
687+
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
688+
// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=scudo \
689+
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
690+
// RUN: -static-libsan \
691+
// RUN: | FileCheck --check-prefix=CHECK-SCUDO-ANDROID-STATIC %s
692+
// CHECK-SCUDO-ANDROID-STATIC: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
693+
// CHECK-SCUDO-ANDROID-STATIC: "-pie"
694+
// CHECK-SCUDO-ANDROID-STATIC: "-whole-archive" "{{.*}}libclang_rt.scudo-arm-android.a" "-no-whole-archive"
695+
// CHECK-SCUDO-ANDROID-STATIC-NOT: "-lstdc++"
696+
// CHECK-SCUDO-ANDROID-STATIC: "-lpthread"

0 commit comments

Comments
 (0)