]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
merge of 0bc367fba741939c3256bd69de909e6c23067adf
authorUlrich Drepper <drepper@redhat.com>
Sat, 13 Aug 2005 22:35:15 +0000 (22:35 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 13 Aug 2005 22:35:15 +0000 (22:35 +0000)
     and bc359776b21dfd2c5106da8610683718e2dd2875

libelf/ChangeLog
libelf/elf_begin.c

index 67d4f39510ab37e6255a1e08a74420658c9727ef..acb026ef2d5254f5f58d74709c050d8231c06028 100644 (file)
@@ -1,3 +1,10 @@
+2005-08-13  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf_begin.c (get_shnum): Optimize memory handling.  Always read from
+       mapped file if available.  Fix access to 64-bit sh_size.  Recognize
+       overflow.
+       (file_read_elf): Likewise.
+
 2005-08-12  Roland McGrath  <roland@redhat.com>
 
        * elf32_offscn.c: Do not match empty sections at OFFSET unless
index 404cbe832821b7a1abc1c19edfa78f55801e3c3d..56c7a481521ce6cf84fb155b9ca3417c953d3543 100644 (file)
@@ -69,6 +69,11 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
     Elf64_Ehdr *e64;
     void *p;
   } ehdr;
+  union
+  {
+    Elf32_Ehdr e32;
+    Elf64_Ehdr e64;
+  } ehdr_mem;
   bool is32 = e_ident[EI_CLASS] == ELFCLASS32;
 
   /* Make the ELF header available.  */
@@ -83,11 +88,17 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
       /* We have to read the data from the file.  */
       size_t len = is32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr);
 
-      ehdr.p = alloca (len);
-      /* Fill it.  */
-      if ((size_t) pread (fildes, ehdr.p, len, offset) != len)
-       /* Failed reading.  */
-       return (size_t) -1l;
+      if (likely (map_address != NULL))
+       ehdr.p = memcpy (&ehdr_mem, (char *) map_address + offset, len);
+      else
+       {
+         /* Fill it.  */
+         if ((size_t) TEMP_FAILURE_RETRY (pread (fildes, &ehdr_mem, len,
+                                                 offset)) != len)
+           /* Failed reading.  */
+           return (size_t) -1l;
+         ehdr.p = &ehdr_mem;
+       }
 
       if (e_ident[EI_DATA] != MY_ELFDATA)
        {
@@ -120,18 +131,27 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
                  || (((size_t) ((char *) map_address + offset))
                      & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
            /* We can directly access the memory.  */
-           result = ((Elf32_Shdr *) ((char *) map_address
-                                     + ehdr.e32->e_shoff
+           result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff
                                      + offset))->sh_size;
          else
            {
              Elf32_Word size;
 
-             if (pread (fildes, &size, sizeof (Elf32_Word),
-                        offset + ehdr.e32->e_shoff
-                        + offsetof (Elf32_Shdr, sh_size))
-                 != sizeof (Elf32_Word))
-               return (size_t) -1l;
+             if (likely (map_address != NULL))
+               /* gcc will optimize the memcpy to a simple memory
+                  access while taking care of alignment issues.  */
+               memcpy (&size, &((Elf32_Shdr *) ((char *) map_address
+                                                + ehdr.e32->e_shoff
+                                                + offset))->sh_size,
+                       sizeof (Elf32_Word));
+             else
+               if (TEMP_FAILURE_RETRY (pread (fildes, &size,
+                                              sizeof (Elf32_Word),
+                                              offset + ehdr.e32->e_shoff
+                                              + offsetof (Elf32_Shdr,
+                                                          sh_size)))
+                   != sizeof (Elf32_Word))
+                 return (size_t) -1l;
 
              if (e_ident[EI_DATA] != MY_ELFDATA)
                CONVERT (size);
@@ -151,29 +171,41 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
            /* Cannot read the first section header.  */
            return (size_t) -1l;
 
+         Elf64_Xword size;
          if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
              && (ALLOW_UNALIGNED
                  || (((size_t) ((char *) map_address + offset))
                      & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
            /* We can directly access the memory.  */
-           result = ((Elf64_Shdr *) ((char *) map_address
-                                     + ehdr.e64->e_shoff
-                                     + offset))->sh_size;
+           size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff
+                                   + offset))->sh_size;
          else
            {
-             Elf64_Word size;
-
-             if (pread (fildes, &size, sizeof (Elf64_Word),
-                        offset + ehdr.e64->e_shoff
-                        + offsetof (Elf64_Shdr, sh_size))
-                 != sizeof (Elf64_Word))
-               return (size_t) -1l;
+             if (likely (map_address != NULL))
+               /* gcc will optimize the memcpy to a simple memory
+                  access while taking care of alignment issues.  */
+               memcpy (&size, &((Elf64_Shdr *) ((char *) map_address
+                                                + ehdr.e64->e_shoff
+                                                + offset))->sh_size,
+                       sizeof (Elf64_Xword));
+             else
+               if (TEMP_FAILURE_RETRY (pread (fildes, &size,
+                                              sizeof (Elf64_Word),
+                                              offset + ehdr.e64->e_shoff
+                                              + offsetof (Elf64_Shdr,
+                                                          sh_size)))
+                   != sizeof (Elf64_Xword))
+                 return (size_t) -1l;
 
              if (e_ident[EI_DATA] != MY_ELFDATA)
                CONVERT (size);
-
-             result = size;
            }
+
+         if (size > ~((GElf_Word) 0))
+           /* Invalid value, it is too large.  */
+           return (size_t) -1l;
+
+         result = size;
        }
     }
 
@@ -188,6 +220,7 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
 {
   /* We only read the ELF header now.  */
   unsigned char *e_ident;
+  unsigned char e_ident_mem[EI_NIDENT];
   size_t scncnt;
   Elf *elf;
 
@@ -197,9 +230,10 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
     e_ident = (unsigned char *) map_address + offset;
   else
     {
-      e_ident = (unsigned char *) alloca (EI_NIDENT);
+      e_ident = e_ident_mem;
 
-      if (pread (fildes, e_ident, EI_NIDENT, offset) != EI_NIDENT)
+      if (TEMP_FAILURE_RETRY (pread (fildes, e_ident, EI_NIDENT, offset))
+         != EI_NIDENT)
        {
          __libelf_seterrno (ELF_E_READ_ERROR);
          return NULL;
@@ -280,14 +314,21 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
        }
       else
        {
-         /* Read the data.  */
-         if (pread (elf->fildes, &elf->state.elf32.ehdr_mem,
-                    sizeof (Elf32_Ehdr), offset) != sizeof (Elf32_Ehdr))
-           {
-             /* We must be able to read the ELF header.  */
-             __libelf_seterrno (ELF_E_INVALID_FILE);
-             return NULL;
-           }
+         if (likely (map_address != NULL))
+           /* Copy the data.  */
+           memcpy (&elf->state.elf32.ehdr_mem,
+                   (char *) map_address + offset, sizeof (Elf32_Ehdr));
+         else
+           /* Read the data.  */
+           if (TEMP_FAILURE_RETRY (pread (elf->fildes,
+                                          &elf->state.elf32.ehdr_mem,
+                                          sizeof (Elf32_Ehdr), offset))
+               != sizeof (Elf32_Ehdr))
+             {
+               /* We must be able to read the ELF header.  */
+               __libelf_seterrno (ELF_E_INVALID_FILE);
+               return NULL;
+             }
 
          if (e_ident[EI_DATA] != MY_ELFDATA)
            {
@@ -365,9 +406,16 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
        }
       else
        {
-         /* Read the data.  */
-         if (pread (elf->fildes, &elf->state.elf64.ehdr_mem,
-                    sizeof (Elf64_Ehdr), offset) != sizeof (Elf64_Ehdr))
+         if (likely (map_address != NULL))
+           /* Copy the data.  */
+           memcpy (&elf->state.elf64.ehdr_mem,
+                   (char *) map_address + offset, sizeof (Elf64_Ehdr));
+         else
+           /* Read the data.  */
+           if (TEMP_FAILURE_RETRY (pread (elf->fildes,
+                                          &elf->state.elf64.ehdr_mem,
+                                          sizeof (Elf64_Ehdr), offset))
+               != sizeof (Elf64_Ehdr))
            {
              /* We must be able to read the ELF header.  */
              __libelf_seterrno (ELF_E_INVALID_FILE);