crazy_linker_elf_relro.cpp revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// found in the LICENSE file.
493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_relro.h"
693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <errno.h>
893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <limits.h>
993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <stdlib.h>
1093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
1193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_relocations.h"
1293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_view.h"
1393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_memory_mapping.h"
1493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_util.h"
1593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
1693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)namespace crazy {
1793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
1893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)namespace {
1993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)inline bool PageEquals(const char* p1, const char* p2) {
2193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return ::memcmp(p1, p2, PAGE_SIZE) == 0;
2293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
2393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Swap pages between |addr| and |addr + size| with the bytes
2593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// from the ashmem region identified by |fd|, starting from
2693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// a given |offset|. On failure return false and set |error| message.
2793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SwapPagesFromFd(void* addr,
2893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                     size_t size,
2993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                     int fd,
3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                     size_t offset,
3193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                     Error* error) {
3293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Unmap current pages.
3393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (::munmap(addr, size) < 0) {
3493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("%s: Could not unmap %p-%p: %s",
3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  __FUNCTION__,
3693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  addr,
3793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  (char*)addr + size,
3893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
3993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
4093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
4193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
4293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Remap the fd pages at the same location now.
4393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  void* new_map = ::mmap(addr,
4493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                         size,
4593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                         PROT_READ,
4693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                         MAP_FIXED | MAP_SHARED,
4793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                         fd,
4893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                         static_cast<off_t>(offset));
4993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (new_map == MAP_FAILED) {
5093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    char* p = reinterpret_cast<char*>(addr);
5193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("%s: Could not map %p-%p: %s",
5293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  __FUNCTION__,
5393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  p,
5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  p + size,
5593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
5693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
5993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// TODO(digit): Is this necessary?
6093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#ifdef __arm__
6193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  __clear_cache(addr, (char*)addr + size);
6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#endif
6393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Done.
6593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return true;
6693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
6793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}  // namespace
6993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
7093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::Allocate(size_t relro_size,
7193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           const char* library_name,
7293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           Error* error) {
7393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Allocate a new ashmem region.
7493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  String name("RELRO:");
7593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  name += library_name;
7693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!ashmem_.Allocate(relro_size, name.c_str())) {
7793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Could not allocate RELRO ashmem region for %s: %s",
7893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  library_name,
7993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
8093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
8193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
8293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
8393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  start_ = 0;
8493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_ = relro_size;
8593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return true;
8693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
8793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
8893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::CopyFrom(size_t relro_start,
8993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           size_t relro_size,
9093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           Error* error) {
9193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Map it in the process.
9293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  ScopedMemoryMapping map;
9393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!map.Allocate(NULL, relro_size, MemoryMapping::CAN_WRITE, ashmem_.fd())) {
9493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Could not allocate RELRO mapping: %s", strerror(errno));
9593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
9693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
9793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
9893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Copy process' RELRO into it.
9993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  ::memcpy(map.Get(), reinterpret_cast<void*>(relro_start), relro_size);
10093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
10193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Unmap it.
10293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  map.Deallocate();
10393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
10493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Everything's good.
10593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  start_ = relro_start;
10693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_ = relro_size;
10793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return true;
10893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
10993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
11093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::CopyFromRelocated(const ElfView* view,
11193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                    size_t load_address,
11293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                    size_t relro_start,
11393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                    size_t relro_size,
11493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                                    Error* error) {
11593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Offset of RELRO section in current library.
11693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_t relro_offset = relro_start - view->load_address();
11793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
11893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  ElfRelocations relocations;
11993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!relocations.Init(view, error))
12093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
12193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
12293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Map the region in memory (any address).
12393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  ScopedMemoryMapping map;
12493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!map.Allocate(
12593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)           NULL, relro_size, MemoryMapping::CAN_READ_WRITE, ashmem_.fd())) {
12693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Could not allocate RELRO mapping for: %s", strerror(errno));
12793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
12893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
12993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
13093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Copy and relocate.
13193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  relocations.CopyAndRelocate(relro_start,
13293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                              reinterpret_cast<size_t>(map.Get()),
13393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                              load_address + relro_offset,
13493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                              relro_size);
13593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Unmap it.
13693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  map.Deallocate();
13793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  start_ = load_address + relro_offset;
13893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_ = relro_size;
13993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return true;
14093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
14193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
14293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::ForceReadOnly(Error* error) {
14393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Ensure the ashmem region content isn't writable anymore.
14493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!ashmem_.SetProtectionFlags(PROT_READ)) {
14593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Could not make RELRO ashmem region read-only: %s",
14693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
14793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
14893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
14993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  return true;
15093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
15193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
15293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::InitFrom(size_t relro_start,
15393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           size_t relro_size,
15493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           int ashmem_fd,
15593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                           Error* error) {
15693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Create temporary mapping of the ashmem region.
15793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  ScopedMemoryMapping fd_map;
15893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
15993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  LOG("%s: Entering addr=%p size=%p fd=%d\n",
16093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      __FUNCTION__,
16193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      (void*)relro_start,
16293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      (void*)relro_size,
16393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      ashmem_fd);
16493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
16593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  // Sanity check: Ashmem file descriptor must be read-only.
16693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!AshmemRegion::CheckFileDescriptorIsReadOnly(ashmem_fd)) {
16793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Ashmem file descriptor is not read-only: %s\n",
16893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
16993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
17093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
17193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
17293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  if (!fd_map.Allocate(NULL, relro_size, MemoryMapping::CAN_READ, ashmem_fd)) {
17393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    error->Format("Cannot map RELRO ashmem region as read-only: %s\n",
17493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                  strerror(errno));
17593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    return false;
17693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  }
17793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
17893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  LOG("%s: mapping allocated at %p\n", __FUNCTION__, fd_map.Get());
17993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
18093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  char* cur_page = reinterpret_cast<char*>(relro_start);
18193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  char* fd_page = static_cast<char*>(fd_map.Get());
18293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_t p = 0;
18393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_t size = relro_size;
18493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  size_t similar_size = 0;
18593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
18693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  do {
18793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    // Skip over dissimilar pages.
18893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    while (p < size && !PageEquals(cur_page + p, fd_page + p)) {
18993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      p += PAGE_SIZE;
19093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
19193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
19293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    // Count similar pages.
19393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    size_t p2 = p;
19493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    while (p2 < size && PageEquals(cur_page + p2, fd_page + p2)) {
19593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      p2 += PAGE_SIZE;
19693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
19793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
19893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (p2 > p) {
19993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      // Swap pages between |pos| and |pos2|.
20093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      LOG("%s: Swap pages at %p-%p\n",
20193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)          __FUNCTION__,
20293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)          cur_page + p,
20393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)          cur_page + p2);
20493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)      if (!SwapPagesFromFd(cur_page + p, p2 - p, ashmem_fd, p, error))
20593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        return false;
206
207      similar_size += (p2 - p);
208    }
209
210    p = p2;
211  } while (p < size);
212
213  LOG("%s: Swapped %d pages over %d (%d %%, %d KB not shared)\n",
214      __FUNCTION__,
215      similar_size / PAGE_SIZE,
216      size / PAGE_SIZE,
217      similar_size * 100 / size,
218      (size - similar_size) / 4096);
219
220  if (similar_size == 0)
221    return false;
222
223  start_ = relro_start;
224  size_ = relro_size;
225  return true;
226}
227
228}  // namespace crazy
229