Index: third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp |
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp |
index 03589fc944bf654b4db0c5c4768b4c5170b557a8..de1ed419f30e8696fa4a405572944f1b0e7d9f50 100644 |
--- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp |
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp |
@@ -306,20 +306,67 @@ bool ElfLoader::LoadSegments(Error* error) { |
seg_page_start + PAGE_END(file_length)); |
if (file_length != 0) { |
+ const int prot_flags = PFLAGS_TO_PROT(phdr->p_flags); |
void* seg_addr = fd_.Map((void*)seg_page_start, |
file_length, |
- PFLAGS_TO_PROT(phdr->p_flags), |
+ prot_flags, |
MAP_FIXED | MAP_PRIVATE, |
file_page_start + file_offset_); |
if (seg_addr == MAP_FAILED) { |
- if (errno == EACCES) { |
- error->Format("Could not map segment %d: %s. " |
- "If you are running L-preview, please upgrade to L.", |
- i, strerror(errno)); |
- } else { |
+ if (errno != EACCES || !(prot_flags & PROT_EXEC)) { |
+ // We don't have a fallback in this case. |
error->Format("Could not map segment %d: %s", i, strerror(errno)); |
+ return false; |
+ } |
+ |
+ // We were unable to map executable code from the file directly. |
+ // This can happen because of overly strict SELinux settings prevent |
+ // mapping executable code directly. We fallback by copying the |
+ // executable code into memory. |
+ |
+ // Cast away the const (we are making the pages writable). |
+ seg_addr = (void*)seg_page_start; |
+ |
+ // Add PROT_WRITE to the pages. Note that even though the above Map() |
+ // failed these pages have already been mapped MAP_ANONYMOUS by |
+ // ReserveAddressSpace, so at this point we just use mprotect. |
+ if (mprotect(seg_addr, file_length, prot_flags | PROT_WRITE) == -1) { |
+ error->Format("mprotect failed to add PROT_WRITE %d: %s", |
+ i, strerror(errno)); |
+ return false; |
+ } |
+ |
+ // Map the library for READ. |
+ void* lib_addr = fd_.Map(NULL, |
+ file_length, |
+ PROT_READ, |
+ MAP_PRIVATE, |
+ file_page_start + file_offset_); |
+ if (lib_addr == MAP_FAILED) { |
+ error->Format( |
+ "Could not map segment (PROT_READ) %d: %s", |
+ i, strerror(errno)); |
+ return false; |
+ } |
+ |
+ // Copy the library into the desired location in memory. |
+ memcpy(seg_addr, lib_addr, file_length); |
+ |
+ // Unmap the library. |
+ if (munmap(lib_addr, file_length) == -1) { |
+ error->Format("Failed to unmap the library segment %d: %s", |
+ i, strerror(errno)); |
+ return false; |
+ } |
+ |
+ if (!(prot_flags & PROT_WRITE)) { |
+ // Remove write permissions (PROT_WRITE). |
+ if (mprotect(seg_addr, file_length, prot_flags) == -1) { |
+ error->Format("mprotect failed to remove PROT_WRITE %d: %s", |
+ i, strerror(errno)); |
+ return false; |
+ } |
} |
- return false; |
} |
} |