Skip to content

Commit

Permalink
Allow specifying sanitizers in blacklists
Browse files Browse the repository at this point in the history
Summary:
This is the follow-up patch to D37924.

This change refactors clang to use the the newly added section headers
in SpecialCaseList to specify which sanitizers blacklists entries
should apply to, like so:

  [cfi-vcall]
  fun:*bad_vcall*
  [cfi-derived-cast|cfi-unrelated-cast]
  fun:*bad_cast*

The SanitizerSpecialCaseList class has been added to allow querying by
SanitizerMask, and SanitizerBlacklist and its downstream users have been
updated to provide that information. Old blacklists not using sections
will continue to function identically since the blacklist entries will
be placed into a '[*]' section by default matching against all
sanitizers.

Reviewers: pcc, kcc, eugenis, vsk

Reviewed By: eugenis

Subscribers: dberris, cfe-commits, mgorny

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

llvm-svn: 314171
  • Loading branch information
vlad902 committed Sep 25, 2017
1 parent 998b220 commit 2eccdab
Show file tree
Hide file tree
Showing 22 changed files with 310 additions and 88 deletions.
12 changes: 10 additions & 2 deletions clang/docs/ControlFlowIntegrity.rst
Expand Up @@ -243,17 +243,25 @@ Blacklist

A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
entity types.
entity types. Specific CFI modes can be be specified using ``[section]``
headers.

.. code-block:: bash
# Suppress checking for code in a file.
# Suppress all CFI checking for code in a file.
src:bad_file.cpp
src:bad_header.h
# Ignore all functions with names containing MyFooBar.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
# Disable only unrelated cast checks for this function
[cfi-unrelated-cast]
fun:*UnrelatedCast*
# Disable CFI call checks for this function without affecting cast checks
[cfi-vcall|cfi-nvcall|cfi-icall]
fun:*BadCall*
.. _cfi-cross-dso:

Expand Down
32 changes: 24 additions & 8 deletions clang/docs/SanitizerSpecialCaseList.rst
Expand Up @@ -51,14 +51,23 @@ Example
Format
======

Each line contains an entity type, followed by a colon and a regular
expression, specifying the names of the entities, optionally followed by
an equals sign and a tool-specific category. Empty lines and lines starting
with "#" are ignored. The meanining of ``*`` in regular expression for entity
names is different - it is treated as in shell wildcarding. Two generic
entity types are ``src`` and ``fun``, which allow user to add, respectively,
source files and functions to special case list. Some sanitizer tools may
introduce custom entity types - refer to tool-specific docs.
Blacklists consist of entries, optionally grouped into sections. Empty lines and
lines starting with "#" are ignored.

Section names are regular expressions written in square brackets that denote
which sanitizer the following entries apply to. For example, ``[address]``
specifies AddressSanitizer while ``[cfi-vcall|cfi-icall]`` specifies Control
Flow Integrity virtual and indirect call checking. Entries without a section
will be placed under the ``[*]`` section applying to all enabled sanitizers.

Entries contain an entity type, followed by a colon and a regular expression,
specifying the names of the entities, optionally followed by an equals sign and
a tool-specific category, e.g. ``fun:*ExampleFunc=example_category``. The
meaning of ``*`` in regular expression for entity names is different - it is
treated as in shell wildcarding. Two generic entity types are ``src`` and
``fun``, which allow users to specify source files and functions, respectively.
Some sanitizer tools may introduce custom entity types and categories - refer to
tool-specific docs.

.. code-block:: bash
Expand All @@ -77,3 +86,10 @@ introduce custom entity types - refer to tool-specific docs.
fun:*BadFunction*
# Specific sanitizer tools may introduce categories.
src:/special/path/*=special_sources
# Sections can be used to limit blacklist entries to specific sanitizers
[address]
fun:*BadASanFunc*
# Section names are regular expressions
[cfi-vcall|cfi-icall]
fun:*BadCfiCall
# Entries without sections are placed into [*] and apply to all sanitizers
15 changes: 8 additions & 7 deletions clang/include/clang/Basic/SanitizerBlacklist.h
Expand Up @@ -15,29 +15,30 @@
#define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/SanitizerSpecialCaseList.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SpecialCaseList.h"
#include <memory>

namespace clang {

class SanitizerBlacklist {
std::unique_ptr<llvm::SpecialCaseList> SCL;
std::unique_ptr<SanitizerSpecialCaseList> SSCL;
SourceManager &SM;

public:
SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths,
SourceManager &SM);
bool isBlacklistedGlobal(StringRef GlobalName,
bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName,
StringRef Category = StringRef()) const;
bool isBlacklistedType(StringRef MangledTypeName,
bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName,
StringRef Category = StringRef()) const;
bool isBlacklistedFunction(StringRef FunctionName) const;
bool isBlacklistedFile(StringRef FileName,
bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const;
bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName,
StringRef Category = StringRef()) const;
bool isBlacklistedLocation(SourceLocation Loc,
bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc,
StringRef Category = StringRef()) const;
};

Expand Down
54 changes: 54 additions & 0 deletions clang/include/clang/Basic/SanitizerSpecialCaseList.h
@@ -0,0 +1,54 @@
//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// An extension of SpecialCaseList to allowing querying sections by
// SanitizerMask.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H
#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/Sanitizers.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SpecialCaseList.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);

static std::unique_ptr<SanitizerSpecialCaseList>
createOrDie(const std::vector<std::string> &Paths);

// Query blacklisted entries if any bit in Mask matches the entry's section.
bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
StringRef Category = StringRef()) const;

protected:
// Initialize SanitizerSections.
void createSanitizerSections();

struct SanitizerSection {
SanitizerSection(SanitizerMask SM, SectionEntries &E)
: Mask(SM), Entries(E){};

SanitizerMask Mask;
SectionEntries &Entries;
};

std::vector<SanitizerSection> SanitizerSections;
};

} // end namespace clang

#endif
12 changes: 7 additions & 5 deletions clang/lib/AST/Decl.cpp
Expand Up @@ -3923,9 +3923,9 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {

bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
ASTContext &Context = getASTContext();
if (!Context.getLangOpts().Sanitize.hasOneOf(
SanitizerKind::Address | SanitizerKind::KernelAddress) ||
!Context.getLangOpts().SanitizeAddressFieldPadding)
const SanitizerMask EnabledAsanMask = Context.getLangOpts().Sanitize.Mask &
(SanitizerKind::Address | SanitizerKind::KernelAddress);
if (!EnabledAsanMask || !Context.getLangOpts().SanitizeAddressFieldPadding)
return false;
const auto &Blacklist = Context.getSanitizerBlacklist();
const auto *CXXRD = dyn_cast<CXXRecordDecl>(this);
Expand All @@ -3943,9 +3943,11 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
ReasonToReject = 4; // has trivial destructor.
else if (CXXRD->isStandardLayout())
ReasonToReject = 5; // is standard layout.
else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding"))
else if (Blacklist.isBlacklistedLocation(EnabledAsanMask, getLocation(),
"field-padding"))
ReasonToReject = 6; // is in a blacklisted file.
else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(),
else if (Blacklist.isBlacklistedType(EnabledAsanMask,
getQualifiedNameAsString(),
"field-padding"))
ReasonToReject = 7; // is blacklisted.

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/CMakeLists.txt
Expand Up @@ -62,6 +62,7 @@ add_clang_library(clangBasic
OpenMPKinds.cpp
OperatorPrecedence.cpp
SanitizerBlacklist.cpp
SanitizerSpecialCaseList.cpp
Sanitizers.cpp
SourceLocation.cpp
SourceManager.cpp
Expand Down
27 changes: 16 additions & 11 deletions clang/lib/Basic/SanitizerBlacklist.cpp
Expand Up @@ -17,30 +17,35 @@ using namespace clang;

SanitizerBlacklist::SanitizerBlacklist(
const std::vector<std::string> &BlacklistPaths, SourceManager &SM)
: SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
: SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}

bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName,
bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask,
StringRef GlobalName,
StringRef Category) const {
return SCL->inSection("global", GlobalName, Category);
return SSCL->inSection(Mask, "global", GlobalName, Category);
}

bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName,
bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask,
StringRef MangledTypeName,
StringRef Category) const {
return SCL->inSection("type", MangledTypeName, Category);
return SSCL->inSection(Mask, "type", MangledTypeName, Category);
}

bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const {
return SCL->inSection("fun", FunctionName);
bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask,
StringRef FunctionName) const {
return SSCL->inSection(Mask, "fun", FunctionName);
}

bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName,
bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask,
StringRef FileName,
StringRef Category) const {
return SCL->inSection("src", FileName, Category);
return SSCL->inSection(Mask, "src", FileName, Category);
}

bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc,
bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask,
SourceLocation Loc,
StringRef Category) const {
return Loc.isValid() &&
isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category);
isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category);
}

64 changes: 64 additions & 0 deletions clang/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -0,0 +1,64 @@
//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// An extension of SpecialCaseList to allowing querying sections by
// SanitizerMask.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/SanitizerSpecialCaseList.h"

using namespace clang;

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

std::unique_ptr<SanitizerSpecialCaseList>
SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
std::string Error;
if (auto SSCL = create(Paths, Error))
return SSCL;
llvm::report_fatal_error(Error);
}

void SanitizerSpecialCaseList::createSanitizerSections() {
for (auto &S : Sections) {
SanitizerMask Mask = 0;

#define SANITIZER(NAME, ID) \
if (S.SectionMatcher->match(NAME)) \
Mask |= SanitizerKind::ID;
#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)

#include "clang/Basic/Sanitizers.def"
#undef SANITIZER
#undef SANITIZER_GROUP

SanitizerSections.emplace_back(Mask, S.Entries);
}
}

bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix,
StringRef Query,
StringRef Category) const {
for (auto &S : SanitizerSections)
if ((S.Mask & Mask) &&
SpecialCaseList::inSection(S.Entries, Prefix, Query, Category))
return true;

return false;
}
14 changes: 9 additions & 5 deletions clang/lib/Basic/XRayLists.cpp
Expand Up @@ -26,21 +26,25 @@ XRayFunctionFilter::ImbueAttribute
XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
// First apply the always instrument list, than if it isn't an "always" see
// whether it's treated as a "never" instrument function.
if (AlwaysInstrument->inSection("fun", FunctionName, "arg1"))
if (AlwaysInstrument->inSection("xray_always_instrument", "fun", FunctionName,
"arg1"))
return ImbueAttribute::ALWAYS_ARG1;
if (AlwaysInstrument->inSection("fun", FunctionName))
if (AlwaysInstrument->inSection("xray_always_instrument", "fun",
FunctionName))
return ImbueAttribute::ALWAYS;
if (NeverInstrument->inSection("fun", FunctionName))
if (NeverInstrument->inSection("xray_never_instrument", "fun", FunctionName))
return ImbueAttribute::NEVER;
return ImbueAttribute::NONE;
}

XRayFunctionFilter::ImbueAttribute
XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename,
StringRef Category) const {
if (AlwaysInstrument->inSection("src", Filename, Category))
if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename,
Category))
return ImbueAttribute::ALWAYS;
if (NeverInstrument->inSection("src", Filename, Category))
if (NeverInstrument->inSection("xray_never_instrument", "src", Filename,
Category))
return ImbueAttribute::NEVER;
return ImbueAttribute::NONE;
}
Expand Down

0 comments on commit 2eccdab

Please sign in to comment.