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.
This commit is contained in:
Alan Modra
2022-11-10 11:48:01 +10:30
parent f735116b3f
commit a3eb71adfe
5 changed files with 70 additions and 35 deletions

View File

@ -2485,13 +2485,7 @@ NAME (aout, canonicalize_reloc) (bfd *abfd,
long long
NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
{ {
bfd_size_type count; size_t count, raw;
if (bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
if (asect->flags & SEC_CONSTRUCTOR) if (asect->flags & SEC_CONSTRUCTOR)
count = asect->reloc_count; count = asect->reloc_count;
@ -2507,11 +2501,21 @@ NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
return -1; 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); bfd_set_error (bfd_error_file_too_big);
return -1; 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 *); return (count + 1) * sizeof (arelent *);
} }

View File

@ -1976,19 +1976,25 @@ coff_get_normalized_symtab (bfd *abfd)
long long
coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
{ {
if (bfd_get_format (abfd) != bfd_object) size_t count, raw;
{
bfd_set_error (bfd_error_invalid_operation); count = asect->reloc_count;
return -1; if (count >= LONG_MAX / sizeof (arelent *)
} || _bfd_mul_overflow (count, bfd_coff_relsz (abfd), &raw))
#if SIZEOF_LONG == SIZEOF_INT
if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
{ {
bfd_set_error (bfd_error_file_too_big); bfd_set_error (bfd_error_file_too_big);
return -1; return -1;
} }
#endif if (!bfd_write_p (abfd))
return (asect->reloc_count + 1L) * sizeof (arelent *); {
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 *);
} }
asymbol * asymbol *

View File

@ -37,14 +37,25 @@
static long static long
elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{ {
#if SIZEOF_LONG == SIZEOF_INT size_t count, raw;
if (sec->reloc_count >= LONG_MAX / 2 / sizeof (arelent *))
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); bfd_set_error (bfd_error_file_too_big);
return -1; return -1;
} }
#endif if (!bfd_write_p (abfd))
return (sec->reloc_count * 2L + 1) * sizeof (arelent *); {
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 static long

View File

@ -1407,17 +1407,27 @@ bfd_mach_o_write_dyld_info (bfd *abfd, bfd_mach_o_load_command *command)
} }
long long
bfd_mach_o_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_get_reloc_upper_bound (bfd *abfd, asection *asect)
asection *asect)
{ {
#if SIZEOF_LONG == SIZEOF_INT size_t count, raw;
if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
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); bfd_set_error (bfd_error_file_too_big);
return -1; return -1;
} }
#endif if (!bfd_write_p (abfd))
return (asect->reloc_count + 1L) * sizeof (arelent *); {
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 /* In addition to the need to byte-swap the symbol number, the bit positions

View File

@ -2125,13 +2125,7 @@ NAME (aout, canonicalize_reloc) (bfd *abfd,
long long
NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
{ {
bfd_size_type count; size_t count, raw;
if (bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
if (asect->flags & SEC_CONSTRUCTOR) if (asect->flags & SEC_CONSTRUCTOR)
count = asect->reloc_count; count = asect->reloc_count;
@ -2147,11 +2141,21 @@ NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
return -1; 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); bfd_set_error (bfd_error_file_too_big);
return -1; 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 *); return (count + 1) * sizeof (arelent *);
} }