diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 06:58:08 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 06:58:08 +0000 |
commit | 1d6dcb5ed4e62d56c21deecb68a7394172b1a8df (patch) | |
tree | 2552b2460f512b2a12eda5710d8a596f3dcb9b01 | |
parent | d4625122c3db5003390cfa5f1d6ffe3ea0e30afa (diff) | |
parent | 08d235034c8721d98a323ebad3af1329c58e62ec (diff) | |
download | gwp_asan-android13-mainline-tethering-release.tar.gz |
Snap for 8564071 from 08d235034c8721d98a323ebad3af1329c58e62ec to mainline-tethering-releaseaml_tet_331910040aml_tet_331820050aml_tet_331711040aml_tet_331511160aml_tet_331511000aml_tet_331412030aml_tet_331312080aml_tet_331117000aml_tet_331012080aml_tet_330911010aml_tet_330812150android13-mainline-tethering-release
Change-Id: Iccedcf83c32ee183f4042797f4f42af2cfc56101
-rw-r--r-- | Android.bp | 14 | ||||
-rw-r--r-- | android/test_backtrace.cpp | 23 | ||||
-rw-r--r-- | gwp_asan/common.h | 57 | ||||
-rw-r--r-- | gwp_asan/guarded_pool_allocator.cpp | 12 | ||||
-rwxr-xr-x | gwp_asan/scripts/symbolize.sh | 8 | ||||
-rw-r--r-- | gwp_asan/tests/alignment.cpp | 42 | ||||
-rw-r--r-- | gwp_asan/tests/backtrace.cpp | 9 | ||||
-rw-r--r-- | gwp_asan/tests/enable_disable.cpp | 2 | ||||
-rw-r--r-- | gwp_asan/tests/harness.h | 5 | ||||
-rw-r--r-- | gwp_asan/tests/iterate.cpp | 1 |
10 files changed, 127 insertions, 46 deletions
@@ -71,7 +71,12 @@ cc_defaults { // GWP-ASan is used by bionic libc, and should have no libc/libc++ // dependencies. - system_shared_libs: [], + target: { + bionic: { + system_shared_libs: [], + header_libs: ["libc_headers"], + }, + }, stl: "none", } @@ -95,6 +100,7 @@ cc_library_headers { "com.android.art.debug", "com.android.media", "com.android.media.swcodec", + "com.android.virt", ], } @@ -104,7 +110,6 @@ cc_library_static { defaults: ["gwp_asan_no_libs_defaults"], header_libs: [ "gwp_asan_headers", - "libc_headers", // Required for pthread.h in mutex.h. ], srcs: [ "gwp_asan/common.cpp", @@ -139,7 +144,6 @@ cc_library { defaults: ["gwp_asan_defaults"], header_libs: [ "gwp_asan_headers", - "libc_headers", // Required for assert.h ], srcs: [ "gwp_asan/common.cpp", @@ -222,9 +226,5 @@ cc_test { // Ensure that the helper functions in test/backtrace.cpp don't get // tail-call optimised, as this breaks the unwind chain. "-fno-optimize-sibling-calls", - - // The experimental pass manager seems to kill __attribute__((optnone)), - // and so we disable it (as we rely on optnone for tests/backtrace.cpp). - "-fno-experimental-new-pass-manager", ], } diff --git a/android/test_backtrace.cpp b/android/test_backtrace.cpp index 4a6d20d..0d397fd 100644 --- a/android/test_backtrace.cpp +++ b/android/test_backtrace.cpp @@ -18,7 +18,10 @@ #include "gwp_asan/optional/backtrace.h" #include "gwp_asan/optional/segv_handler.h" -#include <unwindstack/LocalUnwinder.h> +#include <unwindstack/Maps.h> +#include <unwindstack/Memory.h> +#include <unwindstack/Regs.h> +#include <unwindstack/RegsGetLocal.h> #include <unwindstack/Unwinder.h> namespace { @@ -32,19 +35,21 @@ namespace { // potentially more detailed stack frames in the allocation/deallocation traces // (as we don't use the production unwinder), but that's fine for test-only. size_t BacktraceUnwindstack(uintptr_t *TraceBuffer, size_t Size) { - unwindstack::LocalUnwinder unwinder; - if (!unwinder.Init()) { - return 0; - } - std::vector<unwindstack::LocalFrameData> frames; - if (!unwinder.Unwind(&frames, Size)) { + unwindstack::LocalMaps maps; + if (!maps.Parse()) { return 0; } - for (const auto &frame : frames) { + + auto process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid()); + std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal()); + unwindstack::RegsGetLocal(regs.get()); + unwindstack::Unwinder unwinder(Size, &maps, regs.get(), process_memory); + unwinder.Unwind(); + for (const auto &frame : unwinder.frames()) { *TraceBuffer = frame.pc; TraceBuffer++; } - return frames.size(); + return unwinder.NumFrames(); } // We don't need any custom handling for the Segv backtrace - the unwindstack diff --git a/gwp_asan/common.h b/gwp_asan/common.h index 7ce367e..6b238ad 100644 --- a/gwp_asan/common.h +++ b/gwp_asan/common.h @@ -19,7 +19,28 @@ #include <stdint.h> namespace gwp_asan { -enum class Error { + +// Magic header that resides in the AllocatorState so that GWP-ASan bugreports +// can be understood by tools at different versions. Out-of-process crash +// handlers, like crashpad on Fuchsia, take the raw contents of the +// AllocationMetatada array and the AllocatorState, and shove them into the +// minidump. Online unpacking of these structs needs to know from which version +// of GWP-ASan it's extracting the information, as the structures are not +// stable. +struct AllocatorVersionMagic { + // The values are copied into the structure at runtime, during + // `GuardedPoolAllocator::init()` so that GWP-ASan remains completely in the + // `.bss` segment. + static constexpr uint8_t kAllocatorVersionMagic[4] = {'A', 'S', 'A', 'N'}; + uint8_t Magic[4] = {}; + // Update the version number when the AllocatorState or AllocationMetadata + // change. + static constexpr uint16_t kAllocatorVersion = 1; + uint16_t Version = 0; + uint16_t Reserved = 0; +}; + +enum class Error : uint8_t { UNKNOWN, USE_AFTER_FREE, DOUBLE_FREE, @@ -84,6 +105,7 @@ struct AllocationMetadata { // set of information required for understanding a GWP-ASan crash. struct AllocatorState { constexpr AllocatorState() {} + AllocatorVersionMagic VersionMagic{}; // Returns whether the provided pointer is a current sampled allocation that // is owned by this pool. @@ -123,5 +145,38 @@ struct AllocatorState { uintptr_t FailureAddress = 0; }; +// Below are various compile-time checks that the layout of the internal +// GWP-ASan structures are undisturbed. If they are disturbed, the version magic +// number needs to be increased by one, and the asserts need to be updated. +// Out-of-process crash handlers, like breakpad/crashpad, may copy the internal +// GWP-ASan structures into a minidump for offline reconstruction of the crash. +// In order to accomplish this, the offline reconstructor needs to know the +// version of GWP-ASan internal structures that it's unpacking (along with the +// architecture-specific layout info, which is left as an exercise to the crash +// handler). +static_assert(offsetof(AllocatorState, VersionMagic) == 0, ""); +static_assert(sizeof(AllocatorVersionMagic) == 8, ""); +#if defined(__x86_64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__aarch64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__i386__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 548, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 544, ""); +#elif defined(__arm__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 560, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 552, ""); +#endif // defined($ARCHITECTURE) + } // namespace gwp_asan #endif // GWP_ASAN_COMMON_H_ diff --git a/gwp_asan/guarded_pool_allocator.cpp b/gwp_asan/guarded_pool_allocator.cpp index d784927..7096b42 100644 --- a/gwp_asan/guarded_pool_allocator.cpp +++ b/gwp_asan/guarded_pool_allocator.cpp @@ -59,6 +59,13 @@ void GuardedPoolAllocator::init(const options::Options &Opts) { SingletonPtr = this; Backtrace = Opts.Backtrace; + State.VersionMagic = {{AllocatorVersionMagic::kAllocatorVersionMagic[0], + AllocatorVersionMagic::kAllocatorVersionMagic[1], + AllocatorVersionMagic::kAllocatorVersionMagic[2], + AllocatorVersionMagic::kAllocatorVersionMagic[3]}, + AllocatorVersionMagic::kAllocatorVersion, + 0}; + State.MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations; const size_t PageSize = getPlatformPageSize(); @@ -258,7 +265,10 @@ void GuardedPoolAllocator::trapOnAddress(uintptr_t Address, Error E) { // Raise a SEGV by touching first guard page. volatile char *p = reinterpret_cast<char *>(State.GuardedPagePool); *p = 0; - __builtin_unreachable(); + // Normally, would be __builtin_unreachable(), but because of + // https://bugs.llvm.org/show_bug.cgi?id=47480, unreachable will DCE the + // volatile store above, even though it has side effects. + __builtin_trap(); } void GuardedPoolAllocator::stop() { diff --git a/gwp_asan/scripts/symbolize.sh b/gwp_asan/scripts/symbolize.sh index fad9620..0027fa0 100755 --- a/gwp_asan/scripts/symbolize.sh +++ b/gwp_asan/scripts/symbolize.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # The lines that we're looking to symbolize look like this: #0 ./a.out(_foo+0x3e6) [0x55a52e64c696] @@ -25,7 +25,7 @@ while read -r line; do if [ -z "$function_name" ]; then # If the offset is binary-relative, just resolve that. - symbolized="$(echo $function_offset | addr2line -e $binary_name)" + symbolized="$(echo $function_offset | addr2line -ie $binary_name)" else # Otherwise, the offset is function-relative. Get the address of the # function, and add it to the offset, then symbolize. @@ -41,7 +41,7 @@ while read -r line; do # Add the function address and offset to get the offset into the binary. binary_offset="$(printf "0x%X" "$((function_addr+function_offset))")" - symbolized="$(echo $binary_offset | addr2line -e $binary_name)" + symbolized="$(echo $binary_offset | addr2line -ie $binary_name)" fi # Check that it symbolized properly. If it didn't, output the old line. @@ -52,4 +52,4 @@ while read -r line; do else echo "${frame_number}${symbolized}" fi -done +done 2> >(grep -v "addr2line: DWARF error: could not find variable specification") diff --git a/gwp_asan/tests/alignment.cpp b/gwp_asan/tests/alignment.cpp index 5f24a9a..6d1e912 100644 --- a/gwp_asan/tests/alignment.cpp +++ b/gwp_asan/tests/alignment.cpp @@ -34,81 +34,81 @@ public: // numerics of the testing. TEST(AlignmentTest, LeftAlignedAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::alignUp( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignUp( /* Ptr */ 0x4000, /* Alignment */ 0x4000)); } TEST(AlignmentTest, SingleByteAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x1, + EXPECT_EQ(0x1u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7fff, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7fffu, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x1, + EXPECT_EQ(0x1u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x3001, + EXPECT_EQ(0x3001u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1, /* Alignment */ 0x4000)); } TEST(AlignmentTest, PageSizedAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x1000, + EXPECT_EQ(0x1000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x1000, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x1000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x7000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x7000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x4000, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x4000u, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x1000, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x1000, /* Alignment */ 0x4000)); } TEST(AlignmentTest, MoreThanPageAllocs) { // Alignment < Page Size. - EXPECT_EQ(0x2fff, + EXPECT_EQ(0x2fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x1, /* PageSize */ 0x1000)); - EXPECT_EQ(0x5001, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x5001u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x1)); // Alignment == Page Size. - EXPECT_EQ(0x2fff, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x2fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x1000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x5000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x5000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x1000)); // Alignment > Page Size. - EXPECT_EQ(0x5fff, AlignmentTestGPA::getRequiredBackingSize( + EXPECT_EQ(0x5fffu, AlignmentTestGPA::getRequiredBackingSize( /* Size */ 0x2fff, /* Alignment */ 0x4000, /* PageSize */ 0x1000)); - EXPECT_EQ(0x4000, AlignmentTestGPA::alignDown( + EXPECT_EQ(0x4000u, AlignmentTestGPA::alignDown( /* Ptr */ 0x8000 - 0x2fff, /* Alignment */ 0x4000)); } diff --git a/gwp_asan/tests/backtrace.cpp b/gwp_asan/tests/backtrace.cpp index 9515065..a4eb8eb 100644 --- a/gwp_asan/tests/backtrace.cpp +++ b/gwp_asan/tests/backtrace.cpp @@ -30,7 +30,7 @@ __attribute__((optnone)) void TouchMemory(void *Ptr) { *(reinterpret_cast<volatile char *>(Ptr)) = 7; } -TEST_F(BacktraceGuardedPoolAllocator, DoubleFree) { +TEST_F(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) { void *Ptr = AllocateMemory(GPA); DeallocateMemory(GPA, Ptr); @@ -45,7 +45,12 @@ TEST_F(BacktraceGuardedPoolAllocator, DoubleFree) { ASSERT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex); } -TEST_F(BacktraceGuardedPoolAllocator, UseAfterFree) { +TEST_F(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) { +#if defined(__linux__) && __ARM_ARCH == 7 + // Incomplete backtrace on Armv7 Linux + GTEST_SKIP(); +#endif + void *Ptr = AllocateMemory(GPA); DeallocateMemory(GPA, Ptr); diff --git a/gwp_asan/tests/enable_disable.cpp b/gwp_asan/tests/enable_disable.cpp index 2c6ba51..98da591 100644 --- a/gwp_asan/tests/enable_disable.cpp +++ b/gwp_asan/tests/enable_disable.cpp @@ -10,7 +10,7 @@ constexpr size_t Size = 100; -TEST_F(DefaultGuardedPoolAllocator, Fork) { +TEST_F(DefaultGuardedPoolAllocatorDeathTest, Fork) { void *P; pid_t Pid = fork(); EXPECT_GE(Pid, 0); diff --git a/gwp_asan/tests/harness.h b/gwp_asan/tests/harness.h index a61b856..ed91e64 100644 --- a/gwp_asan/tests/harness.h +++ b/gwp_asan/tests/harness.h @@ -106,4 +106,9 @@ protected: gwp_asan::GuardedPoolAllocator GPA; }; +// https://github.com/google/googletest/blob/master/docs/advanced.md#death-tests-and-threads +using DefaultGuardedPoolAllocatorDeathTest = DefaultGuardedPoolAllocator; +using CustomGuardedPoolAllocatorDeathTest = CustomGuardedPoolAllocator; +using BacktraceGuardedPoolAllocatorDeathTest = BacktraceGuardedPoolAllocator; + #endif // GWP_ASAN_TESTS_HARNESS_H_ diff --git a/gwp_asan/tests/iterate.cpp b/gwp_asan/tests/iterate.cpp index 2b8635d..49953f3 100644 --- a/gwp_asan/tests/iterate.cpp +++ b/gwp_asan/tests/iterate.cpp @@ -8,6 +8,7 @@ #include "gwp_asan/tests/harness.h" +#include <algorithm> #include <set> #include <vector> |