Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Unified Diff: third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_relro.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to fix build. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_relro.cpp
diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_relro.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_relro.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c0bf00a8d80359fe6e5595cd18bc88d33074abc
--- /dev/null
+++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_relro.cpp
@@ -0,0 +1,228 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crazy_linker_elf_relro.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "crazy_linker_elf_relocations.h"
+#include "crazy_linker_elf_view.h"
+#include "crazy_linker_memory_mapping.h"
+#include "crazy_linker_util.h"
+
+namespace crazy {
+
+namespace {
+
+inline bool PageEquals(const char* p1, const char* p2) {
+ return ::memcmp(p1, p2, PAGE_SIZE) == 0;
+}
+
+// Swap pages between |addr| and |addr + size| with the bytes
+// from the ashmem region identified by |fd|, starting from
+// a given |offset|. On failure return false and set |error| message.
+bool SwapPagesFromFd(void* addr,
+ size_t size,
+ int fd,
+ size_t offset,
+ Error* error) {
+ // Unmap current pages.
+ if (::munmap(addr, size) < 0) {
+ error->Format("%s: Could not unmap %p-%p: %s",
+ __FUNCTION__,
+ addr,
+ (char*)addr + size,
+ strerror(errno));
+ return false;
+ }
+
+ // Remap the fd pages at the same location now.
+ void* new_map = ::mmap(addr,
+ size,
+ PROT_READ,
+ MAP_FIXED | MAP_SHARED,
+ fd,
+ static_cast<off_t>(offset));
+ if (new_map == MAP_FAILED) {
+ char* p = reinterpret_cast<char*>(addr);
+ error->Format("%s: Could not map %p-%p: %s",
+ __FUNCTION__,
+ p,
+ p + size,
+ strerror(errno));
+ return false;
+ }
+
+// TODO(digit): Is this necessary?
+#ifdef __arm__
+ __clear_cache(addr, (char*)addr + size);
+#endif
+
+ // Done.
+ return true;
+}
+
+} // namespace
+
+bool SharedRelro::Allocate(size_t relro_size,
+ const char* library_name,
+ Error* error) {
+ // Allocate a new ashmem region.
+ String name("RELRO:");
+ name += library_name;
+ if (!ashmem_.Allocate(relro_size, name.c_str())) {
+ error->Format("Could not allocate RELRO ashmem region for %s: %s",
+ library_name,
+ strerror(errno));
+ return false;
+ }
+
+ start_ = 0;
+ size_ = relro_size;
+ return true;
+}
+
+bool SharedRelro::CopyFrom(size_t relro_start,
+ size_t relro_size,
+ Error* error) {
+ // Map it in the process.
+ ScopedMemoryMapping map;
+ if (!map.Allocate(NULL, relro_size, MemoryMapping::CAN_WRITE, ashmem_.fd())) {
+ error->Format("Could not allocate RELRO mapping: %s", strerror(errno));
+ return false;
+ }
+
+ // Copy process' RELRO into it.
+ ::memcpy(map.Get(), reinterpret_cast<void*>(relro_start), relro_size);
+
+ // Unmap it.
+ map.Deallocate();
+
+ // Everything's good.
+ start_ = relro_start;
+ size_ = relro_size;
+ return true;
+}
+
+bool SharedRelro::CopyFromRelocated(const ElfView* view,
+ size_t load_address,
+ size_t relro_start,
+ size_t relro_size,
+ Error* error) {
+ // Offset of RELRO section in current library.
+ size_t relro_offset = relro_start - view->load_address();
+
+ ElfRelocations relocations;
+ if (!relocations.Init(view, error))
+ return false;
+
+ // Map the region in memory (any address).
+ ScopedMemoryMapping map;
+ if (!map.Allocate(
+ NULL, relro_size, MemoryMapping::CAN_READ_WRITE, ashmem_.fd())) {
+ error->Format("Could not allocate RELRO mapping for: %s", strerror(errno));
+ return false;
+ }
+
+ // Copy and relocate.
+ relocations.CopyAndRelocate(relro_start,
+ reinterpret_cast<size_t>(map.Get()),
+ load_address + relro_offset,
+ relro_size);
+ // Unmap it.
+ map.Deallocate();
+ start_ = load_address + relro_offset;
+ size_ = relro_size;
+ return true;
+}
+
+bool SharedRelro::ForceReadOnly(Error* error) {
+ // Ensure the ashmem region content isn't writable anymore.
+ if (!ashmem_.SetProtectionFlags(PROT_READ)) {
+ error->Format("Could not make RELRO ashmem region read-only: %s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+bool SharedRelro::InitFrom(size_t relro_start,
+ size_t relro_size,
+ int ashmem_fd,
+ Error* error) {
+ // Create temporary mapping of the ashmem region.
+ ScopedMemoryMapping fd_map;
+
+ LOG("%s: Entering addr=%p size=%p fd=%d\n",
+ __FUNCTION__,
+ (void*)relro_start,
+ (void*)relro_size,
+ ashmem_fd);
+
+ // Sanity check: Ashmem file descriptor must be read-only.
+ if (!AshmemRegion::CheckFileDescriptorIsReadOnly(ashmem_fd)) {
+ error->Format("Ashmem file descriptor is not read-only: %s\n",
+ strerror(errno));
+ return false;
+ }
+
+ if (!fd_map.Allocate(NULL, relro_size, MemoryMapping::CAN_READ, ashmem_fd)) {
+ error->Format("Cannot map RELRO ashmem region as read-only: %s\n",
+ strerror(errno));
+ return false;
+ }
+
+ LOG("%s: mapping allocated at %p\n", __FUNCTION__, fd_map.Get());
+
+ char* cur_page = reinterpret_cast<char*>(relro_start);
+ char* fd_page = static_cast<char*>(fd_map.Get());
+ size_t p = 0;
+ size_t size = relro_size;
+ size_t similar_size = 0;
+
+ do {
+ // Skip over dissimilar pages.
+ while (p < size && !PageEquals(cur_page + p, fd_page + p)) {
+ p += PAGE_SIZE;
+ }
+
+ // Count similar pages.
+ size_t p2 = p;
+ while (p2 < size && PageEquals(cur_page + p2, fd_page + p2)) {
+ p2 += PAGE_SIZE;
+ }
+
+ if (p2 > p) {
+ // Swap pages between |pos| and |pos2|.
+ LOG("%s: Swap pages at %p-%p\n",
+ __FUNCTION__,
+ cur_page + p,
+ cur_page + p2);
+ if (!SwapPagesFromFd(cur_page + p, p2 - p, ashmem_fd, p, error))
+ return false;
+
+ similar_size += (p2 - p);
+ }
+
+ p = p2;
+ } while (p < size);
+
+ LOG("%s: Swapped %d pages over %d (%d %%, %d KB not shared)\n",
+ __FUNCTION__,
+ similar_size / PAGE_SIZE,
+ size / PAGE_SIZE,
+ similar_size * 100 / size,
+ (size - similar_size) / 4096);
+
+ if (similar_size == 0)
+ return false;
+
+ start_ = relro_start;
+ size_ = relro_size;
+ return true;
+}
+
+} // namespace crazy

Powered by Google App Engine
This is Rietveld 408576698