Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / android_crazy_linker / src / src / crazy_linker_elf_loader.cpp
index 03589fc..c8594c4 100644 (file)
@@ -21,7 +21,7 @@ namespace crazy {
    MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
    MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
 
-ElfLoader::ElfLoader()
+ElfLoader::ElfLoader(bool no_map_exec_support_fallback_enabled)
     : fd_(),
       path_(NULL),
       phdr_num_(0),
@@ -33,7 +33,9 @@ ElfLoader::ElfLoader()
       load_start_(NULL),
       load_size_(0),
       load_bias_(0),
-      loaded_phdr_(NULL) {}
+      loaded_phdr_(NULL),
+      no_map_exec_support_fallback_enabled_(
+          no_map_exec_support_fallback_enabled) {}
 
 ElfLoader::~ElfLoader() {
   if (phdr_mmap_) {
@@ -306,20 +308,68 @@ 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 (!no_map_exec_support_fallback_enabled_ || 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;
       }
     }