diff options
author | Andreas Gampe <agampe@google.com> | 2014-05-20 18:47:40 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-05-20 18:47:41 +0000 |
commit | 07d5fa63f562702d722d9a212fdef8ffc542c5eb (patch) | |
tree | 984f5269e3e16b1eb1d6ff89a360224da4fa0862 | |
parent | 02d2d48f957ba4f93703aeb40a10ae58475817eb (diff) | |
parent | d8f26dbebe72c1cbdfa85bdeeb003283c7435db3 (diff) | |
download | art-07d5fa63f562702d722d9a212fdef8ffc542c5eb.zip art-07d5fa63f562702d722d9a212fdef8ffc542c5eb.tar.gz art-07d5fa63f562702d722d9a212fdef8ffc542c5eb.tar.bz2 |
Merge "ART: Randomize mem_map start address for linear scan search"
-rw-r--r-- | runtime/mem_map.cc | 60 | ||||
-rw-r--r-- | runtime/mem_map.h | 6 | ||||
-rw-r--r-- | runtime/mem_map_test.cc | 33 |
3 files changed, 97 insertions, 2 deletions
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 8a555fb..49e0b54 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -20,6 +20,11 @@ #include <backtrace/BacktraceMap.h> #include <memory> +// See CreateStartPos below. +#ifdef __BIONIC__ +#include <sys/auxv.h> +#endif + #include "base/stringprintf.h" #include "ScopedFd.h" #include "utils.h" @@ -47,10 +52,61 @@ static std::ostream& operator<<( } #if defined(__LP64__) && !defined(__x86_64__) -// Where to start with low memory allocation. The first 64KB is protected by SELinux. +// Handling mem_map in 32b address range for 64b architectures that do not support MAP_32BIT. + +// The regular start of memory allocations. The first 64KB is protected by SELinux. static constexpr uintptr_t LOW_MEM_START = 64 * KB; -uintptr_t MemMap::next_mem_pos_ = LOW_MEM_START; // first page to check for low-mem extent +// Generate random starting position. +// To not interfere with image position, take the image's address and only place it below. Current +// formula (sketch): +// +// ART_BASE_ADDR = 0001XXXXXXXXXXXXXXX +// ---------------------------------------- +// = 0000111111111111111 +// & ~(kPageSize - 1) =~0000000000000001111 +// ---------------------------------------- +// mask = 0000111111111110000 +// & random data = YYYYYYYYYYYYYYYYYYY +// ----------------------------------- +// tmp = 0000YYYYYYYYYYY0000 +// + LOW_MEM_START = 0000000000001000000 +// -------------------------------------- +// start +// +// getauxval as an entropy source is exposed in Bionic, but not in glibc before 2.16. When we +// do not have Bionic, simply start with LOW_MEM_START. + +// Function is standalone so it can be tested somewhat in mem_map_test.cc. +#ifdef __BIONIC__ +uintptr_t CreateStartPos(uint64_t input) { + CHECK_NE(0, ART_BASE_ADDRESS); + + // Start with all bits below highest bit in ART_BASE_ADDRESS. + constexpr size_t leading_zeros = CLZ(static_cast<uint32_t>(ART_BASE_ADDRESS)); + constexpr uintptr_t mask_ones = (1 << (31 - leading_zeros)) - 1; + + // Lowest (usually 12) bits are not used, as aligned by page size. + constexpr uintptr_t mask = mask_ones & ~(kPageSize - 1); + + // Mask input data. + return (input & mask) + LOW_MEM_START; +} +#endif + +static uintptr_t GenerateNextMemPos() { +#ifdef __BIONIC__ + uint8_t* random_data = reinterpret_cast<uint8_t*>(getauxval(AT_RANDOM)); + // The lower 8B are taken for the stack guard. Use the upper 8B (with mask). + return CreateStartPos(*reinterpret_cast<uintptr_t*>(random_data + 8)); +#else + // No auxv on host, see above. + return LOW_MEM_START; +#endif +} + +// Initialize linear scan to random position. +uintptr_t MemMap::next_mem_pos_ = GenerateNextMemPos(); #endif static bool CheckMapRequest(byte* expected_ptr, void* actual_ptr, size_t byte_count, diff --git a/runtime/mem_map.h b/runtime/mem_map.h index 4255d17..1411856 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -28,6 +28,12 @@ namespace art { // Used to keep track of mmap segments. +// +// On 64b systems not supporting MAP_32BIT, the implementation of MemMap will do a linear scan +// for free pages. For security, the start of this scan should be randomized. This requires a +// dynamic initializer. +// For this to work, it is paramount that there are no other static initializers that access MemMap. +// Otherwise, calls might see uninitialized values. class MemMap { public: // Request an anonymous region of length 'byte_count' and a requested base address. diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc index c07a9a3..c108a5f 100644 --- a/runtime/mem_map_test.cc +++ b/runtime/mem_map_test.cc @@ -84,8 +84,41 @@ class MemMapTest : public testing::Test { } delete m1; } + +#if defined(__LP64__) && !defined(__x86_64__) + static uintptr_t GetLinearScanPos() { + return MemMap::next_mem_pos_; + } +#endif }; +#if defined(__LP64__) && !defined(__x86_64__) + +#ifdef __BIONIC__ +extern uintptr_t CreateStartPos(uint64_t input); +#endif + +TEST_F(MemMapTest, Start) { + uintptr_t start = GetLinearScanPos(); + EXPECT_LE(64 * KB, start); + EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS)); + +#ifdef __BIONIC__ + // Test a couple of values. Make sure they are different. + uintptr_t last = 0; + for (size_t i = 0; i < 100; ++i) { + uintptr_t random_start = CreateStartPos(i * kPageSize); + EXPECT_NE(last, random_start); + last = random_start; + } + + // Even on max, should be below ART_BASE_ADDRESS. + EXPECT_LT(CreateStartPos(~0), static_cast<uintptr_t>(ART_BASE_ADDRESS)); +#endif + // End of test. +} +#endif + TEST_F(MemMapTest, MapAnonymousEmpty) { std::string error_msg; std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", |