diff options
| author | Mark Wielaard <[email protected]> | 2014-11-22 17:33:05 +0100 |
|---|---|---|
| committer | Mark Wielaard <[email protected]> | 2014-11-26 20:12:52 +0100 |
| commit | 2deeb7c51020df07d752107cdc6822d70ae1da4e (patch) | |
| tree | 02375a5709a669a99fb1dfbc2d4d89ee6dab8b74 | |
| parent | 9f8c08e68243561a54a09e38fd472b4fc2c17d5d (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]>
| -rw-r--r-- | libelf/ChangeLog | 5 | ||||
| -rw-r--r-- | libelf/elf_getphdrnum.c | 33 |
2 files changed, 38 insertions, 0 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index c7e8d307..b21714e3 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,8 @@ +2014-11-22 Mark Wielaard <[email protected]> + + * elf_getphdrnum.c (elf_getphdrnum): Sanity check the + __elf_getphdrnum_rdlock result. + 2014-11-18 Mark Wielaard <[email protected]> * version_xlate.h (elf_cvt_Verdef): Check for overflow. 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; |
