Validate ELF file segment lengths against file length when loading

Bug: 11152153
Change-Id: I31047b9bb607aac478b79dea4ed9a72abe1bd775
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 2140334..dfb6819 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -71,8 +71,9 @@
   }
   if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) {
     if (writable) {
-      LOG(WARNING) << "File size " << file_length
-                   << " not large enough to contain ELF header: " << file_->GetPath();
+      LOG(WARNING) << "File size of " << file_length
+                   << " bytes not large enough to contain ELF header of "
+                   << sizeof(llvm::ELF::Elf32_Ehdr) << " bytes: " << file_->GetPath();
     }
     return false;
   }
@@ -85,6 +86,12 @@
     }
     // then remap to cover program header
     size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);
+    if (file_length < program_header_size) {
+      LOG(WARNING) << "File size of " << file_length
+                   << " bytes not large enough to contain ELF program header of "
+                   << program_header_size << " bytes: " << file_->GetPath();
+      return false;
+    }
     if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) {
       LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath();
       return false;
@@ -617,6 +624,7 @@
     // non-zero, the segments require the specific address specified,
     // which either was specified in the file because we already set
     // base_address_ after the first zero segment).
+    int64_t file_length = file_->GetLength();
     if (program_header.p_vaddr == 0) {
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
@@ -648,6 +656,13 @@
     } else {
       flags |= MAP_PRIVATE;
     }
+    if (file_length < (program_header.p_offset + program_header.p_memsz)) {
+      LOG(WARNING) << "File size of " << file_length
+                   << " bytes not large enough to contain ELF segment " << i
+                   << " of " << (program_header.p_offset + program_header.p_memsz)
+                   << " bytes: " << file_->GetPath();
+      return false;
+    }
     UniquePtr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr,
                                                        program_header.p_memsz,
                                                        prot, flags, file_->Fd(),