mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 22:30:13 +00:00
[Scudo] [GWP-ASan] Add GWP-ASan to Scudo Standalone.
Summary: Adds GWP-ASan to Scudo standalone. Default parameters are pulled across from the GWP-ASan build. No backtrace support as of yet. Reviewers: cryptoad, eugenis, pcc Reviewed By: cryptoad Subscribers: merge_guards_bot, mgorny, #sanitizers, llvm-commits, cferris, vlad.tsyrklevich, pcc Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D71229
This commit is contained in:
parent
c1ef116cd9
commit
ed4618edb3
@ -1,4 +1,5 @@
|
||||
add_compiler_rt_component(scudo_standalone)
|
||||
add_dependencies(scudo_standalone gwp_asan)
|
||||
|
||||
include_directories(../..)
|
||||
|
||||
@ -101,6 +102,13 @@ set(SCUDO_SOURCES_CXX_WRAPPERS
|
||||
wrappers_cpp.cpp
|
||||
)
|
||||
|
||||
set(SCUDO_OBJECT_LIBS)
|
||||
|
||||
if (COMPILER_RT_HAS_GWP_ASAN)
|
||||
list(APPEND SCUDO_OBJECT_LIBS RTGwpAsan)
|
||||
list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
add_compiler_rt_object_libraries(RTScudoStandalone
|
||||
ARCHS ${SCUDO_STANDALONE_SUPPORTED_ARCH}
|
||||
@ -124,6 +132,7 @@ if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
SOURCES ${SCUDO_SOURCES} ${SCUDO_SOURCES_C_WRAPPERS}
|
||||
ADDITIONAL_HEADERS ${SCUDO_HEADERS}
|
||||
CFLAGS ${SCUDO_CFLAGS}
|
||||
OBJECT_LIBS ${SCUDO_OBJECT_LIBS}
|
||||
PARENT_TARGET scudo_standalone)
|
||||
add_compiler_rt_runtime(clang_rt.scudo_standalone_cxx
|
||||
STATIC
|
||||
@ -131,6 +140,7 @@ if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
SOURCES ${SCUDO_SOURCES_CXX_WRAPPERS}
|
||||
ADDITIONAL_HEADERS ${SCUDO_HEADERS}
|
||||
CFLAGS ${SCUDO_CFLAGS}
|
||||
OBJECT_LIBS ${SCUDO_OBJECT_LIBS}
|
||||
PARENT_TARGET scudo_standalone)
|
||||
|
||||
add_subdirectory(benchmarks)
|
||||
|
@ -18,8 +18,19 @@
|
||||
#include "quarantine.h"
|
||||
#include "report.h"
|
||||
#include "secondary.h"
|
||||
#include "string_utils.h"
|
||||
#include "tsd.h"
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
# include "gwp_asan/guarded_pool_allocator.h"
|
||||
// GWP-ASan is declared here in order to avoid indirect call overhead. It's also
|
||||
// instantiated outside of the Allocator class, as the allocator is only
|
||||
// zero-initialised. GWP-ASan requires constant initialisation, and the Scudo
|
||||
// allocator doesn't have a constexpr constructor (see discussion here:
|
||||
// https://reviews.llvm.org/D69265#inline-624315).
|
||||
static gwp_asan::GuardedPoolAllocator GuardedAlloc;
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
namespace scudo {
|
||||
|
||||
template <class Params> class Allocator {
|
||||
@ -133,6 +144,22 @@ public:
|
||||
Quarantine.init(
|
||||
static_cast<uptr>(getFlags()->quarantine_size_kb << 10),
|
||||
static_cast<uptr>(getFlags()->thread_local_quarantine_size_kb << 10));
|
||||
|
||||
#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;
|
||||
Opt.Printf = Printf;
|
||||
GuardedAlloc.init(Opt);
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
}
|
||||
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
@ -164,6 +191,14 @@ public:
|
||||
uptr Alignment = MinAlignment,
|
||||
bool ZeroContents = false) {
|
||||
initThreadMaybe();
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
if (UNLIKELY(GuardedAlloc.shouldSample())) {
|
||||
if (void *Ptr = GuardedAlloc.allocate(roundUpTo(Size, Alignment)))
|
||||
return Ptr;
|
||||
}
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
ZeroContents |= static_cast<bool>(Options.ZeroContents);
|
||||
|
||||
if (UNLIKELY(Alignment > MaxAlignment)) {
|
||||
@ -261,6 +296,13 @@ public:
|
||||
// being destroyed properly. Any other heap operation will do a full init.
|
||||
initThreadMaybe(/*MinimalInit=*/true);
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr))) {
|
||||
GuardedAlloc.deallocate(Ptr);
|
||||
return;
|
||||
}
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
if (&__scudo_deallocate_hook)
|
||||
__scudo_deallocate_hook(Ptr);
|
||||
|
||||
@ -300,6 +342,17 @@ public:
|
||||
DCHECK_NE(OldPtr, nullptr);
|
||||
DCHECK_NE(NewSize, 0);
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
if (UNLIKELY(GuardedAlloc.pointerIsMine(OldPtr))) {
|
||||
uptr OldSize = GuardedAlloc.getSize(OldPtr);
|
||||
void *NewPtr = allocate(NewSize, Chunk::Origin::Malloc, Alignment);
|
||||
if (NewPtr)
|
||||
memcpy(NewPtr, OldPtr, (NewSize < OldSize) ? NewSize : OldSize);
|
||||
GuardedAlloc.deallocate(OldPtr);
|
||||
return NewPtr;
|
||||
}
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
if (UNLIKELY(!isAligned(reinterpret_cast<uptr>(OldPtr), MinAlignment)))
|
||||
reportMisalignedPointer(AllocatorAction::Reallocating, OldPtr);
|
||||
|
||||
@ -446,6 +499,12 @@ public:
|
||||
initThreadMaybe();
|
||||
if (UNLIKELY(!Ptr))
|
||||
return 0;
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr)))
|
||||
return GuardedAlloc.getSize(Ptr);
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
Chunk::UnpackedHeader Header;
|
||||
Chunk::loadHeader(Cookie, Ptr, &Header);
|
||||
// Getting the usable size of a chunk only makes sense if it's allocated.
|
||||
@ -464,6 +523,10 @@ public:
|
||||
// A corrupted chunk will not be reported as owned, which is WAI.
|
||||
bool isOwned(const void *Ptr) {
|
||||
initThreadMaybe();
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
if (GuardedAlloc.pointerIsMine(Ptr))
|
||||
return true;
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
if (!Ptr || !isAligned(reinterpret_cast<uptr>(Ptr), MinAlignment))
|
||||
return false;
|
||||
Chunk::UnpackedHeader Header;
|
||||
|
@ -22,6 +22,13 @@ 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) {
|
||||
@ -30,6 +37,14 @@ 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() {
|
||||
|
@ -17,6 +17,14 @@ struct Flags {
|
||||
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Type Name;
|
||||
#include "flags.inc"
|
||||
#undef SCUDO_FLAG
|
||||
|
||||
#ifdef GWP_ASAN_HOOKS
|
||||
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
|
||||
Type GWP_ASAN_##Name;
|
||||
#include "gwp_asan/options.inc"
|
||||
#undef GWP_ASAN_OPTION
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
void setDefaults();
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
void printFlagDescriptions();
|
||||
|
||||
private:
|
||||
static const u32 MaxFlags = 12;
|
||||
static const u32 MaxFlags = 16;
|
||||
struct Flag {
|
||||
const char *Name;
|
||||
const char *Desc;
|
||||
|
@ -20,6 +20,10 @@ if(ANDROID)
|
||||
list(APPEND SCUDO_UNITTEST_CFLAGS -fno-emulated-tls)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_GWP_ASAN)
|
||||
list(APPEND SCUDO_UNITTEST_CFLAGS -DGWP_ASAN_HOOKS)
|
||||
endif()
|
||||
|
||||
set(SCUDO_TEST_ARCH ${SCUDO_STANDALONE_SUPPORTED_ARCH})
|
||||
|
||||
# gtests requires c++
|
||||
@ -38,6 +42,10 @@ endforeach()
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
|
||||
foreach(arch ${SCUDO_TEST_ARCH})
|
||||
# Additional runtime objects get added along RTScudoStandalone
|
||||
|
@ -117,3 +117,20 @@ TEST(ScudoFlagsTest, AllocatorFlags) {
|
||||
EXPECT_TRUE(Flags.delete_size_mismatch);
|
||||
EXPECT_EQ(2048, Flags.quarantine_max_chunk_size);
|
||||
}
|
||||
|
||||
TEST(ScudoFlagsTest, GWPASanFlags) {
|
||||
#ifndef GWP_ASAN_HOOKS
|
||||
GTEST_SKIP() << "GWP-ASan wasn't built as part of Scudo Standalone.";
|
||||
#endif // GWP_ASAN_HOOKS
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -10,3 +10,7 @@ config.name = 'ScudoStandalone-Unit'
|
||||
# For unit tests, we define it as build directory with unit tests.
|
||||
config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/scudo/standalone/tests"
|
||||
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'
|
||||
|
@ -11,6 +11,7 @@ config.llvm_build_mode = "@LLVM_BUILD_MODE@"
|
||||
config.host_arch = "@HOST_ARCH@"
|
||||
config.host_os = "@HOST_OS@"
|
||||
config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@"
|
||||
config.gwp_asan = @COMPILER_RT_HAS_GWP_ASAN_PYBOOL@
|
||||
|
||||
# LLVM tools dir and build mode can be passed in lit parameters,
|
||||
# so try to apply substitution.
|
||||
|
Loading…
Reference in New Issue
Block a user