From cb00add1b382d1e3045876d7e1ccbee2fdce976b Mon Sep 17 00:00:00 2001
From: Dmitriy Ivanov <dimitry@google.com>
Date: Tue, 31 Mar 2015 17:28:24 -0700
Subject: [PATCH] Remove text-relocation support for lp32

Bug: 20013628
Change-Id: Idaf8012f00ee1304d429c3b42f9ebc6b648c55b8
---
 linker/linker.cpp      | 38 ++-----------------------
 linker/linker.h        |  4 +--
 linker/linker_phdr.cpp | 64 ------------------------------------------
 linker/linker_phdr.h   |  6 ----
 4 files changed, 4 insertions(+), 108 deletions(-)

diff --git a/linker/linker.cpp b/linker/linker.cpp
index ebf125e1f..49c10a7f7 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2297,13 +2297,8 @@ bool soinfo::prelink_image() {
         break;
 
       case DT_TEXTREL:
-#if defined(__LP64__)
-        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name);
+        DL_ERR("text relocations (DT_TEXTREL) found in the ELF file \"%s\"", name);
         return false;
-#else
-        has_text_relocations = true;
-        break;
-#endif
 
       case DT_SYMBOLIC:
         has_DT_SYMBOLIC = true;
@@ -2315,12 +2310,8 @@ bool soinfo::prelink_image() {
 
       case DT_FLAGS:
         if (d->d_un.d_val & DF_TEXTREL) {
-#if defined(__LP64__)
-          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name);
+          DL_ERR("text relocations (DF_TEXTREL) found in the ELF file \"%s\"", name);
           return false;
-#else
-          has_text_relocations = true;
-#endif
         }
         if (d->d_un.d_val & DF_SYMBOLIC) {
           has_DT_SYMBOLIC = true;
@@ -2429,20 +2420,6 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
     local_group_root_ = this;
   }
 
-#if !defined(__LP64__)
-  if (has_text_relocations) {
-    // Make segments writable to allow text relocations to work properly. We will later call
-    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
-    DL_WARN("%s has text relocations. This is wasting memory and prevents "
-            "security hardening. Please fix.", name);
-    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
-      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
-             name, strerror(errno));
-      return false;
-    }
-  }
-#endif
-
   if (android_relocs_ != nullptr) {
     // check signature
     if (android_relocs_size_ > 3 &&
@@ -2513,17 +2490,6 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
 
   DEBUG("[ finished linking %s ]", name);
 
-#if !defined(__LP64__)
-  if (has_text_relocations) {
-    // All relocations are done, we can protect our segments back to read-only.
-    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
-      DL_ERR("can't protect segments for \"%s\": %s",
-             name, strerror(errno));
-      return false;
-    }
-  }
-#endif
-
   /* We can also turn on GNU RELRO protection */
   if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
     DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
diff --git a/linker/linker.h b/linker/linker.h
index bf3e7bf5d..ed2691730 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -226,8 +226,8 @@ struct soinfo {
   // value to get the corresponding address in the process' address space.
   ElfW(Addr) load_bias;
 
-#if !defined(__LP64__)
-  bool has_text_relocations;
+#if defined(__arm__)
+  bool unused4; // DO NOT USE, maintained for compatibility
 #endif
   bool has_DT_SYMBOLIC;
 
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 2c4ca15cc..66b28aeb3 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -412,70 +412,6 @@ bool ElfReader::LoadSegments() {
   return true;
 }
 
-/* Used internally. Used to set the protection bits of all loaded segments
- * with optional extra flags (i.e. really PROT_WRITE). Used by
- * phdr_table_protect_segments and phdr_table_unprotect_segments.
- */
-static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                     ElfW(Addr) load_bias, int extra_prot_flags) {
-  const ElfW(Phdr)* phdr = phdr_table;
-  const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
-
-  for (; phdr < phdr_limit; phdr++) {
-    if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) {
-      continue;
-    }
-
-    ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
-    ElfW(Addr) seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
-
-    int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
-                       seg_page_end - seg_page_start,
-                       PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
-    if (ret < 0) {
-      return -1;
-    }
-  }
-  return 0;
-}
-
-/* Restore the original protection modes for all loadable segments.
- * You should only call this after phdr_table_unprotect_segments and
- * applying all relocations.
- *
- * Input:
- *   phdr_table  -> program header table
- *   phdr_count  -> number of entries in tables
- *   load_bias   -> load bias
- * Return:
- *   0 on error, -1 on failure (error code in errno).
- */
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
-                                size_t phdr_count, ElfW(Addr) load_bias) {
-  return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
-}
-
-/* Change the protection of all loaded segments in memory to writable.
- * This is useful before performing relocations. Once completed, you
- * will have to call phdr_table_protect_segments to restore the original
- * protection flags on all segments.
- *
- * Note that some writable segments can also have their content turned
- * to read-only by calling phdr_table_protect_gnu_relro. This is no
- * performed here.
- *
- * Input:
- *   phdr_table  -> program header table
- *   phdr_count  -> number of entries in tables
- *   load_bias   -> load bias
- * Return:
- *   0 on error, -1 on failure (error code in errno).
- */
-int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table,
-                                  size_t phdr_count, ElfW(Addr) load_bias) {
-  return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, PROT_WRITE);
-}
-
 /* Used internally by phdr_table_protect_gnu_relro and
  * phdr_table_unprotect_gnu_relro.
  */
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 50f211775..cc3296b3d 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -84,12 +84,6 @@ class ElfReader {
 size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                                 ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
 
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
-                                size_t phdr_count, ElfW(Addr) load_bias);
-
-int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                  ElfW(Addr) load_bias);
-
 int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                                  ElfW(Addr) load_bias);