Created
May 12, 2017 03:55
-
-
Save thestinger/fc55e3a0194c1a1b1979983b03b271b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 02f8db1d34c6979c72a8e5c9992398d7a948d36f Mon Sep 17 00:00:00 2001 | |
From: Daniel Micay <danielmicay@gmail.com> | |
Date: Sun, 13 Sep 2015 20:40:56 -0400 | |
Subject: [PATCH] add an isolated region for dynamic libraries | |
--- | |
linker/linker.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++++++- | |
linker/linker.h | 2 + | |
linker/linker_phdr.cpp | 13 +++-- | |
3 files changed, 145 insertions(+), 4 deletions(-) | |
diff --git a/linker/linker.cpp b/linker/linker.cpp | |
index d3ac1d000..beffca093 100644 | |
--- a/linker/linker.cpp | |
+++ b/linker/linker.cpp | |
@@ -45,6 +45,8 @@ | |
#include <vector> | |
// Private C library headers. | |
+#include "private/bionic_macros.h" | |
+#include "private/bionic_prctl.h" | |
#include "private/bionic_tls.h" | |
#include "private/KernelArgumentBlock.h" | |
#include "private/ScopedPthreadMutexLocker.h" | |
@@ -226,6 +228,133 @@ void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) { | |
g_soinfo_links_allocator.free(entry); | |
} | |
+struct region_span { | |
+ struct region_span* prev; | |
+ struct region_span* next; | |
+ char* ptr; | |
+ size_t size; | |
+}; | |
+ | |
+static region_span region_spans; | |
+static LinkerTypeAllocator<region_span> region_span_allocator; | |
+ | |
+static const void* library_region_start; | |
+static const void* library_region_end; | |
+ | |
+static void remove_span(region_span* span) { | |
+ span->prev->next = span->next; | |
+ if (span->next != nullptr) { | |
+ span->next->prev = span->prev; | |
+ } | |
+ region_span_allocator.free(span); | |
+} | |
+ | |
+static void library_region_init() { | |
+#ifdef __LP64__ | |
+ size_t size = 1024 * 1024 * 1024; | |
+#else | |
+ size_t size = 128 * 1024 * 1024; | |
+#endif | |
+ size_t gap_size = BIONIC_ALIGN_DOWN(arc4random_uniform(size), PAGE_SIZE); | |
+ | |
+ char* ptr = static_cast<char*>(mmap(nullptr, gap_size + size, PROT_NONE, | |
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); | |
+ if (ptr == MAP_FAILED) { | |
+ return; | |
+ } | |
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, gap_size, "library region random gap"); | |
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr + gap_size, size, "library region"); | |
+ | |
+ region_span* span = region_span_allocator.alloc(); | |
+ span->prev = ®ion_spans; | |
+ span->next = nullptr; | |
+ span->ptr = ptr + gap_size; | |
+ span->size = size; | |
+ | |
+ region_spans.next = span; | |
+ | |
+ library_region_start = span->ptr; | |
+ library_region_end = span->ptr + size; | |
+} | |
+ | |
+void* get_library_mapping(size_t size) { | |
+ if (size % PAGE_SIZE != 0) { | |
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "not a multiple of the page size"); | |
+ } | |
+ | |
+ region_span* span = nullptr; | |
+ for (region_span* s = region_spans.next; s != nullptr; s = s->next) { | |
+ if (s->size < size) { | |
+ continue; | |
+ } | |
+ if (span == nullptr || s->size < span->size || (s->size == span->size && s->ptr < span->ptr)) { | |
+ span = s; | |
+ } | |
+ } | |
+ | |
+ if (span == nullptr) { | |
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "library isolation region exhausted"); | |
+ void* ptr = mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
+ if (ptr == MAP_FAILED) { | |
+ return nullptr; | |
+ } | |
+ return ptr; | |
+ } | |
+ | |
+ void* ptr = span->ptr; | |
+ if (size == span->size) { | |
+ remove_span(span); | |
+ } else { | |
+ span->ptr += size; | |
+ span->size -= size; | |
+ } | |
+ return ptr; | |
+} | |
+ | |
+static void release_library_mapping(void* ptr, size_t size) { | |
+ if (ptr >= library_region_start && ptr < library_region_end) { | |
+ mmap(ptr, size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "library region"); | |
+ | |
+ region_span* span = nullptr; | |
+ for (region_span* s = region_spans.next; s != nullptr; s = s->next) { | |
+ if (s->ptr + s->size == ptr) { | |
+ ptr = s->ptr; | |
+ size += s->size; | |
+ span = s; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ for (region_span* s = region_spans.next; s != nullptr; s = s->next) { | |
+ if (s->ptr == static_cast<char*>(ptr) + size) { | |
+ size += s->size; | |
+ if (span == nullptr) { | |
+ span = s; | |
+ } else { | |
+ remove_span(s); | |
+ } | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (span == nullptr) { | |
+ span = region_span_allocator.alloc(); | |
+ span->prev = ®ion_spans; | |
+ span->next = region_spans.next; | |
+ if (region_spans.next != nullptr) { | |
+ region_spans.next->prev = span; | |
+ } | |
+ region_spans.next = span; | |
+ } | |
+ | |
+ span->ptr = static_cast<char*>(ptr); | |
+ span->size = size; | |
+ } else { | |
+ munmap(ptr, size); | |
+ } | |
+} | |
+ | |
static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, | |
off64_t file_offset, uint32_t rtld_flags) { | |
if (strlen(name) >= PATH_MAX) { | |
@@ -248,7 +377,7 @@ static void soinfo_free(soinfo* si) { | |
} | |
if (si->base != 0 && si->size != 0) { | |
- munmap(reinterpret_cast<void*>(si->base), si->size); | |
+ release_library_mapping(reinterpret_cast<void*>(si->base), si->size); | |
} | |
soinfo *prev = nullptr, *trav; | |
@@ -809,6 +938,7 @@ class ProtectedDataGuard { | |
void protect_data(int protection) { | |
g_soinfo_allocator.protect_all(protection); | |
g_soinfo_links_allocator.protect_all(protection); | |
+ region_span_allocator.protect_all(protection); | |
} | |
static size_t ref_count_; | |
@@ -3152,6 +3282,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( | |
// Initialize system properties | |
__system_properties_init(); // may use 'environ' | |
+ library_region_init(); | |
+ | |
debuggerd_init(); | |
// Get a few environment variables. | |
diff --git a/linker/linker.h b/linker/linker.h | |
index 023b6721f..27bd3a3f5 100644 | |
--- a/linker/linker.h | |
+++ b/linker/linker.h | |
@@ -438,4 +438,6 @@ size_t linker_get_error_buffer_size(); | |
void set_application_target_sdk_version(uint32_t target); | |
uint32_t get_application_target_sdk_version(); | |
+__LIBC_HIDDEN__ void* get_library_mapping(size_t size); | |
+ | |
#endif | |
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp | |
index 30118e363..bc5b0ab78 100644 | |
--- a/linker/linker_phdr.cpp | |
+++ b/linker/linker_phdr.cpp | |
@@ -338,9 +338,16 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) { | |
reserved_size - load_size_, load_size_, name_); | |
return false; | |
} | |
- int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; | |
- start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0); | |
- if (start == MAP_FAILED) { | |
+ if (mmap_hint) { | |
+ int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; | |
+ start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0); | |
+ if (start == MAP_FAILED) { | |
+ start = nullptr; | |
+ } | |
+ } else { | |
+ start = get_library_mapping(load_size_); | |
+ } | |
+ if (!start) { | |
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_); | |
return false; | |
} | |
-- | |
2.12.2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment