[GWP-ASan] Add inbuilt options parser.
Adds a modified options parser (shamefully pulled from Scudo, which shamefully pulled it from sanitizer-common) to GWP-ASan. This allows customers (Android) to parse options strings in a common way. Depends on D94117. AOSP side of these patches is staged at: - sepolicy (sysprops should only be settable by the shell, in both root and unrooted conditions): https://android-review.googlesource.com/c/platform/system/sepolicy/+/1517238 - zygote updates: https://android-review.googlesource.com/c/platform/frameworks/base/+/1515009 - bionic changes to add `gwp_asan.<process_name>` system property, and GWP_ASAN_OPTIONS environment variable: https://android-review.googlesource.com/c/platform/bionic/+/1514989 Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D92696
This commit is contained in:
parent
a14c36fe27
commit
6a42cbf6d2
|
@ -41,11 +41,10 @@ append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC GWP_ASAN_CFLAGS)
|
|||
# Remove -stdlib= which is unused when passing -nostdinc++.
|
||||
string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
# Options parsing support is optional. GwpAsan is totally independent of
|
||||
# sanitizer_common, the options parser is not. This is an optional library
|
||||
# that can be used by an allocator to automatically parse GwpAsan options from
|
||||
# the environment variable GWP_ASAN_FLAGS, but the allocator can choose to
|
||||
# implement its own options parsing and populate the Options struct itself.
|
||||
# Options parsing support is optional. This is an optional library that can be
|
||||
# used by an allocator to automatically parse GwpAsan options from the
|
||||
# environment variable GWP_ASAN_FLAGS, but the allocator can choose to implement
|
||||
# its own options parsing and populate the Options struct itself.
|
||||
set(GWP_ASAN_OPTIONS_PARSER_SOURCES
|
||||
optional/options_parser.cpp
|
||||
)
|
||||
|
@ -64,11 +63,7 @@ set(GWP_ASAN_SEGV_HANDLER_HEADERS
|
|||
options.h)
|
||||
|
||||
set(GWP_ASAN_OPTIONS_PARSER_CFLAGS
|
||||
${GWP_ASAN_CFLAGS}
|
||||
${SANITIZER_COMMON_CFLAGS})
|
||||
set(GWP_ASAN_OPTIONS_PARSER_OBJECT_LIBS
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonNoLibc)
|
||||
${GWP_ASAN_CFLAGS})
|
||||
|
||||
if (COMPILER_RT_HAS_GWP_ASAN)
|
||||
foreach(arch ${GWP_ASAN_SUPPORTED_ARCH})
|
||||
|
@ -89,11 +84,6 @@ if (COMPILER_RT_HAS_GWP_ASAN)
|
|||
ADDITIONAL_HEADERS ${GWP_ASAN_HEADERS}
|
||||
CFLAGS ${GWP_ASAN_CFLAGS})
|
||||
|
||||
# Note: If you choose to add this as an object library, ensure you also
|
||||
# include the sanitizer_common flag parsing object lib (generally
|
||||
# 'RTSanitizerCommonNoTermination'). Also, you'll need to either implement
|
||||
# your own backtrace support (see optional/backtrace.h), or choose between one
|
||||
# of the pre-implemented backtrace support options (see below).
|
||||
add_compiler_rt_object_libraries(RTGwpAsanOptionsParser
|
||||
ARCHS ${GWP_ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${GWP_ASAN_OPTIONS_PARSER_SOURCES}
|
||||
|
|
|
@ -7,84 +7,251 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gwp_asan/optional/options_parser.h"
|
||||
#include "gwp_asan/optional/printf.h"
|
||||
#include "gwp_asan/utilities.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gwp_asan/options.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
namespace gwp_asan {
|
||||
namespace options {
|
||||
namespace {
|
||||
void registerGwpAsanFlags(__sanitizer::FlagParser *parser, Options *o) {
|
||||
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &o->Name);
|
||||
enum class OptionType : uint8_t {
|
||||
OT_bool,
|
||||
OT_int,
|
||||
};
|
||||
|
||||
#define InvokeIfNonNull(Printf, ...) \
|
||||
do { \
|
||||
if (Printf) \
|
||||
Printf(__VA_ARGS__); \
|
||||
} while (0);
|
||||
|
||||
class OptionParser {
|
||||
public:
|
||||
explicit OptionParser(gwp_asan::Printf_t PrintfForWarnings)
|
||||
: Printf(PrintfForWarnings) {}
|
||||
void registerOption(const char *Name, const char *Desc, OptionType Type,
|
||||
void *Var);
|
||||
void parseString(const char *S);
|
||||
void printOptionDescriptions();
|
||||
|
||||
private:
|
||||
// Calculate at compile-time how many options are available.
|
||||
#define GWP_ASAN_OPTION(...) +1
|
||||
static constexpr size_t MaxOptions = 0
|
||||
#include "gwp_asan/options.inc"
|
||||
;
|
||||
#undef GWP_ASAN_OPTION
|
||||
|
||||
struct Option {
|
||||
const char *Name;
|
||||
const char *Desc;
|
||||
OptionType Type;
|
||||
void *Var;
|
||||
} Options[MaxOptions];
|
||||
|
||||
size_t NumberOfOptions = 0;
|
||||
const char *Buffer = nullptr;
|
||||
uintptr_t Pos = 0;
|
||||
gwp_asan::Printf_t Printf = nullptr;
|
||||
|
||||
void skipWhitespace();
|
||||
void parseOptions();
|
||||
bool parseOption();
|
||||
bool setOptionToValue(const char *Name, const char *Value);
|
||||
};
|
||||
|
||||
void OptionParser::printOptionDescriptions() {
|
||||
InvokeIfNonNull(Printf, "GWP-ASan: Available options:\n");
|
||||
for (size_t I = 0; I < NumberOfOptions; ++I)
|
||||
InvokeIfNonNull(Printf, "\t%s\n\t\t- %s\n", Options[I].Name,
|
||||
Options[I].Desc);
|
||||
}
|
||||
|
||||
const char *getCompileDefinitionGwpAsanDefaultOptions() {
|
||||
#ifdef GWP_ASAN_DEFAULT_OPTIONS
|
||||
return SANITIZER_STRINGIFY(GWP_ASAN_DEFAULT_OPTIONS);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
bool isSeparator(char C) {
|
||||
return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
|
||||
C == '\r';
|
||||
}
|
||||
|
||||
bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
|
||||
|
||||
void OptionParser::skipWhitespace() {
|
||||
while (isSeparator(Buffer[Pos]))
|
||||
++Pos;
|
||||
}
|
||||
|
||||
bool OptionParser::parseOption() {
|
||||
const uintptr_t NameStart = Pos;
|
||||
while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
|
||||
++Pos;
|
||||
|
||||
const char *Name = Buffer + NameStart;
|
||||
if (Buffer[Pos] != '=') {
|
||||
InvokeIfNonNull(Printf, "GWP-ASan: Expected '=' when parsing option '%s'.",
|
||||
Name);
|
||||
return false;
|
||||
}
|
||||
const uintptr_t ValueStart = ++Pos;
|
||||
const char *Value;
|
||||
if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
|
||||
const char Quote = Buffer[Pos++];
|
||||
while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
|
||||
++Pos;
|
||||
if (Buffer[Pos] == 0) {
|
||||
InvokeIfNonNull(Printf, "GWP-ASan: Unterminated string in option '%s'.",
|
||||
Name);
|
||||
return false;
|
||||
}
|
||||
Value = Buffer + ValueStart + 1;
|
||||
++Pos; // consume the closing quote
|
||||
} else {
|
||||
while (!isSeparatorOrNull(Buffer[Pos]))
|
||||
++Pos;
|
||||
Value = Buffer + ValueStart;
|
||||
}
|
||||
|
||||
return setOptionToValue(Name, Value);
|
||||
}
|
||||
|
||||
void OptionParser::parseOptions() {
|
||||
while (true) {
|
||||
skipWhitespace();
|
||||
if (Buffer[Pos] == 0)
|
||||
break;
|
||||
if (!parseOption()) {
|
||||
InvokeIfNonNull(Printf, "GWP-ASan: Options parsing failed.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OptionParser::parseString(const char *S) {
|
||||
if (!S)
|
||||
return;
|
||||
Buffer = S;
|
||||
Pos = 0;
|
||||
parseOptions();
|
||||
}
|
||||
|
||||
bool parseBool(const char *Value, bool *b) {
|
||||
if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
|
||||
strncmp(Value, "false", 5) == 0) {
|
||||
*b = false;
|
||||
return true;
|
||||
}
|
||||
if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
|
||||
strncmp(Value, "true", 4) == 0) {
|
||||
*b = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OptionParser::setOptionToValue(const char *Name, const char *Value) {
|
||||
for (size_t I = 0; I < NumberOfOptions; ++I) {
|
||||
const uintptr_t Len = strlen(Options[I].Name);
|
||||
if (strncmp(Name, Options[I].Name, Len) != 0 || Name[Len] != '=')
|
||||
continue;
|
||||
bool Ok = false;
|
||||
switch (Options[I].Type) {
|
||||
case OptionType::OT_bool:
|
||||
Ok = parseBool(Value, reinterpret_cast<bool *>(Options[I].Var));
|
||||
if (!Ok)
|
||||
InvokeIfNonNull(
|
||||
Printf, "GWP-ASan: Invalid boolean value '%s' for option '%s'.\n",
|
||||
Value, Options[I].Name);
|
||||
break;
|
||||
case OptionType::OT_int:
|
||||
char *ValueEnd;
|
||||
*reinterpret_cast<int *>(Options[I].Var) =
|
||||
static_cast<int>(strtol(Value, &ValueEnd, 10));
|
||||
Ok =
|
||||
*ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
|
||||
if (!Ok)
|
||||
InvokeIfNonNull(
|
||||
Printf, "GWP-ASan: Invalid integer value '%s' for option '%s'.\n",
|
||||
Value, Options[I].Name);
|
||||
break;
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
||||
InvokeIfNonNull(Printf, "GWP-ASan: Unknown option '%s'.", Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OptionParser::registerOption(const char *Name, const char *Desc,
|
||||
OptionType Type, void *Var) {
|
||||
assert(NumberOfOptions < MaxOptions &&
|
||||
"GWP-ASan Error: Ran out of space for options.\n");
|
||||
Options[NumberOfOptions].Name = Name;
|
||||
Options[NumberOfOptions].Desc = Desc;
|
||||
Options[NumberOfOptions].Type = Type;
|
||||
Options[NumberOfOptions].Var = Var;
|
||||
++NumberOfOptions;
|
||||
}
|
||||
|
||||
void registerGwpAsanOptions(OptionParser *parser,
|
||||
gwp_asan::options::Options *o) {
|
||||
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
|
||||
parser->registerOption(#Name, Description, OptionType::OT_##Type, &o->Name);
|
||||
#include "gwp_asan/options.inc"
|
||||
#undef GWP_ASAN_OPTION
|
||||
}
|
||||
|
||||
const char *getGwpAsanDefaultOptions() {
|
||||
return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";
|
||||
}
|
||||
|
||||
Options *getOptionsInternal() {
|
||||
static Options GwpAsanFlags;
|
||||
return &GwpAsanFlags;
|
||||
gwp_asan::options::Options *getOptionsInternal() {
|
||||
static gwp_asan::options::Options GwpAsanOptions;
|
||||
return &GwpAsanOptions;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void initOptions() {
|
||||
__sanitizer::SetCommonFlagsDefaults();
|
||||
namespace gwp_asan {
|
||||
namespace options {
|
||||
|
||||
void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {
|
||||
Options *o = getOptionsInternal();
|
||||
o->setDefaults();
|
||||
|
||||
__sanitizer::FlagParser Parser;
|
||||
registerGwpAsanFlags(&Parser, o);
|
||||
OptionParser Parser(PrintfForWarnings);
|
||||
registerGwpAsanOptions(&Parser, o);
|
||||
|
||||
// Override from compile definition.
|
||||
Parser.ParseString(getCompileDefinitionGwpAsanDefaultOptions());
|
||||
// Override from the weak function definition in this executable.
|
||||
Parser.parseString(getGwpAsanDefaultOptions());
|
||||
|
||||
// Override from user-specified string.
|
||||
Parser.ParseString(getGwpAsanDefaultOptions());
|
||||
// Override from the provided options string.
|
||||
Parser.parseString(OptionsStr);
|
||||
|
||||
// Override from environment.
|
||||
Parser.ParseString(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"));
|
||||
|
||||
__sanitizer::InitializeCommonFlags();
|
||||
if (__sanitizer::Verbosity())
|
||||
__sanitizer::ReportUnrecognizedFlags();
|
||||
if (o->help)
|
||||
Parser.printOptionDescriptions();
|
||||
|
||||
if (!o->Enabled)
|
||||
return;
|
||||
|
||||
// Sanity checks for the parameters.
|
||||
if (o->MaxSimultaneousAllocations <= 0) {
|
||||
__sanitizer::Printf("GWP-ASan ERROR: MaxSimultaneousAllocations must be > "
|
||||
"0 when GWP-ASan is enabled.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
InvokeIfNonNull(
|
||||
PrintfForWarnings,
|
||||
"GWP-ASan ERROR: MaxSimultaneousAllocations must be > 0 when GWP-ASan "
|
||||
"is enabled.\n");
|
||||
o->Enabled = false;
|
||||
}
|
||||
|
||||
if (o->SampleRate < 1) {
|
||||
__sanitizer::Printf(
|
||||
if (o->SampleRate <= 0) {
|
||||
InvokeIfNonNull(
|
||||
PrintfForWarnings,
|
||||
"GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
o->Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void initOptions(Printf_t PrintfForWarnings) {
|
||||
initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);
|
||||
}
|
||||
|
||||
Options &getOptions() { return *getOptionsInternal(); }
|
||||
|
||||
} // namespace options
|
||||
|
|
|
@ -9,14 +9,15 @@
|
|||
#ifndef GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
|
||||
#define GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
|
||||
|
||||
#include "gwp_asan/optional/backtrace.h"
|
||||
#include "gwp_asan/optional/printf.h"
|
||||
#include "gwp_asan/options.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
||||
namespace gwp_asan {
|
||||
namespace options {
|
||||
// Parse the options from the GWP_ASAN_FLAGS environment variable.
|
||||
void initOptions();
|
||||
// Parse the options from the GWP_ASAN_OPTIONS environment variable.
|
||||
void initOptions(Printf_t PrintfForWarnings = nullptr);
|
||||
// Parse the options from the provided string.
|
||||
void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings = nullptr);
|
||||
// Returns the initialised options. Call initOptions() prior to calling this
|
||||
// function.
|
||||
Options &getOptions();
|
||||
|
@ -24,8 +25,7 @@ Options &getOptions();
|
|||
} // namespace gwp_asan
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *
|
||||
__gwp_asan_default_options();
|
||||
__attribute__((weak)) const char *__gwp_asan_default_options();
|
||||
}
|
||||
|
||||
#endif // GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
|
||||
|
|
|
@ -62,3 +62,18 @@ GWP_ASAN_OPTION(
|
|||
GWP_ASAN_OPTION(bool, InstallForkHandlers, true,
|
||||
"Install GWP-ASan atfork handlers to acquire internal locks "
|
||||
"before fork and release them after.")
|
||||
|
||||
GWP_ASAN_OPTION(bool, help, false, "Print a summary of the available options.")
|
||||
|
||||
// =============================================================================
|
||||
// ==== WARNING
|
||||
// =============================================================================
|
||||
// If you are adding flags to GWP-ASan, please note that GWP-ASan flag strings
|
||||
// may be parsed by trusted system components (on Android, GWP-ASan flag strings
|
||||
// are parsed by libc during the dynamic loader). This means that GWP-ASan
|
||||
// should never feature flags like log paths on disk, because this can lead to
|
||||
// arbitrary file write and thus privilege escalation. For an example, see the
|
||||
// setuid ASan log_path exploits: https://www.exploit-db.com/exploits/46241.
|
||||
//
|
||||
// Please place all new flags above this warning, so that the warning always
|
||||
// stays at the bottom.
|
||||
|
|
|
@ -23,7 +23,8 @@ set(GWP_ASAN_UNITTESTS
|
|||
thread_contention.cpp
|
||||
harness.cpp
|
||||
enable_disable.cpp
|
||||
late_init.cpp)
|
||||
late_init.cpp
|
||||
options.cpp)
|
||||
|
||||
set(GWP_ASAN_UNIT_TEST_HEADERS
|
||||
${GWP_ASAN_HEADERS}
|
||||
|
@ -48,6 +49,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST GWP_ASAN_SUPPORTED_ARCH)
|
|||
$<TARGET_OBJECTS:RTGwpAsan.${arch}>
|
||||
$<TARGET_OBJECTS:RTGwpAsanBacktraceSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTGwpAsanSegvHandler.${arch}>
|
||||
$<TARGET_OBJECTS:RTGwpAsanOptionsParser.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>)
|
||||
|
|
63
compiler-rt/lib/gwp_asan/tests/options.cpp
Normal file
63
compiler-rt/lib/gwp_asan/tests/options.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//===-- options.cpp ---------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gwp_asan/tests/harness.h"
|
||||
|
||||
#include "gwp_asan/optional/options_parser.h"
|
||||
#include "gwp_asan/options.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static char Message[1024];
|
||||
void MessageRecorder(const char *Format, ...) {
|
||||
va_list Args;
|
||||
va_start(Args, Format);
|
||||
vsprintf(Message + strlen(Message), Format, Args);
|
||||
va_end(Args);
|
||||
}
|
||||
|
||||
TEST(GwpAsanOptionsTest, Basic) {
|
||||
Message[0] = '\0';
|
||||
gwp_asan::options::initOptions("Enabled=0:SampleRate=4:"
|
||||
"InstallSignalHandlers=false",
|
||||
MessageRecorder);
|
||||
gwp_asan::options::Options Opts = gwp_asan::options::getOptions();
|
||||
EXPECT_EQ('\0', Message[0]);
|
||||
EXPECT_FALSE(Opts.Enabled);
|
||||
EXPECT_FALSE(Opts.InstallSignalHandlers);
|
||||
EXPECT_EQ(4, Opts.SampleRate);
|
||||
}
|
||||
|
||||
void RunErrorTest(const char *OptionsStr, const char *ErrorNeedle) {
|
||||
Message[0] = '\0';
|
||||
gwp_asan::options::initOptions(OptionsStr, MessageRecorder);
|
||||
EXPECT_NE('\0', Message[0])
|
||||
<< "Options string \"" << OptionsStr << "\" didn't generate an error.";
|
||||
EXPECT_NE(nullptr, strstr(Message, ErrorNeedle))
|
||||
<< "Couldn't find error needle \"" << ErrorNeedle
|
||||
<< "\" in haystack created by options string \"" << OptionsStr
|
||||
<< "\". Error was: \"" << Message << "\".";
|
||||
}
|
||||
|
||||
TEST(GwpAsanOptionsTest, FailureModes) {
|
||||
RunErrorTest("Enabled=2", "Invalid boolean value '2' for option 'Enabled'");
|
||||
RunErrorTest("Enabled=1:MaxSimultaneousAllocations=0",
|
||||
"MaxSimultaneousAllocations must be > 0");
|
||||
RunErrorTest("Enabled=1:MaxSimultaneousAllocations=-1",
|
||||
"MaxSimultaneousAllocations must be > 0");
|
||||
RunErrorTest("Enabled=1:SampleRate=0", "SampleRate must be > 0");
|
||||
RunErrorTest("Enabled=1:SampleRate=-1", "SampleRate must be > 0");
|
||||
RunErrorTest("Enabled=", "Invalid boolean value '' for option 'Enabled'");
|
||||
RunErrorTest("==", "Unknown option '=='");
|
||||
RunErrorTest("Enabled==0", "Invalid boolean value '=0' for option 'Enabled'");
|
||||
RunErrorTest("Enabled:", "Expected '=' when parsing option 'Enabled:'");
|
||||
RunErrorTest("Enabled:=", "Expected '=' when parsing option 'Enabled:='");
|
||||
RunErrorTest("SampleRate=NOT_A_NUMBER",
|
||||
"Invalid integer value 'NOT_A_NUMBER' for option 'SampleRate'");
|
||||
RunErrorTest("NOT_A_VALUE=0", "Unknown option 'NOT_A_VALUE");
|
||||
}
|
|
@ -672,7 +672,8 @@ static BackendT &getBackend() {
|
|||
void initScudo() {
|
||||
Instance.init();
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
gwp_asan::options::initOptions();
|
||||
gwp_asan::options::initOptions(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"),
|
||||
Printf);
|
||||
gwp_asan::options::Options &Opts = gwp_asan::options::getOptions();
|
||||
Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
|
||||
GuardedAlloc.init(Opts);
|
||||
|
|
|
@ -120,7 +120,7 @@ set(SCUDO_OBJECT_LIBS)
|
|||
|
||||
if (COMPILER_RT_HAS_GWP_ASAN)
|
||||
list(APPEND SCUDO_OBJECT_LIBS
|
||||
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler)
|
||||
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler RTGwpAsanOptionsParser)
|
||||
list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#ifdef GWP_ASAN_HOOKS
|
||||
#include "gwp_asan/guarded_pool_allocator.h"
|
||||
#include "gwp_asan/optional/backtrace.h"
|
||||
#include "gwp_asan/optional/options_parser.h"
|
||||
#include "gwp_asan/optional/segv_handler.h"
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
|
@ -183,17 +184,12 @@ public:
|
|||
// be functional, best called from PostInitCallback.
|
||||
void initGwpAsan() {
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
gwp_asan::options::Options Opt;
|
||||
Opt.Enabled = getFlags()->GWP_ASAN_Enabled;
|
||||
// Bear in mind - Scudo has its own alignment guarantees that are strictly
|
||||
// enforced. Scudo exposes the same allocation function for everything from
|
||||
// malloc() to posix_memalign, so in general this flag goes unused, as Scudo
|
||||
// will always ask GWP-ASan for an aligned amount of bytes.
|
||||
Opt.PerfectlyRightAlign = getFlags()->GWP_ASAN_PerfectlyRightAlign;
|
||||
Opt.MaxSimultaneousAllocations =
|
||||
getFlags()->GWP_ASAN_MaxSimultaneousAllocations;
|
||||
Opt.SampleRate = getFlags()->GWP_ASAN_SampleRate;
|
||||
Opt.InstallSignalHandlers = getFlags()->GWP_ASAN_InstallSignalHandlers;
|
||||
gwp_asan::options::initOptions(getEnv("GWP_ASAN_OPTIONS"), Printf);
|
||||
gwp_asan::options::Options Opt = gwp_asan::options::getOptions();
|
||||
// Embedded GWP-ASan is locked through the Scudo atfork handler (via
|
||||
// Allocator::disable calling GWPASan.disable). Disable GWP-ASan's atfork
|
||||
// handler.
|
||||
|
|
|
@ -23,13 +23,6 @@ void Flags::setDefaults() {
|
|||
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
|
||||
#include "flags.inc"
|
||||
#undef SCUDO_FLAG
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
|
||||
GWP_ASAN_##Name = DefaultValue;
|
||||
#include "gwp_asan/options.inc"
|
||||
#undef GWP_ASAN_OPTION
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
}
|
||||
|
||||
void registerFlags(FlagParser *Parser, Flags *F) {
|
||||
|
@ -38,14 +31,6 @@ void registerFlags(FlagParser *Parser, Flags *F) {
|
|||
reinterpret_cast<void *>(&F->Name));
|
||||
#include "flags.inc"
|
||||
#undef SCUDO_FLAG
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
|
||||
Parser->registerFlag("GWP_ASAN_" #Name, Description, FlagType::FT_##Type, \
|
||||
reinterpret_cast<void *>(&F->GWP_ASAN_##Name));
|
||||
#include "gwp_asan/options.inc"
|
||||
#undef GWP_ASAN_OPTION
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
}
|
||||
|
||||
static const char *getCompileDefinitionScudoDefaultOptions() {
|
||||
|
|
|
@ -45,7 +45,7 @@ macro(add_scudo_unittest testname)
|
|||
cmake_parse_arguments(TEST "" "" "SOURCES;ADDITIONAL_RTOBJECTS" ${ARGN})
|
||||
if (COMPILER_RT_HAS_GWP_ASAN)
|
||||
list(APPEND TEST_ADDITIONAL_RTOBJECTS
|
||||
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler)
|
||||
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler RTGwpAsanOptionsParser)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
|
|
|
@ -117,18 +117,3 @@ TEST(ScudoFlagsTest, AllocatorFlags) {
|
|||
EXPECT_TRUE(Flags.delete_size_mismatch);
|
||||
EXPECT_EQ(2048, Flags.quarantine_max_chunk_size);
|
||||
}
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
TEST(ScudoFlagsTest, GWPASanFlags) {
|
||||
scudo::FlagParser Parser;
|
||||
scudo::Flags Flags;
|
||||
scudo::registerFlags(&Parser, &Flags);
|
||||
Flags.setDefaults();
|
||||
Flags.GWP_ASAN_Enabled = false;
|
||||
Parser.parseString("GWP_ASAN_Enabled=true:GWP_ASAN_SampleRate=1:"
|
||||
"GWP_ASAN_InstallSignalHandlers=false");
|
||||
EXPECT_TRUE(Flags.GWP_ASAN_Enabled);
|
||||
EXPECT_FALSE(Flags.GWP_ASAN_InstallSignalHandlers);
|
||||
EXPECT_EQ(1, Flags.GWP_ASAN_SampleRate);
|
||||
}
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
|
|
@ -13,4 +13,4 @@ config.test_source_root = config.test_exec_root
|
|||
|
||||
# Disable GWP-ASan for scudo internal tests.
|
||||
if config.gwp_asan:
|
||||
config.environment['SCUDO_OPTIONS'] = 'GWP_ASAN_Enabled=0'
|
||||
config.environment['GWP_ASAN_OPTIONS'] = 'Enabled=false'
|
||||
|
|
|
@ -14,7 +14,20 @@ if (LLVM_USE_SANITIZE_COVERAGE)
|
|||
target_include_directories(
|
||||
stack_trace_compressor_fuzzer PRIVATE ../../lib/)
|
||||
|
||||
add_executable(options_parser_fuzzer
|
||||
../../lib/gwp_asan/optional/options_parser.cpp
|
||||
../../lib/gwp_asan/optional/options_parser.h
|
||||
options_parser_fuzzer.cpp)
|
||||
set_target_properties(
|
||||
options_parser_fuzzer PROPERTIES FOLDER "Fuzzers")
|
||||
target_compile_options(
|
||||
options_parser_fuzzer PRIVATE -fsanitize=fuzzer-no-link)
|
||||
set_target_properties(
|
||||
options_parser_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
|
||||
target_include_directories(
|
||||
options_parser_fuzzer PRIVATE ../../lib/)
|
||||
|
||||
if (TARGET gwp_asan)
|
||||
add_dependencies(gwp_asan stack_trace_compressor_fuzzer)
|
||||
add_dependencies(gwp_asan stack_trace_compressor_fuzzer options_parser_fuzzer)
|
||||
endif()
|
||||
endif()
|
||||
|
|
12
compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp
Normal file
12
compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
|
||||
#include "gwp_asan/optional/options_parser.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzedDataProvider Fdp(Data, Size);
|
||||
gwp_asan::options::initOptions(Fdp.ConsumeRemainingBytesAsString().c_str());
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user