Do not unmap reserved region on dlclose

dlclose used to unmap the part of the reserved region
for ANDROID_DLEXT_RESERVED_ADDRESS that was neccessary
to map PT_LOAD segments. With this change dlclose
replaces mapped PT_LOAD segments with a PROT_NONE,
MAP_ANONYMOUS | MAP_NORESERVE.

Previously caller was unmapping the reserved region after
the failed dlclose which led to race condition when someone
else reused the region freed by dlclose but before the unmap
by the chromium code.

Bug: http://code.google.com/p/chromium/issues/detail?id=568880
Change-Id: I0f5eaa2bf6641f83dde469b631c518482acc59a2
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 70c2ca5..1c1650e 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -356,7 +356,13 @@
   }
 
   if (si->base != 0 && si->size != 0) {
-    munmap(reinterpret_cast<void*>(si->base), si->size);
+    if (!si->is_mapped_by_caller()) {
+      munmap(reinterpret_cast<void*>(si->base), si->size);
+    } else {
+      // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
+      mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
+           MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
+    }
   }
 
   soinfo *prev = nullptr, *trav;
@@ -1160,6 +1166,7 @@
 
     si_->base = elf_reader.load_start();
     si_->size = elf_reader.load_size();
+    si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
     si_->load_bias = elf_reader.load_bias();
     si_->phnum = elf_reader.phdr_count();
     si_->phdr = elf_reader.loaded_phdr();
@@ -3248,6 +3255,19 @@
   return local_group_root_;
 }
 
+
+void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
+  if (mapped_by_caller) {
+    flags_ |= FLAG_MAPPED_BY_CALLER;
+  } else {
+    flags_ &= ~FLAG_MAPPED_BY_CALLER;
+  }
+}
+
+bool soinfo::is_mapped_by_caller() const {
+  return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
+}
+
 // This function returns api-level at the time of
 // dlopen/load. Note that libraries opened by system
 // will always have 'current' api level.