From 5f6cd01d4ca5d5b0fab6dd35d22fbf900f50364f Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 7 Nov 2014 12:54:02 +0100 Subject: [PATCH] readelf: Sanity check hash section contents before processing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported by: Hanno Böck Signed-off-by: Mark Wielaard --- src/ChangeLog | 6 ++++++ src/readelf.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index a252cdc..3ff3e31 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2014-11-07 Mark Wielaard + + * readelf.c (handle_sysv_hash): Sanity check section contents. + (handle_sysv_hash64): Likewise. + (handle_gnu_hash): Likewise. + 2014-09-14 Petr Machata * readelf.c (handle_relocs_rela): Typo fix, test DESTSHDR properly. diff --git a/src/readelf.c b/src/readelf.c index 4d3bb36..fba6c03 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -2954,8 +2954,21 @@ handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx) return; } + if (unlikely (data->d_size < 2 * sizeof (Elf32_Word))) + { + invalid_data: + error (0, 0, gettext ("invalid data in sysv.hash section %d"), + (int) elf_ndxscn (scn)); + return; + } + Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1]; + + uint32_t used_buf = (2 + nchain + nbucket) * sizeof (Elf32_Word); + if (used_buf > data->d_size || used_buf + data->d_size < data->d_size) + goto invalid_data; + Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2]; Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket]; @@ -2996,8 +3009,21 @@ handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx) return; } + if (unlikely (data->d_size < 2 * sizeof (Elf64_Xword))) + { + invalid_data: + error (0, 0, gettext ("invalid data in sysv.hash64 section %d"), + (int) elf_ndxscn (scn)); + return; + } + Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0]; Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1]; + + uint32_t used_buf = (2 + nchain + nbucket) * sizeof (Elf64_Xword); + if (used_buf > data->d_size || used_buf + data->d_size < data->d_size) + goto invalid_data; + Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2]; Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket]; @@ -3037,18 +3063,36 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx) return; } + if (unlikely (data->d_size < 4 * sizeof (Elf32_Word))) + { + invalid_data: + error (0, 0, gettext ("invalid data in gnu.hash section %d"), + (int) elf_ndxscn (scn)); + return; + } + Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1]; /* Next comes the size of the bitmap. It's measured in words for the architecture. It's 32 bits for 32 bit archs, and 64 bits for - 64 bit archs. */ + 64 bit archs. There is always a bloom filter present, so zero is + an invalid value. */ Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2]; if (gelf_getclass (ebl->elf) == ELFCLASS64) bitmask_words *= 2; + if (bitmask_words == 0) + goto invalid_data; + Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3]; + /* Is there still room for the sym chain? Check for unsigned overlow. */ + uint32_t used_buf = (4 + bitmask_words + nbucket) * sizeof (Elf32_Word); + uint32_t max_nsyms = (data->d_size - used_buf) / sizeof (Elf32_Word); + if (used_buf > data->d_size || used_buf + data->d_size < data->d_size) + goto invalid_data; + uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t)); Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4]; @@ -3068,6 +3112,8 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx) ++nsyms; if (maxlength < ++lengths[cnt]) ++maxlength; + if (inner > max_nsyms) + goto invalid_data; } while ((chain[inner++] & 1) == 0); } -- 1.9.3