Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_view.cpp |
diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_view.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_view.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..65ec2818533860d0ab2d8f605ef070f99ba96722 |
--- /dev/null |
+++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_elf_view.cpp |
@@ -0,0 +1,121 @@ |
+#include "crazy_linker_elf_view.h" |
+ |
+#include <errno.h> |
+ |
+#include "crazy_linker_debug.h" |
+#include "crazy_linker_error.h" |
+#include "linker_phdr.h" |
+ |
+namespace crazy { |
+ |
+bool ElfView::InitUnmapped(size_t load_address, |
+ const ELF::Phdr* phdr, |
+ size_t phdr_count, |
+ Error* error) { |
+ // Compute load size and bias. |
+ size_t min_vaddr = 0; |
+ load_size_ = phdr_table_get_load_size(phdr, phdr_count, &min_vaddr, NULL); |
+ if (load_size_ == 0) { |
+ *error = "Invalid program header table"; |
+ return false; |
+ } |
+ load_address_ = (load_address ? load_address : min_vaddr); |
+ load_bias_ = load_address - min_vaddr; |
+ |
+ // Extract the dynamic table information. |
+ phdr_table_get_dynamic_section(phdr, |
+ phdr_count, |
+ load_address, |
+ &dynamic_, |
+ &dynamic_count_, |
+ &dynamic_flags_); |
+ if (!dynamic_) { |
+ *error = "No PT_DYNAMIC section!"; |
+ return false; |
+ } |
+ |
+ // Compute the program header table address relative to load_address. |
+ // This is different from |phdr|..|phdr + phdr_count| which can actually |
+ // be at a different location. |
+ const ELF::Phdr* phdr0 = NULL; |
+ |
+ // First, if there is a PT_PHDR, use it directly. |
+ for (size_t n = 0; n < phdr_count; ++n) { |
+ const ELF::Phdr* entry = &phdr[n]; |
+ if (entry->p_type == PT_PHDR) { |
+ phdr0 = entry; |
+ break; |
+ } |
+ } |
+ |
+ // Otherwise, check the first loadable segment. If its file offset |
+ // is 0, it starts with the ELF header, and we can trivially find the |
+ // loaded program header from it. |
+ if (!phdr0) { |
+ for (size_t n = 0; n < phdr_count; ++n) { |
+ const ELF::Phdr* entry = &phdr[n]; |
+ if (entry->p_type == PT_LOAD) { |
+ if (entry->p_offset == 0) { |
+ ELF::Addr elf_addr = load_bias_ + entry->p_vaddr; |
+ const ELF::Ehdr* ehdr = reinterpret_cast<const ELF::Ehdr*>(elf_addr); |
+ ELF::Addr offset = ehdr->e_phoff; |
+ phdr0 = reinterpret_cast<const ELF::Phdr*>(elf_addr + offset); |
+ } |
+ break; |
+ } |
+ } |
+ } |
+ |
+ // Check that the program header table is indeed in a loadable segment, |
+ // this helps catching malformed ELF binaries. |
+ if (phdr0) { |
+ ELF::Addr phdr0_addr = reinterpret_cast<ELF::Addr>(phdr0); |
+ ELF::Addr phdr0_limit = phdr0_addr + sizeof(ELF::Phdr) * phdr_count; |
+ bool found = false; |
+ for (size_t n = 0; n < phdr_count; ++n) { |
+ size_t seg_start = load_bias_ + phdr[n].p_vaddr; |
+ size_t seg_end = seg_start + phdr[n].p_filesz; |
+ |
+ if (seg_start <= phdr0_addr && phdr0_limit <= seg_end) { |
+ found = true; |
+ break; |
+ } |
+ } |
+ |
+ if (!found) |
+ phdr0 = NULL; |
+ } |
+ |
+ if (!phdr0) { |
+ *error = "Malformed ELF binary"; |
+ return false; |
+ } |
+ |
+ phdr_ = phdr0; |
+ phdr_count_ = phdr_count; |
+ |
+ LOG("%s: New ELF view [load_address:%p, load_size:%p, load_bias:%p, phdr:%p, " |
+ "phdr_count:%d, dynamic:%p, dynamic_count:%d, dynamic_flags:%d", |
+ __FUNCTION__, |
+ load_address_, |
+ load_size_, |
+ load_bias_, |
+ phdr_, |
+ phdr_count_, |
+ dynamic_, |
+ dynamic_count_, |
+ dynamic_flags_); |
+ return true; |
+} |
+ |
+bool ElfView::ProtectRelroSection(Error* error) { |
+ LOG("%s: Enabling GNU RELRO protection\n", __FUNCTION__); |
+ |
+ if (phdr_table_protect_gnu_relro(phdr_, phdr_count_, load_bias_) < 0) { |
+ error->Format("Can't enable GNU RELRO protection: %s", strerror(errno)); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+} // namespace crazy |