summaryrefslogtreecommitdiffstats
path: root/libelf
diff options
context:
space:
mode:
authorUlrich Drepper <[email protected]>2005-08-13 22:35:15 +0000
committerUlrich Drepper <[email protected]>2005-08-13 22:35:15 +0000
commit0f6abbbc08ee259a1a702e7dd3be3e2c6b82305e (patch)
tree5ed3739265f7d808bb12c74c554a344c8e738688 /libelf
parentf6895046ad74f67fc357d2c9f76dcb6313c13ab9 (diff)
merge of 0bc367fba741939c3256bd69de909e6c23067adf
and bc359776b21dfd2c5106da8610683718e2dd2875
Diffstat (limited to 'libelf')
-rw-r--r--libelf/ChangeLog7
-rw-r--r--libelf/elf_begin.c122
2 files changed, 92 insertions, 37 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 67d4f395..acb026ef 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,10 @@
+2005-08-13 Ulrich Drepper <[email protected]>
+
+ * 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 <[email protected]>
* elf32_offscn.c: Do not match empty sections at OFFSET unless
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c
index 404cbe83..56c7a481 100644
--- a/libelf/elf_begin.c
+++ b/libelf/elf_begin.c
@@ -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);