summaryrefslogtreecommitdiffstats
path: root/libelf/elf_getphdrnum.c
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2014-11-22 17:33:05 +0100
committerMark Wielaard <[email protected]>2014-11-26 20:12:52 +0100
commit2deeb7c51020df07d752107cdc6822d70ae1da4e (patch)
tree02375a5709a669a99fb1dfbc2d4d89ee6dab8b74 /libelf/elf_getphdrnum.c
parent9f8c08e68243561a54a09e38fd472b4fc2c17d5d (diff)
libelf: elf_getphdrnum sanity check the returned phnum result.
The internal __elf_getphdrnum_rdlock might return an inconsistent phnum. Return a sanitized value, or return an error to users that rely on phnum to be consistent. That way iterating over all phdrs using elf_getphdr will return consistent results. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'libelf/elf_getphdrnum.c')
-rw-r--r--libelf/elf_getphdrnum.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/libelf/elf_getphdrnum.c b/libelf/elf_getphdrnum.c
index d8e34d7e..63c27fb1 100644
--- a/libelf/elf_getphdrnum.c
+++ b/libelf/elf_getphdrnum.c
@@ -97,6 +97,39 @@ elf_getphdrnum (elf, dst)
rwlock_rdlock (elf->lock);
result = __elf_getphdrnum_rdlock (elf, dst);
+
+ /* Do some sanity checking to make sure phnum and phoff are consistent. */
+ Elf64_Off off = (elf->class == ELFCLASS32
+ ? elf->state.elf32.ehdr->e_phoff
+ : elf->state.elf64.ehdr->e_phoff);
+ if (unlikely (off == 0))
+ {
+ *dst = 0;
+ goto out;
+ }
+
+ if (unlikely (off >= elf->maximum_size))
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ result = -1;
+ goto out;
+ }
+
+ /* Check for too many sections. */
+ size_t phdr_size = (elf->class == ELFCLASS32
+ ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr));
+ if (unlikely (*dst > SIZE_MAX / phdr_size))
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ result = -1;
+ goto out;
+ }
+
+ /* Truncated file? Don't return more than can be indexed. */
+ if (unlikely (elf->maximum_size - off < *dst * phdr_size))
+ *dst = (elf->maximum_size - off) / phdr_size;
+
+out:
rwlock_unlock (elf->lock);
return result;