From 2c7c5554df19e410ea3a7d78b0c1435967a4bc62 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 19 Feb 2020 13:22:39 +1030 Subject: [PATCH] file size check in _bfd_alloc_and_read * coffgen.c (_bfd_coff_get_external_symbols): Remove file size check. * elf.c (bfd_elf_get_str_section): Likewise. (_bfd_elf_slurp_version_tables): Likewise. * libbfd-in.h (_bfd_constant_p): Define. (_bfd_alloc_and_read, _bfd_malloc_and_read): Check read size against file size before allocating memory. * libbfd.h: Regenerate. --- bfd/ChangeLog | 10 ++++++++++ bfd/coffgen.c | 8 +------- bfd/elf.c | 14 -------------- bfd/libbfd-in.h | 30 ++++++++++++++++++++++++++++-- bfd/libbfd.h | 30 ++++++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f2ddd86a3c..e68e558505 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2020-02-19 Alan Modra + + * libbfd-in.h (_bfd_constant_p): Define. + (_bfd_alloc_and_read, _bfd_malloc_and_read): Check read size against + file size before allocating memory. + * coffgen.c (_bfd_coff_get_external_symbols): Remove file size check. + * elf.c (bfd_elf_get_str_section): Likewise. + (_bfd_elf_slurp_version_tables): Likewise. + * libbfd.h: Regenerate. + 2020-02-19 Alan Modra * libbfd-in.h (_bfd_alloc_and_read, _bfd_malloc_and_read): New. diff --git a/bfd/coffgen.c b/bfd/coffgen.c index dda98394f1..daaaba95c5 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -1632,20 +1632,14 @@ _bfd_coff_get_external_symbols (bfd *abfd) size_t symesz; size_t size; void * syms; - ufile_ptr filesize; if (obj_coff_external_syms (abfd) != NULL) return TRUE; - /* Check for integer overflow and for unreasonable symbol counts. */ - filesize = bfd_get_file_size (abfd); symesz = bfd_coff_symesz (abfd); - if (_bfd_mul_overflow (obj_raw_syment_count (abfd), symesz, &size) - || (filesize != 0 && size > filesize)) + if (_bfd_mul_overflow (obj_raw_syment_count (abfd), symesz, &size)) { bfd_set_error (bfd_error_file_truncated); - _bfd_error_handler (_("%pB: corrupt symbol count: %#" PRIx64 ""), - abfd, (uint64_t) obj_raw_syment_count (abfd)); return FALSE; } diff --git a/bfd/elf.c b/bfd/elf.c index 7eb717b7ff..deb93b0a5a 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -296,7 +296,6 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || shstrtabsize > bfd_get_file_size (abfd) || bfd_seek (abfd, offset, SEEK_SET) != 0 || (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1, shstrtabsize)) == NULL) @@ -8586,19 +8585,6 @@ error_return_verref: goto error_return; } - ufile_ptr filesize = bfd_get_file_size (abfd); - if (filesize > 0 && filesize < hdr->sh_size) - { - /* PR 24708: Avoid attempts to allocate a ridiculous amount - of memory. */ - bfd_set_error (bfd_error_no_memory); - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %pB version reference section is too large (%#" PRIx64 " bytes)"), - abfd, (uint64_t) hdr->sh_size); - goto error_return_verref; - } - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0) goto error_return_verref; contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index a8f9bcd47d..6d796b7ef8 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -904,10 +904,26 @@ extern bfd_vma _bfd_safe_read_leb128 ((*res) = (a), (*res) *= (b), (b) != 0 && (*res) / (b) != (a)) #endif +#ifdef __GNUC__ +#define _bfd_constant_p(v) __builtin_constant_p (v) +#else +#define _bfd_constant_p(v) 0 +#endif + static inline bfd_byte * _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { - bfd_byte *mem = bfd_alloc (abfd, asize); + bfd_byte *mem; + if (!_bfd_constant_p (rsize)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && rsize > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + } + mem = bfd_alloc (abfd, asize); if (mem != NULL) { if (bfd_bread (mem, rsize, abfd) == rsize) @@ -920,7 +936,17 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) static inline bfd_byte * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { - bfd_byte *mem = bfd_malloc (asize); + bfd_byte *mem; + if (!_bfd_constant_p (rsize)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && rsize > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + } + mem = bfd_malloc (asize); if (mem != NULL) { if (bfd_bread (mem, rsize, abfd) == rsize) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 77c66309a2..2391500c33 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -909,10 +909,26 @@ extern bfd_vma _bfd_safe_read_leb128 ((*res) = (a), (*res) *= (b), (b) != 0 && (*res) / (b) != (a)) #endif +#ifdef __GNUC__ +#define _bfd_constant_p(v) __builtin_constant_p (v) +#else +#define _bfd_constant_p(v) 0 +#endif + static inline bfd_byte * _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { - bfd_byte *mem = bfd_alloc (abfd, asize); + bfd_byte *mem; + if (!_bfd_constant_p (rsize)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && rsize > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + } + mem = bfd_alloc (abfd, asize); if (mem != NULL) { if (bfd_bread (mem, rsize, abfd) == rsize) @@ -925,7 +941,17 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) static inline bfd_byte * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { - bfd_byte *mem = bfd_malloc (asize); + bfd_byte *mem; + if (!_bfd_constant_p (rsize)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && rsize > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + } + mem = bfd_malloc (asize); if (mem != NULL) { if (bfd_bread (mem, rsize, abfd) == rsize) -- 2.34.1