[OE-core] [PATCH][morty] lib/oe/qa: handle binaries with segments outside the first 4kb

akuster808 akuster808 at gmail.com
Sat Nov 26 15:39:25 UTC 2016



On 11/25/2016 09:35 AM, Ross Burton wrote:
> The ELF parser was assuming that the segment tables are in the first 4kb of the
> binary.  Whilst this generally appears to be the case, there have been instances
> where the segment table is elsewhere (offset 2MB, in this sample I have).  Solve
> this problem by mmap()ing the file instead.
> 
> Also clean up the code a little whilst chasing the problem.

merged to staging.
Armin
> 
> Signed-off-by: Ross Burton <ross.burton at intel.com>
> ---
>  meta/lib/oe/qa.py | 82 +++++++++++++++++++++++++++----------------------------
>  1 file changed, 41 insertions(+), 41 deletions(-)
> 
> diff --git a/meta/lib/oe/qa.py b/meta/lib/oe/qa.py
> index fbe719d..22d76dc 100644
> --- a/meta/lib/oe/qa.py
> +++ b/meta/lib/oe/qa.py
> @@ -1,4 +1,4 @@
> -import os, struct
> +import os, struct, mmap
>  
>  class NotELFFileError(Exception):
>      pass
> @@ -23,9 +23,9 @@ class ELFFile:
>      EV_CURRENT   = 1
>  
>      # possible values for EI_DATA
> -    ELFDATANONE  = 0
> -    ELFDATA2LSB  = 1
> -    ELFDATA2MSB  = 2
> +    EI_DATA_NONE  = 0
> +    EI_DATA_LSB  = 1
> +    EI_DATA_MSB  = 2
>  
>      PT_INTERP = 3
>  
> @@ -34,51 +34,46 @@ class ELFFile:
>              #print "'%x','%x' %s" % (ord(expectation), ord(result), self.name)
>              raise NotELFFileError("%s is not an ELF" % self.name)
>  
> -    def __init__(self, name, bits = 0):
> +    def __init__(self, name):
>          self.name = name
> -        self.bits = bits
>          self.objdump_output = {}
>  
> -    def open(self):
> -        if not os.path.isfile(self.name):
> -            raise NotELFFileError("%s is not a normal file" % self.name)
> +    # Context Manager functions to close the mmap explicitly
> +    def __enter__(self):
> +        return self
> +
> +    def __exit__(self, exc_type, exc_value, traceback):
> +        self.data.close()
>  
> +    def open(self):
>          with open(self.name, "rb") as f:
> -            # Read 4k which should cover most of the headers we're after
> -            self.data = f.read(4096)
> +            try:
> +                self.data = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
> +            except ValueError:
> +                # This means the file is empty
> +                raise NotELFFileError("%s is empty" % self.name)
>  
> +        # Check the file has the minimum number of ELF table entries
>          if len(self.data) < ELFFile.EI_NIDENT + 4:
>              raise NotELFFileError("%s is not an ELF" % self.name)
>  
> +        # ELF header
>          self.my_assert(self.data[0], 0x7f)
>          self.my_assert(self.data[1], ord('E'))
>          self.my_assert(self.data[2], ord('L'))
>          self.my_assert(self.data[3], ord('F'))
> -        if self.bits == 0:
> -            if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32:
> -                self.bits = 32
> -            elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64:
> -                self.bits = 64
> -            else:
> -                # Not 32-bit or 64.. lets assert
> -                raise NotELFFileError("ELF but not 32 or 64 bit.")
> -        elif self.bits == 32:
> -            self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS32)
> -        elif self.bits == 64:
> -            self.my_assert(self.data[ELFFile.EI_CLASS], ELFFile.ELFCLASS64)
> +        if self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS32:
> +            self.bits = 32
> +        elif self.data[ELFFile.EI_CLASS] == ELFFile.ELFCLASS64:
> +            self.bits = 64
>          else:
> -            raise NotELFFileError("Must specify unknown, 32 or 64 bit size.")
> +            # Not 32-bit or 64.. lets assert
> +            raise NotELFFileError("ELF but not 32 or 64 bit.")
>          self.my_assert(self.data[ELFFile.EI_VERSION], ELFFile.EV_CURRENT)
>  
> -        self.sex = self.data[ELFFile.EI_DATA]
> -        if self.sex == ELFFile.ELFDATANONE:
> -            raise NotELFFileError("self.sex == ELFDATANONE")
> -        elif self.sex == ELFFile.ELFDATA2LSB:
> -            self.sex = "<"
> -        elif self.sex == ELFFile.ELFDATA2MSB:
> -            self.sex = ">"
> -        else:
> -            raise NotELFFileError("Unknown self.sex")
> +        self.endian = self.data[ELFFile.EI_DATA]
> +        if self.endian not in (ELFFile.EI_DATA_LSB, ELFFile.EI_DATA_MSB):
> +            raise NotELFFileError("Unexpected EI_DATA %x" % self.endian)
>  
>      def osAbi(self):
>          return self.data[ELFFile.EI_OSABI]
> @@ -90,16 +85,20 @@ class ELFFile:
>          return self.bits
>  
>      def isLittleEndian(self):
> -        return self.sex == "<"
> +        return self.endian == ELFFile.EI_DATA_LSB
>  
>      def isBigEndian(self):
> -        return self.sex == ">"
> +        return self.endian == ELFFile.EI_DATA_MSB
> +
> +    def getStructEndian(self):
> +        return {ELFFile.EI_DATA_LSB: "<",
> +                ELFFile.EI_DATA_MSB: ">"}[self.endian]
>  
>      def getShort(self, offset):
> -        return struct.unpack_from(self.sex+"H", self.data, offset)[0]
> +        return struct.unpack_from(self.getStructEndian() + "H", self.data, offset)[0]
>  
>      def getWord(self, offset):
> -        return struct.unpack_from(self.sex+"i", self.data, offset)[0]
> +        return struct.unpack_from(self.getStructEndian() + "i", self.data, offset)[0]
>  
>      def isDynamic(self):
>          """
> @@ -118,7 +117,7 @@ class ELFFile:
>  
>      def machine(self):
>          """
> -        We know the sex stored in self.sex and we
> +        We know the endian stored in self.endian and we
>          know the position
>          """
>          return self.getShort(ELFFile.E_MACHINE)
> @@ -166,6 +165,7 @@ def elf_machine_to_string(machine):
>  
>  if __name__ == "__main__":
>      import sys
> -    elf = ELFFile(sys.argv[1])
> -    elf.open()
> -    print(elf.isDynamic())
> +
> +    with ELFFile(sys.argv[1]) as elf:
> +        elf.open()
> +        print(elf.isDynamic())
> 



More information about the Openembedded-core mailing list