Home | History | Annotate | Download | only in src
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crazy_linker_elf_view.h"
      6 
      7 #include <errno.h>
      8 
      9 #include "crazy_linker_debug.h"
     10 #include "crazy_linker_error.h"
     11 #include "linker_phdr.h"
     12 
     13 namespace crazy {
     14 
     15 bool ElfView::InitUnmapped(ELF::Addr load_address,
     16                            const ELF::Phdr* phdr,
     17                            size_t phdr_count,
     18                            Error* error) {
     19   // Compute load size and bias.
     20   ELF::Addr min_vaddr = 0;
     21   load_size_ = phdr_table_get_load_size(phdr, phdr_count, &min_vaddr, NULL);
     22   if (load_size_ == 0) {
     23     *error = "Invalid program header table";
     24     return false;
     25   }
     26   load_address_ = (load_address ? load_address : min_vaddr);
     27   load_bias_ = load_address - min_vaddr;
     28 
     29   // Extract the dynamic table information.
     30   phdr_table_get_dynamic_section(phdr,
     31                                  phdr_count,
     32                                  load_bias_,
     33                                  &dynamic_,
     34                                  &dynamic_count_,
     35                                  &dynamic_flags_);
     36   if (!dynamic_) {
     37     *error = "No PT_DYNAMIC section!";
     38     return false;
     39   }
     40 
     41   // Compute the program header table address relative to load_address.
     42   // This is different from |phdr|..|phdr + phdr_count| which can actually
     43   // be at a different location.
     44   const ELF::Phdr* phdr0 = NULL;
     45 
     46   // First, if there is a PT_PHDR, use it directly.
     47   for (size_t n = 0; n < phdr_count; ++n) {
     48     const ELF::Phdr* entry = &phdr[n];
     49     if (entry->p_type == PT_PHDR) {
     50       phdr0 = entry;
     51       break;
     52     }
     53   }
     54 
     55   // Otherwise, check the first loadable segment. If its file offset
     56   // is 0, it starts with the ELF header, and we can trivially find the
     57   // loaded program header from it.
     58   if (!phdr0) {
     59     for (size_t n = 0; n < phdr_count; ++n) {
     60       const ELF::Phdr* entry = &phdr[n];
     61       if (entry->p_type == PT_LOAD) {
     62         if (entry->p_offset == 0) {
     63           ELF::Addr elf_addr = load_bias_ + entry->p_vaddr;
     64           const ELF::Ehdr* ehdr = reinterpret_cast<const ELF::Ehdr*>(elf_addr);
     65           ELF::Addr offset = ehdr->e_phoff;
     66           phdr0 = reinterpret_cast<const ELF::Phdr*>(elf_addr + offset);
     67         }
     68         break;
     69       }
     70     }
     71   }
     72 
     73   // Check that the program header table is indeed in a loadable segment,
     74   // this helps catching malformed ELF binaries.
     75   if (phdr0) {
     76     ELF::Addr phdr0_addr = reinterpret_cast<ELF::Addr>(phdr0);
     77     ELF::Addr phdr0_limit = phdr0_addr + sizeof(ELF::Phdr) * phdr_count;
     78     bool found = false;
     79     for (size_t n = 0; n < phdr_count; ++n) {
     80       size_t seg_start = load_bias_ + phdr[n].p_vaddr;
     81       size_t seg_end = seg_start + phdr[n].p_filesz;
     82 
     83       if (seg_start <= phdr0_addr && phdr0_limit <= seg_end) {
     84         found = true;
     85         break;
     86       }
     87     }
     88 
     89     if (!found)
     90       phdr0 = NULL;
     91   }
     92 
     93   if (!phdr0) {
     94     *error = "Malformed ELF binary";
     95     return false;
     96   }
     97 
     98   phdr_ = phdr0;
     99   phdr_count_ = phdr_count;
    100 
    101   LOG("%s: New ELF view [load_address:%p, load_size:%p, load_bias:%p, phdr:%p, "
    102       "phdr_count:%d, dynamic:%p, dynamic_count:%d, dynamic_flags:%d\n",
    103       __FUNCTION__,
    104       load_address_,
    105       load_size_,
    106       load_bias_,
    107       phdr_,
    108       phdr_count_,
    109       dynamic_,
    110       dynamic_count_,
    111       dynamic_flags_);
    112   return true;
    113 }
    114 
    115 bool ElfView::ProtectRelroSection(Error* error) {
    116   LOG("%s: Enabling GNU RELRO protection\n", __FUNCTION__);
    117 
    118   if (phdr_table_protect_gnu_relro(phdr_, phdr_count_, load_bias_) < 0) {
    119     error->Format("Can't enable GNU RELRO protection: %s", strerror(errno));
    120     return false;
    121   }
    122   return true;
    123 }
    124 
    125 }  // namespace crazy
    126