Make DexFiles opened from files readonly by default, but writable during dex2oat

Bug: 9618388
Change-Id: I83f2e16ee8446a79a94a84971146d807bb0c9ee0
diff --git a/runtime/common_test.h b/runtime/common_test.h
index e2dda86..dc1f592 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -434,6 +434,8 @@
     filename += ".jar";
     const DexFile* dex_file = DexFile::Open(filename, filename);
     CHECK(dex_file != NULL) << "Failed to open " << filename;
+    CHECK_EQ(PROT_READ, dex_file->GetPermissions());
+    CHECK(dex_file->IsReadOnly());
     opened_dex_files_.push_back(dex_file);
     return dex_file;
   }
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 45b3427..4fd9a60 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -111,21 +111,21 @@
   return GetPermissions() == PROT_READ;
 }
 
-bool DexFile::EnableWrite(uint8_t* addr, size_t length) const {
+bool DexFile::EnableWrite() const {
   CHECK(IsReadOnly());
   if (mem_map_.get() == NULL) {
     return false;
   } else {
-    return mem_map_->ProtectRegion(addr, length, PROT_READ | PROT_WRITE);
+    return mem_map_->Protect(PROT_READ | PROT_WRITE);
   }
 }
 
-bool DexFile::DisableWrite(uint8_t* addr, size_t length) const {
+bool DexFile::DisableWrite() const {
   CHECK(!IsReadOnly());
   if (mem_map_.get() == NULL) {
     return false;
   } else {
-    return mem_map_->ProtectRegion(addr, length, PROT_READ);
+    return mem_map_->Protect(PROT_READ);
   }
 }
 
@@ -208,24 +208,26 @@
     LOG(ERROR) << "Failed to find classes.dex within '" << location << "'";
     return NULL;
   }
-
   UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex));
   if (map.get() == NULL) {
     LOG(ERROR) << "Failed to extract '" << kClassesDex << "' from '" << location << "'";
     return NULL;
   }
-  const DexFile* dex_file = OpenMemory(location, zip_entry->GetCrc32(), map.release());
-  if (dex_file == NULL) {
+  UniquePtr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release()));
+  if (dex_file.get() == NULL) {
     LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
     return NULL;
   }
-
-  if (!DexFileVerifier::Verify(dex_file, dex_file->Begin(), dex_file->Size())) {
+  if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size())) {
     LOG(ERROR) << "Failed to verify dex file '" << location << "'";
     return NULL;
   }
-
-  return dex_file;
+  if (!dex_file->DisableWrite()) {
+    LOG(ERROR) << "Failed to make dex file read only '" << location << "'";
+    return NULL;
+  }
+  CHECK(dex_file->IsReadOnly()) << location;
+  return dex_file.release();
 }
 
 const DexFile* DexFile::OpenMemory(const byte* base,
@@ -839,7 +841,9 @@
                               DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
                               void* context) const {
   const byte* stream = GetDebugInfoStream(code_item);
-  UniquePtr<LocalInfo[]> local_in_reg(local_cb != NULL ? new LocalInfo[code_item->registers_size_] : NULL);
+  UniquePtr<LocalInfo[]> local_in_reg(local_cb != NULL ?
+                                      new LocalInfo[code_item->registers_size_] :
+                                      NULL);
   if (stream != NULL) {
     DecodeDebugInfo0(code_item, is_static, method_idx, position_cb, local_cb, context, stream, &local_in_reg[0]);
   }
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 006b692..26635ae 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -805,9 +805,9 @@
 
   bool IsReadOnly() const;
 
-  bool EnableWrite(uint8_t* addr, size_t size) const;
+  bool EnableWrite() const;
 
-  bool DisableWrite(uint8_t* addr, size_t size) const;
+  bool DisableWrite() const;
 
  private:
   // Opens a .dex file
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 6449493..32a8354 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -75,6 +75,8 @@
   ScopedObjectAccess soa(Thread::Current());
   const DexFile* dex_file = DexFile::Open(location, location);
   CHECK(dex_file != NULL);
+  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
+  EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
 }
 
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 9a34610..6451d5c 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -192,27 +192,4 @@
   return false;
 }
 
-bool MemMap::ProtectRegion(uint8_t* addr, size_t length, int prot) {
-  CHECK_GE(addr, base_begin_);
-  CHECK_LT(addr + length, reinterpret_cast<const uint8_t*>(base_begin_) + base_size_);
-
-  /*
-   * Align "addr" to a page boundary and adjust "length" appropriately.
-   * (The address must be page-aligned, the length doesn't need to be,
-   * but we do need to ensure we cover the same range.)
-   */
-  uint8_t* alignAddr = reinterpret_cast<uint8_t*>(RoundDown(reinterpret_cast<uintptr_t>(addr),
-                                                            kPageSize));
-  size_t alignLength = length + (addr - alignAddr);
-
-  if (mprotect(alignAddr, alignLength, prot) == 0) {
-    prot_ = prot;
-    return true;
-  }
-
-  PLOG(ERROR) << "mprotect(" << reinterpret_cast<void*>(alignAddr) << ", " << alignLength << ", "
-              << prot << ") failed";
-  return false;
-}
-
 }  // namespace art
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 7d418a5..e294824 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -61,8 +61,6 @@
 
   bool Protect(int prot);
 
-  bool ProtectRegion(uint8_t* addr, size_t length, int prot);
-
   int GetProtect() const {
     return prot_;
   }