@@ -221,17 +221,24 @@ const char* ElfReader::get_string(ElfW(Word) index) const {
221221}
222222
223223bool ElfReader::ReadElfHeader () {
224- ssize_t rc = TEMP_FAILURE_RETRY (pread64 (fd_, &header_, sizeof (header_), file_offset_));
225- if (rc < 0 ) {
226- DL_ERR (" can't read file \" %s\" : %s" , name_.c_str (), strerror (errno));
224+ size_t map_size = file_size_ - file_offset_;
225+ if (map_size < sizeof (header_)) {
226+ DL_ERR (" \" %s\" is too small to be an ELF executable: only found %zd bytes" , name_.c_str (),
227+ map_size);
227228 return false ;
228229 }
229230
230- if (rc != sizeof (header_)) {
231- DL_ERR (" \" %s\" is too small to be an ELF executable: only found %zd bytes" , name_.c_str (),
232- static_cast <size_t >(rc));
231+ #if !defined(__LP64__)
232+ // Map at most 1MiB which should cover most cases
233+ map_size = std::min (map_size, static_cast <size_t >(1 * 1024 * 1024 ));
234+ #endif
235+
236+ if (!file_fragment_.Map (fd_, file_offset_, 0 , map_size)) {
237+ DL_ERR (" \" %s\" header mmap failed: %s" , name_.c_str (), strerror (errno));
233238 return false ;
234239 }
240+
241+ header_ = *static_cast <ElfW (Ehdr)*>(file_fragment_.data ());
235242 return true ;
236243}
237244
@@ -340,6 +347,24 @@ bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment)
340347 ((offset % alignment) == 0 );
341348}
342349
350+ void * ElfReader::MapData (MappedFileFragment* fragment, off64_t offs, off64_t size) {
351+ off64_t end;
352+ CHECK (safe_add (&end, offs, size));
353+
354+ // If the data is already mapped just return it
355+ if (static_cast <off64_t >(file_fragment_.size ()) >= end) {
356+ return static_cast <char *>(file_fragment_.data ()) + offs;
357+ }
358+ // Use the passed-in fragment if area is not mapped. We can't remap the original fragment
359+ // because that invalidates all previous pointers if the file is remapped to a different
360+ // virtual address. A local variable can't be used in place of the passed-in fragment because
361+ // the area would be unmapped as soon as the local object goes out of scope.
362+ if (fragment->Map (fd_, file_offset_, offs, size)) {
363+ return fragment->data ();
364+ }
365+ return nullptr ;
366+ }
367+
343368// Loads the program header table from an ELF file into a read-only private
344369// anonymous mmap-ed block.
345370bool ElfReader::ReadProgramHeaders () {
@@ -362,12 +387,13 @@ bool ElfReader::ReadProgramHeaders() {
362387 return false ;
363388 }
364389
365- if (!phdr_fragment_.Map (fd_, file_offset_, header_.e_phoff , size)) {
390+ void * phdr_data = MapData (&phdr_fragment_, header_.e_phoff , size);
391+ if (phdr_data == nullptr ) {
366392 DL_ERR (" \" %s\" phdr mmap failed: %s" , name_.c_str (), strerror (errno));
367393 return false ;
368394 }
369395
370- phdr_table_ = static_cast <ElfW (Phdr)*>(phdr_fragment_. data () );
396+ phdr_table_ = static_cast <ElfW (Phdr)*>(phdr_data );
371397 return true ;
372398}
373399
@@ -388,12 +414,13 @@ bool ElfReader::ReadSectionHeaders() {
388414 return false ;
389415 }
390416
391- if (!shdr_fragment_.Map (fd_, file_offset_, header_.e_shoff , size)) {
417+ void * shdr_data = MapData (&shdr_fragment_, header_.e_shoff , size);
418+ if (shdr_data == nullptr ) {
392419 DL_ERR (" \" %s\" shdr mmap failed: %s" , name_.c_str (), strerror (errno));
393420 return false ;
394421 }
395422
396- shdr_table_ = static_cast <const ElfW (Shdr)*>(shdr_fragment_. data () );
423+ shdr_table_ = static_cast <const ElfW (Shdr)*>(shdr_data );
397424 return true ;
398425}
399426
@@ -481,26 +508,28 @@ bool ElfReader::ReadDynamicSection() {
481508 return false ;
482509 }
483510
484- if (!dynamic_fragment_.Map (fd_, file_offset_, dynamic_shdr->sh_offset , dynamic_shdr->sh_size )) {
511+ void * dynamic_data = MapData (&dynamic_fragment_, dynamic_shdr->sh_offset , dynamic_shdr->sh_size );
512+ if (dynamic_data == nullptr ) {
485513 DL_ERR (" \" %s\" dynamic section mmap failed: %s" , name_.c_str (), strerror (errno));
486514 return false ;
487515 }
488516
489- dynamic_ = static_cast <const ElfW (Dyn)*>(dynamic_fragment_. data () );
517+ dynamic_ = static_cast <const ElfW (Dyn)*>(dynamic_data );
490518
491519 if (!CheckFileRange (strtab_shdr->sh_offset , strtab_shdr->sh_size , alignof (const char ))) {
492520 DL_ERR_AND_LOG (" \" %s\" has invalid offset/size of the .strtab section linked from .dynamic section" ,
493521 name_.c_str ());
494522 return false ;
495523 }
496524
497- if (!strtab_fragment_.Map (fd_, file_offset_, strtab_shdr->sh_offset , strtab_shdr->sh_size )) {
525+ void * strtab_data = MapData (&strtab_fragment_, strtab_shdr->sh_offset , strtab_shdr->sh_size );
526+ if (strtab_data == nullptr ) {
498527 DL_ERR (" \" %s\" strtab section mmap failed: %s" , name_.c_str (), strerror (errno));
499528 return false ;
500529 }
501530
502- strtab_ = static_cast <const char *>(strtab_fragment_. data () );
503- strtab_size_ = strtab_fragment_. size () ;
531+ strtab_ = static_cast <const char *>(strtab_data );
532+ strtab_size_ = strtab_shdr-> sh_size ;
504533 return true ;
505534}
506535
@@ -756,7 +785,8 @@ bool ElfReader::ReadPadSegmentNote() {
756785 // note_fragment is scoped to within the loop so that there is
757786 // at most 1 PT_NOTE mapped at anytime during this search.
758787 MappedFileFragment note_fragment;
759- if (!note_fragment.Map (fd_, file_offset_, phdr->p_offset , phdr->p_memsz )) {
788+ void * note_data = MapData (¬e_fragment, phdr->p_offset , phdr->p_memsz );
789+ if (note_data == nullptr ) {
760790 DL_ERR (" \" %s\" : PT_NOTE mmap(nullptr, %p, PROT_READ, MAP_PRIVATE, %d, %p) failed: %m" ,
761791 name_.c_str (), reinterpret_cast <void *>(phdr->p_memsz ), fd_,
762792 reinterpret_cast <void *>(page_start (file_offset_ + phdr->p_offset )));
@@ -766,7 +796,7 @@ bool ElfReader::ReadPadSegmentNote() {
766796 const ElfW (Nhdr)* note_hdr = nullptr ;
767797 const char * note_desc = nullptr ;
768798 if (!__get_elf_note (NT_ANDROID_TYPE_PAD_SEGMENT, " Android" ,
769- reinterpret_cast <ElfW (Addr)>(note_fragment. data () ),
799+ reinterpret_cast <ElfW (Addr)>(note_data ),
770800 phdr, ¬e_hdr, ¬e_desc)) {
771801 continue ;
772802 }
0 commit comments