From 0c9d30f3c83bb451412ad5fdda73529d661cb0fc Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 13 Jul 2016 17:06:36 -0700 Subject: linker: Improve elf-file validation 1. Make sure that the .dynamic section offset and size matches PT_DYNAMIC segment offset and filesz 2. No section offset can be 0 Bug: http://b/16548758 Bug: http://b/29637134 Change-Id: I11bc2567b0cff89f48699ec74015991fee5b137b Test: Install and start the app from http://b/29637134 --- linker/linker_phdr.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 136e43236..4eff46d49 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -252,7 +252,12 @@ bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) { off64_t range_start; off64_t range_end; - return safe_add(&range_start, file_offset_, offset) && + // Only header can be located at the 0 offset... This function called to + // check DYNSYM and DYNAMIC sections and phdr/shdr - none of them can be + // and 0 offset. + + return offset > 0 && + safe_add(&range_start, file_offset_, offset) && safe_add(&range_end, range_start, size) && range_start < file_size_ && range_end <= file_size_; @@ -324,6 +329,35 @@ bool ElfReader::ReadDynamicSection() { return false; } + // Make sure dynamic_shdr offset and size matches PT_DYNAMIC phdr + size_t pt_dynamic_offset = 0; + size_t pt_dynamic_filesz = 0; + for (size_t i = 0; i < phdr_num_; ++i) { + const ElfW(Phdr)* phdr = &phdr_table_[i]; + if (phdr->p_type == PT_DYNAMIC) { + pt_dynamic_offset = phdr->p_offset; + pt_dynamic_filesz = phdr->p_filesz; + } + } + + if (pt_dynamic_offset != dynamic_shdr->sh_offset) { + DL_ERR("\"%s\" .dynamic section has invalid offset: 0x%zx, " + "expected to match PT_DYNAMIC offset: 0x%zx", + name_.c_str(), + static_cast(dynamic_shdr->sh_offset), + pt_dynamic_offset); + return false; + } + + if (pt_dynamic_filesz != dynamic_shdr->sh_size) { + DL_ERR("\"%s\" .dynamic section has invalid size: 0x%zx, " + "expected to match PT_DYNAMIC filesz: 0x%zx", + name_.c_str(), + static_cast(dynamic_shdr->sh_size), + pt_dynamic_filesz); + return false; + } + if (dynamic_shdr->sh_link >= shdr_num_) { DL_ERR("\"%s\" .dynamic section has invalid sh_link: %d", name_.c_str(), dynamic_shdr->sh_link); return false; -- cgit v1.2.3