Skip to content

Sanitizer blacklist #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions clang/include/clang/Basic/SanitizerSpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@
#include "clang/Basic/Sanitizers.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SpecialCaseList.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <memory>

namespace clang {

class SanitizerSpecialCaseList : public llvm::SpecialCaseList {
public:
static std::unique_ptr<SanitizerSpecialCaseList>
create(const std::vector<std::string> &Paths, std::string &Error);
create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS,
std::string &Error);

static std::unique_ptr<SanitizerSpecialCaseList>
createOrDie(const std::vector<std::string> &Paths);
createOrDie(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &VFS);

// Query blacklisted entries if any bit in Mask matches the entry's section.
bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,9 @@ def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
Group<f_clang_Group>,
HelpText<"Path to blacklist file for sanitizers">;
def fsanitize_system_blacklist : Joined<["-"], "fsanitize-system-blacklist=">,
HelpText<"Path to system blacklist file for sanitizers">,
Flags<[CC1Option]>;
def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class SanitizerArgs {
SanitizerSet RecoverableSanitizers;
SanitizerSet TrapSanitizers;

std::vector<std::string> BlacklistFiles;
std::vector<std::string> ExtraDeps;
std::vector<std::string> UserBlacklistFiles;
std::vector<std::string> SystemBlacklistFiles;
int CoverageFeatures = 0;
int MsanTrackOrigins = 0;
bool MsanUseAfterDtor = true;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Basic/SanitizerBlacklist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ using namespace clang;

SanitizerBlacklist::SanitizerBlacklist(
const std::vector<std::string> &BlacklistPaths, SourceManager &SM)
: SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
: SSCL(SanitizerSpecialCaseList::createOrDie(
BlacklistPaths, SM.getFileManager().getVirtualFileSystem())),
SM(SM) {}

bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask,
StringRef GlobalName,
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Basic/SanitizerSpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@ using namespace clang;

std::unique_ptr<SanitizerSpecialCaseList>
SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &VFS,
std::string &Error) {
std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
new SanitizerSpecialCaseList());
if (SSCL->createInternal(Paths, Error)) {
if (SSCL->createInternal(Paths, Error, VFS)) {
SSCL->createSanitizerSections();
return SSCL;
}
return nullptr;
}

std::unique_ptr<SanitizerSpecialCaseList>
SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &VFS) {
std::string Error;
if (auto SSCL = create(Paths, Error))
if (auto SSCL = create(Paths, VFS, Error))
return SSCL;
llvm::report_fatal_error(Error);
}
Expand Down
28 changes: 17 additions & 11 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,29 +547,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,

// Setup blacklist files.
// Add default blacklist from resource directory.
addDefaultBlacklists(D, Kinds, BlacklistFiles);
addDefaultBlacklists(D, Kinds, SystemBlacklistFiles);
// Parse -f(no-)sanitize-blacklist options.
for (const auto *Arg : Args) {
if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
Arg->claim();
std::string BLPath = Arg->getValue();
if (llvm::sys::fs::exists(BLPath)) {
BlacklistFiles.push_back(BLPath);
ExtraDeps.push_back(BLPath);
UserBlacklistFiles.push_back(BLPath);
} else {
D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
}
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
Arg->claim();
BlacklistFiles.clear();
ExtraDeps.clear();
UserBlacklistFiles.clear();
SystemBlacklistFiles.clear();
}
}
// Validate blacklists format.
{
std::string BLError;
std::unique_ptr<llvm::SpecialCaseList> SCL(
llvm::SpecialCaseList::create(BlacklistFiles, BLError));
llvm::SpecialCaseList::create(UserBlacklistFiles, BLError));
if (!SCL.get())
D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
}
{
std::string BLError;
std::unique_ptr<llvm::SpecialCaseList> SCL(
llvm::SpecialCaseList::create(SystemBlacklistFiles, BLError));
if (!SCL.get())
D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
}
Expand Down Expand Up @@ -920,15 +926,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));

for (const auto &BLPath : BlacklistFiles) {
for (const auto &BLPath : UserBlacklistFiles) {
SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
BlacklistOpt += BLPath;
CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
}
for (const auto &Dep : ExtraDeps) {
SmallString<64> ExtraDepOpt("-fdepfile-entry=");
ExtraDepOpt += Dep;
CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
for (const auto &BLPath : SystemBlacklistFiles) {
SmallString<64> BlacklistOpt("-fsanitize-system-blacklist=");
BlacklistOpt += BLPath;
CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
}

if (MsanTrackOrigins)
Expand Down
26 changes: 25 additions & 1 deletion clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,26 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
// Add sanitizer blacklists as extra dependencies.
// They won't be discovered by the regular preprocessor, so
// we let make / ninja to know about this implicit dependency.
Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry);
if (!Args.hasArg(OPT_fno_sanitize_blacklist)) {
for (const auto *A : Args.filtered(OPT_fsanitize_blacklist)) {
StringRef Val = A->getValue();
if (Val.find('=') == StringRef::npos)
Opts.ExtraDeps.push_back(Val);
}
if (Opts.IncludeSystemHeaders) {
for (const auto *A : Args.filtered(OPT_fsanitize_system_blacklist)) {
StringRef Val = A->getValue();
if (Val.find('=') == StringRef::npos)
Opts.ExtraDeps.push_back(Val);
}
}
}

// Propagate the extra dependencies.
for (const auto *A : Args.filtered(OPT_fdepfile_entry)) {
Opts.ExtraDeps.push_back(A->getValue());
}

// Only the -fmodule-file=<file> form.
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
StringRef Val = A->getValue();
Expand Down Expand Up @@ -3110,6 +3129,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
std::vector<std::string> systemBlacklists =
Args.getAllArgValues(OPT_fsanitize_system_blacklist);
Opts.SanitizerBlacklistFiles.insert(Opts.SanitizerBlacklistFiles.end(),
systemBlacklists.begin(),
systemBlacklists.end());

// -fxray-instrument
Opts.XRayInstrument =
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/Inputs/sanitizer-blacklist-vfsoverlay.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
'version': 0,
'roots': [
{ 'name': '@DIR@', 'type': 'directory',
'contents': [
{ 'name': 'only-virtual-file.blacklist', 'type': 'file',
'external-contents': '@REAL_FILE@'
},
{ 'name': 'invalid-virtual-file.blacklist', 'type': 'file',
'external-contents': '@NONEXISTENT_FILE@'
}
]
}
]
}
36 changes: 36 additions & 0 deletions clang/test/CodeGen/ubsan-blacklist-vfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Verify ubsan doesn't emit checks for blacklisted functions and files
// RUN: echo "fun:hash" > %t-func.blacklist
// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t-file.blacklist

// RUN: rm -f %t-vfsoverlay.yaml
// RUN: rm -f %t-nonexistent.blacklist
// RUN: sed -e "s|@DIR@|%/T|g" %S/Inputs/sanitizer-blacklist-vfsoverlay.yaml | sed -e "s|@REAL_FILE@|%/t-func.blacklist|g" | sed -e "s|@NONEXISTENT_FILE@|%/t-nonexistent.blacklist|g" > %t-vfsoverlay.yaml
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -ivfsoverlay %t-vfsoverlay.yaml -fsanitize-blacklist=%/T/only-virtual-file.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=FUNC

// RUN: not %clang_cc1 -fsanitize=unsigned-integer-overflow -ivfsoverlay %t-vfsoverlay.yaml -fsanitize-blacklist=%/T/invalid-virtual-file.blacklist -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=INVALID-MAPPED-FILE
// INVALID-MAPPED-FILE: invalid-virtual-file.blacklist': {{[Nn]}}o such file or directory

// RUN: not %clang_cc1 -fsanitize=unsigned-integer-overflow -ivfsoverlay %t-vfsoverlay.yaml -fsanitize-blacklist=%t-nonexistent.blacklist -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=INVALID
// INVALID: nonexistent.blacklist': {{[Nn]}}o such file or directory

unsigned i;

// DEFAULT: @hash
// FUNC: @hash
// FILE: @hash
unsigned hash() {
// DEFAULT: call {{.*}}void @__ubsan
// FUNC-NOT: call {{.*}}void @__ubsan
// FILE-NOT: call {{.*}}void @__ubsan
return i * 37;
}

// DEFAULT: @add
// FUNC: @add
// FILE: @add
unsigned add() {
// DEFAULT: call {{.*}}void @__ubsan
// FUNC: call {{.*}}void @__ubsan
// FILE-NOT: call {{.*}}void @__ubsan
return i + 1;
}
10 changes: 3 additions & 7 deletions clang/test/Driver/fsanitize-blacklist.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,17 @@
// RUN: %clang -target aarch64-linux-gnu -fsanitize=hwaddress -fsanitize-blacklist=%t.good -fsanitize-blacklist=%t.second %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST
// CHECK-BLACKLIST: -fsanitize-blacklist={{.*}}.good" "-fsanitize-blacklist={{.*}}.second

// Now, check for -fdepfile-entry flags.
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-blacklist=%t.good -fsanitize-blacklist=%t.second %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST2
// CHECK-BLACKLIST2: -fdepfile-entry={{.*}}.good" "-fdepfile-entry={{.*}}.second

// Check that the default blacklist is not added as an extra dependency.
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-BLACKLIST-ASAN --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// CHECK-DEFAULT-BLACKLIST-ASAN: -fsanitize-blacklist={{.*[^w]}}asan_blacklist.txt
// CHECK-DEFAULT-BLACKLIST-ASAN: -fsanitize-system-blacklist={{.*[^w]}}asan_blacklist.txt
// RUN: %clang -target x86_64-linux-gnu -fsanitize=hwaddress -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-BLACKLIST-HWASAN --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// CHECK-DEFAULT-BLACKLIST-HWASAN: -fsanitize-blacklist={{.*}}hwasan_blacklist.txt
// CHECK-DEFAULT-BLACKLIST-HWASAN: -fsanitize-system-blacklist={{.*}}hwasan_blacklist.txt

// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// RUN: %clang -target x86_64-linux-gnu -fsanitize=nullability -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// RUN: %clang -target x86_64-linux-gnu -fsanitize=alignment -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
// CHECK-DEFAULT-UBSAN-BLACKLIST: -fsanitize-blacklist={{.*}}ubsan_blacklist.txt
// CHECK-DEFAULT-UBSAN-BLACKLIST: -fsanitize-system-blacklist={{.*}}ubsan_blacklist.txt

// Check that combining ubsan and another sanitizer results in both blacklists being used.
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined,address -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --check-prefix=CHECK-DEFAULT-ASAN-BLACKLIST --implicit-check-not=fdepfile-entry --implicit-check-not=-fsanitize-blacklist=
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Frontend/dependency-gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,20 @@
#ifndef INCLUDE_FLAG_TEST
#include <x.h>
#endif

// RUN: echo "fun:foo" > %t.blacklist1
// RUN: echo "fun:foo" > %t.blacklist2
// RUN: %clang -MD -MF - %s -fsyntax-only -resource-dir=%S/Inputs/resource_dir_with_cfi_blacklist -fsanitize=cfi-vcall -flto -fvisibility=hidden -fsanitize-blacklist=%t.blacklist1 -fsanitize-blacklist=%t.blacklist2 -I ./ | FileCheck -check-prefix=TWO-BLACK-LISTS %s
// TWO-BLACK-LISTS: dependency-gen.o:
// TWO-BLACK-LISTS-DAG: blacklist1
// TWO-BLACK-LISTS-DAG: blacklist2
// TWO-BLACK-LISTS-DAG: x.h
// TWO-BLACK-LISTS-DAG: dependency-gen.c

// RUN: %clang -MD -MF - %s -fsyntax-only -resource-dir=%S/Inputs/resource_dir_with_cfi_blacklist -fsanitize=cfi-vcall -flto -fvisibility=hidden -I ./ | FileCheck -check-prefix=USER-AND-SYS-DEPS %s
// USER-AND-SYS-DEPS: dependency-gen.o:
// USER-AND-SYS-DEPS-DAG: cfi_blacklist.txt

// RUN: %clang -MMD -MF - %s -fsyntax-only -resource-dir=%S/Inputs/resource_dir_with_cfi_blacklist -fsanitize=cfi-vcall -flto -fvisibility=hidden -I ./ | FileCheck -check-prefix=ONLY-USER-DEPS %s
// ONLY-USER-DEPS: dependency-gen.o:
// NOT-ONLY-USER-DEPS: cfi_blacklist.txt
2 changes: 1 addition & 1 deletion compiler-rt/test/asan/TestCases/default_blacklist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
//
// Test that ASan uses the default blacklist from resource directory.
// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s
// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt
// CHECK: fsanitize-system-blacklist={{.*}}asan_blacklist.txt
2 changes: 1 addition & 1 deletion compiler-rt/test/msan/default_blacklist.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Test that MSan uses the default blacklist from resource directory.
// RUN: %clangxx_msan -### %s 2>&1 | FileCheck %s
// CHECK: fsanitize-blacklist={{.*}}msan_blacklist.txt
// CHECK: fsanitize-system-blacklist={{.*}}msan_blacklist.txt
5 changes: 3 additions & 2 deletions llvm/include/llvm/Support/SpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/TrigramIndex.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <string>
#include <vector>

Expand Down Expand Up @@ -102,8 +103,8 @@ class SpecialCaseList {
protected:
// Implementations of the create*() functions that can also be used by derived
// classes.
bool createInternal(const std::vector<std::string> &Paths,
std::string &Error);
bool createInternal(const std::vector<std::string> &Paths, std::string &Error,
vfs::FileSystem &VFS = *vfs::getRealFileSystem());
bool createInternal(const MemoryBuffer *MB, std::string &Error);

SpecialCaseList() = default;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Support/SpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ SpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
}

bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
std::string &Error) {
std::string &Error, vfs::FileSystem &VFS) {
StringMap<size_t> Sections;
for (const auto &Path : Paths) {
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
MemoryBuffer::getFile(Path);
VFS.getBufferForFile(Path);
if (std::error_code EC = FileOrErr.getError()) {
Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
return false;
Expand Down