[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
//===-- crash_handler_api.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/crash_handler.h"
|
|
|
|
#include "gwp_asan/guarded_pool_allocator.h"
|
|
|
|
#include "gwp_asan/stack_trace_compressor.h"
|
|
|
|
#include "gwp_asan/tests/harness.h"
|
|
|
|
|
|
|
|
using Error = gwp_asan::Error;
|
|
|
|
using GuardedPoolAllocator = gwp_asan::GuardedPoolAllocator;
|
|
|
|
using AllocationMetadata = gwp_asan::AllocationMetadata;
|
|
|
|
using AllocatorState = gwp_asan::AllocatorState;
|
|
|
|
|
|
|
|
class CrashHandlerAPITest : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
void SetUp() override { setupState(); }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
size_t metadata(uintptr_t Addr, uintptr_t Size, bool IsDeallocated) {
|
|
|
|
// Should only be allocating the 0x3000, 0x5000, 0x7000, 0x9000 pages.
|
|
|
|
EXPECT_GE(Addr, 0x3000u);
|
|
|
|
EXPECT_LT(Addr, 0xa000u);
|
|
|
|
|
|
|
|
size_t Slot = State.getNearestSlot(Addr);
|
|
|
|
|
|
|
|
Metadata[Slot].Addr = Addr;
|
|
|
|
Metadata[Slot].Size = Size;
|
|
|
|
Metadata[Slot].IsDeallocated = IsDeallocated;
|
|
|
|
Metadata[Slot].AllocationTrace.ThreadID = 123;
|
|
|
|
Metadata[Slot].DeallocationTrace.ThreadID = 321;
|
|
|
|
setupBacktraces(&Metadata[Slot]);
|
|
|
|
|
|
|
|
return Slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupState() {
|
|
|
|
State.GuardedPagePool = 0x2000;
|
|
|
|
State.GuardedPagePoolEnd = 0xb000;
|
|
|
|
State.MaxSimultaneousAllocations = 4; // 0x3000, 0x5000, 0x7000, 0x9000.
|
|
|
|
State.PageSize = 0x1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupBacktraces(AllocationMetadata *Meta) {
|
|
|
|
Meta->AllocationTrace.TraceSize = gwp_asan::compression::pack(
|
|
|
|
BacktraceConstants, kNumBacktraceConstants,
|
|
|
|
Meta->AllocationTrace.CompressedTrace,
|
|
|
|
AllocationMetadata::kStackFrameStorageBytes);
|
|
|
|
|
|
|
|
if (Meta->IsDeallocated)
|
|
|
|
Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack(
|
|
|
|
BacktraceConstants, kNumBacktraceConstants,
|
|
|
|
Meta->DeallocationTrace.CompressedTrace,
|
|
|
|
AllocationMetadata::kStackFrameStorageBytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkBacktrace(const AllocationMetadata *Meta, bool IsDeallocated) {
|
|
|
|
uintptr_t Buffer[kNumBacktraceConstants];
|
|
|
|
size_t NumBacktraceConstants = kNumBacktraceConstants;
|
2020-02-06 09:31:27 +08:00
|
|
|
EXPECT_EQ(NumBacktraceConstants, __gwp_asan_get_allocation_trace(
|
|
|
|
Meta, Buffer, kNumBacktraceConstants));
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
for (size_t i = 0; i < kNumBacktraceConstants; ++i)
|
|
|
|
EXPECT_EQ(Buffer[i], BacktraceConstants[i]);
|
|
|
|
|
|
|
|
if (IsDeallocated) {
|
|
|
|
EXPECT_EQ(NumBacktraceConstants,
|
2020-02-06 09:31:27 +08:00
|
|
|
__gwp_asan_get_deallocation_trace(Meta, Buffer,
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
kNumBacktraceConstants));
|
|
|
|
for (size_t i = 0; i < kNumBacktraceConstants; ++i)
|
|
|
|
EXPECT_EQ(Buffer[i], BacktraceConstants[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkMetadata(size_t Index, uintptr_t ErrorPtr) {
|
|
|
|
const AllocationMetadata *Meta =
|
|
|
|
__gwp_asan_get_metadata(&State, Metadata, ErrorPtr);
|
|
|
|
EXPECT_NE(nullptr, Meta);
|
2020-02-06 09:31:27 +08:00
|
|
|
EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(Meta));
|
|
|
|
EXPECT_EQ(Metadata[Index].Size, __gwp_asan_get_allocation_size(Meta));
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID,
|
2020-02-06 09:31:27 +08:00
|
|
|
__gwp_asan_get_allocation_thread_id(Meta));
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
|
2020-02-06 09:31:27 +08:00
|
|
|
bool IsDeallocated = __gwp_asan_is_deallocated(Meta);
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated);
|
|
|
|
checkBacktrace(Meta, IsDeallocated);
|
|
|
|
|
|
|
|
if (!IsDeallocated)
|
|
|
|
return;
|
|
|
|
|
|
|
|
EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID,
|
2020-02-06 09:31:27 +08:00
|
|
|
__gwp_asan_get_deallocation_thread_id(Meta));
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr size_t kNumBacktraceConstants = 4;
|
|
|
|
static uintptr_t BacktraceConstants[kNumBacktraceConstants];
|
|
|
|
AllocatorState State = {};
|
|
|
|
AllocationMetadata Metadata[4] = {};
|
|
|
|
};
|
|
|
|
|
|
|
|
uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = {
|
2020-02-06 08:46:51 +08:00
|
|
|
0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d};
|
[GWP-ASan] Crash Handler API.
Summary:
Forewarning: This patch looks big in #LOC changed. I promise it's not that bad, it just moves a lot of content from one file to another. I've gone ahead and left inline comments on Phabricator for sections where this has happened.
This patch:
1. Introduces the crash handler API (crash_handler_api.h).
2. Moves information required for out-of-process crash handling into an AllocatorState. This is a trivially-copied POD struct that designed to be recovered from a deceased process, and used by the crash handler to create a GWP-ASan report (along with the other trivially-copied Metadata struct).
3. Implements the crash handler API using the AllocatorState and Metadata.
4. Adds tests for the crash handler.
5. Reimplements the (now optionally linked by the supporting allocator) in-process crash handler (i.e. the segv handler) using the new crash handler API.
6. Minor updates Scudo & Scudo Standalone to fix compatibility.
7. Changed capitalisation of errors (e.g. /s/Use after free/Use After Free).
Reviewers: cryptoad, eugenis, jfb
Reviewed By: eugenis
Subscribers: merge_guards_bot, pcc, jfb, dexonsmith, mgorny, cryptoad, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D73557
2020-02-06 07:39:03 +08:00
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, PointerNotMine) {
|
|
|
|
uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State);
|
|
|
|
|
|
|
|
EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0));
|
|
|
|
EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr));
|
|
|
|
|
|
|
|
EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0));
|
|
|
|
EXPECT_EQ(Error::UNKNOWN,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, UnknownPtr));
|
|
|
|
|
|
|
|
EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0));
|
|
|
|
EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, PointerNotAllocated) {
|
|
|
|
uintptr_t FailureAddress = 0x9000;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
|
|
|
|
EXPECT_EQ(Error::UNKNOWN,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
|
|
|
|
EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, DoubleFree) {
|
|
|
|
size_t Index =
|
|
|
|
metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);
|
|
|
|
uintptr_t FailureAddress = 0x7000;
|
|
|
|
|
|
|
|
State.FailureType = Error::DOUBLE_FREE;
|
|
|
|
State.FailureAddress = FailureAddress;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
|
|
|
|
EXPECT_EQ(Error::DOUBLE_FREE,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, 0x0));
|
|
|
|
EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
checkMetadata(Index, FailureAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, InvalidFree) {
|
|
|
|
size_t Index =
|
|
|
|
metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false);
|
|
|
|
uintptr_t FailureAddress = 0x7001;
|
|
|
|
|
|
|
|
State.FailureType = Error::INVALID_FREE;
|
|
|
|
State.FailureAddress = FailureAddress;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
|
|
|
|
EXPECT_EQ(Error::INVALID_FREE,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, 0x0));
|
|
|
|
EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
checkMetadata(Index, FailureAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) {
|
|
|
|
uintptr_t FailureAddress = 0x7001;
|
|
|
|
|
|
|
|
State.FailureType = Error::INVALID_FREE;
|
|
|
|
State.FailureAddress = FailureAddress;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
|
|
|
|
EXPECT_EQ(Error::INVALID_FREE,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, 0x0));
|
|
|
|
EXPECT_EQ(FailureAddress, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, UseAfterFree) {
|
|
|
|
size_t Index =
|
|
|
|
metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);
|
|
|
|
uintptr_t FailureAddress = 0x7001;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
|
|
|
|
EXPECT_EQ(Error::USE_AFTER_FREE,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
|
|
|
|
EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
checkMetadata(Index, FailureAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, BufferOverflow) {
|
|
|
|
size_t Index =
|
|
|
|
metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false);
|
|
|
|
uintptr_t FailureAddress = 0x6000;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
|
|
|
|
EXPECT_EQ(Error::BUFFER_OVERFLOW,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
|
|
|
|
EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
checkMetadata(Index, FailureAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(CrashHandlerAPITest, BufferUnderflow) {
|
|
|
|
size_t Index =
|
|
|
|
metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false);
|
|
|
|
uintptr_t FailureAddress = 0x2fff;
|
|
|
|
|
|
|
|
EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
|
|
|
|
EXPECT_EQ(Error::BUFFER_UNDERFLOW,
|
|
|
|
__gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
|
|
|
|
EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State));
|
|
|
|
checkMetadata(Index, FailureAddress);
|
|
|
|
}
|