From a3eb71adfea201f9e14980d8a96ea2e27ef52ad1 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 10 Nov 2022 11:48:01 +1030 Subject: Sanity check reloc count in get_reloc_upper_bound The idea here is the stop tools from allocating up to 32G per section for the arelent pointer array, only to find a little later that the section reloc count was fuzzed. This usually doesn't hurt much (on systems that allow malloc overcommit) except when compiled with asan. We already do this for ELF targets, and while fixing the logic recently I decided other targets ought to do the same. * elf64-sparc.c (elf64_sparc_get_reloc_upper_bound): Sanity check section reloc count against file size. * mach-o.c (bfd_mach_o_get_reloc_upper_bound): Likewise. * aoutx.h (get_reloc_upper_bound): Likewise, and don't duplicate check done in bfd_get_reloc_upper_bound. * pdp11.c (get_reloc_upper_bound): Likewise. * coffgen.c (coff_get_reloc_upper_bound): Likewise. --- bfd/aoutx.h | 20 ++++++++++++-------- bfd/coffgen.c | 22 ++++++++++++++-------- bfd/elf64-sparc.c | 19 +++++++++++++++---- bfd/mach-o.c | 22 ++++++++++++++++------ bfd/pdp11.c | 20 ++++++++++++-------- 5 files changed, 69 insertions(+), 34 deletions(-) diff --git a/bfd/aoutx.h b/bfd/aoutx.h index 4aed234..61ea9f7 100644 --- a/bfd/aoutx.h +++ b/bfd/aoutx.h @@ -2485,13 +2485,7 @@ NAME (aout, canonicalize_reloc) (bfd *abfd, long NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) { - bfd_size_type count; - - if (bfd_get_format (abfd) != bfd_object) - { - bfd_set_error (bfd_error_invalid_operation); - return -1; - } + size_t count, raw; if (asect->flags & SEC_CONSTRUCTOR) count = asect->reloc_count; @@ -2507,11 +2501,21 @@ NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) return -1; } - if (count >= LONG_MAX / sizeof (arelent *)) + if (count >= LONG_MAX / sizeof (arelent *) + || _bfd_mul_overflow (count, obj_reloc_entry_size (abfd), &raw)) { bfd_set_error (bfd_error_file_too_big); return -1; } + if (!bfd_write_p (abfd)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && raw > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } return (count + 1) * sizeof (arelent *); } diff --git a/bfd/coffgen.c b/bfd/coffgen.c index 3e0fbc6..aab41c3 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -1976,19 +1976,25 @@ coff_get_normalized_symtab (bfd *abfd) long coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) { - if (bfd_get_format (abfd) != bfd_object) + size_t count, raw; + + count = asect->reloc_count; + if (count >= LONG_MAX / sizeof (arelent *) + || _bfd_mul_overflow (count, bfd_coff_relsz (abfd), &raw)) { - bfd_set_error (bfd_error_invalid_operation); + bfd_set_error (bfd_error_file_too_big); return -1; } -#if SIZEOF_LONG == SIZEOF_INT - if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + if (!bfd_write_p (abfd)) { - bfd_set_error (bfd_error_file_too_big); - return -1; + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && raw > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } } -#endif - return (asect->reloc_count + 1L) * sizeof (arelent *); + return (count + 1) * sizeof (arelent *); } asymbol * diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c index e9f03cf..fb4483d 100644 --- a/bfd/elf64-sparc.c +++ b/bfd/elf64-sparc.c @@ -37,14 +37,25 @@ static long elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) { -#if SIZEOF_LONG == SIZEOF_INT - if (sec->reloc_count >= LONG_MAX / 2 / sizeof (arelent *)) + size_t count, raw; + + count = sec->reloc_count; + if (count >= LONG_MAX / 2 / sizeof (arelent *) + || _bfd_mul_overflow (count, sizeof (Elf64_External_Rela), &raw)) { bfd_set_error (bfd_error_file_too_big); return -1; } -#endif - return (sec->reloc_count * 2L + 1) * sizeof (arelent *); + if (!bfd_write_p (abfd)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && raw > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + return (count * 2 + 1) * sizeof (arelent *); } static long diff --git a/bfd/mach-o.c b/bfd/mach-o.c index 5279343..664ff44 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -1407,17 +1407,27 @@ bfd_mach_o_write_dyld_info (bfd *abfd, bfd_mach_o_load_command *command) } long -bfd_mach_o_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, - asection *asect) +bfd_mach_o_get_reloc_upper_bound (bfd *abfd, asection *asect) { -#if SIZEOF_LONG == SIZEOF_INT - if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + size_t count, raw; + + count = asect->reloc_count; + if (count >= LONG_MAX / sizeof (arelent *) + || _bfd_mul_overflow (count, BFD_MACH_O_RELENT_SIZE, &raw)) { bfd_set_error (bfd_error_file_too_big); return -1; } -#endif - return (asect->reloc_count + 1L) * sizeof (arelent *); + if (!bfd_write_p (abfd)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && raw > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + return (count + 1) * sizeof (arelent *); } /* In addition to the need to byte-swap the symbol number, the bit positions diff --git a/bfd/pdp11.c b/bfd/pdp11.c index 9ef63cc..de9c869 100644 --- a/bfd/pdp11.c +++ b/bfd/pdp11.c @@ -2125,13 +2125,7 @@ NAME (aout, canonicalize_reloc) (bfd *abfd, long NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) { - bfd_size_type count; - - if (bfd_get_format (abfd) != bfd_object) - { - bfd_set_error (bfd_error_invalid_operation); - return -1; - } + size_t count, raw; if (asect->flags & SEC_CONSTRUCTOR) count = asect->reloc_count; @@ -2147,11 +2141,21 @@ NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) return -1; } - if (count >= LONG_MAX / sizeof (arelent *)) + if (count >= LONG_MAX / sizeof (arelent *) + || _bfd_mul_overflow (count, obj_reloc_entry_size (abfd), &raw)) { bfd_set_error (bfd_error_file_too_big); return -1; } + if (!bfd_write_p (abfd)) + { + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && raw > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } return (count + 1) * sizeof (arelent *); } -- cgit v1.1