mips-coff: mips_reflo_reloc buffer overflow

Like commit c2cb1bfb90, but for mips-coff.  Make the hi reloc list
per-section rather than per-file, since fuzzers can generate objects
with cross-section refs where the hi reloc section data is freed
before the lo relocs are processed.

Also properly sanity check the hi reloc offset.

	* libecoff.h (struct ecoff_tdata): Move mips_refhi_list to..
	(struct ecoff_section_tdata): ..here.
	(ecoff_section_data): Remove unused abfd arg.
	* coff-alpha.c (alpha_relocate_section): Update ecoff_section_data.
	* coff-mips.c (mips_refhi_reloc): Use bfd_reloc_offset_in_range.
	Allocate ecoff_section_data as necessary.  Use that instead of
	bfd tdata.
	(mips_reflo_reloc): Adjust to suit tdata change.
	* ecoff.c (_bfd_ecoff_bfd_free_cached_info): Likewise.
This commit is contained in:
Alan Modra 2026-06-11 11:10:40 +09:30
parent 6c85ef111b
commit f4441fd82f
4 changed files with 36 additions and 18 deletions

View file

@ -1445,7 +1445,7 @@ alpha_relocate_section (bfd *output_bfd,
/* Make sure we have a section data structure to which we can
hang on to the gp value we pick for the section. */
lita_sec_data = ecoff_section_data (input_bfd, lita_sec);
lita_sec_data = ecoff_section_data (lita_sec);
if (lita_sec_data == NULL)
{
lita_sec_data = bfd_zalloc (input_bfd, sizeof (*lita_sec_data));

View file

@ -460,17 +460,29 @@ mips_refhi_reloc (bfd *abfd,
relocation += symbol->section->output_offset;
relocation += reloc_entry->addend;
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
bfd_size_type octet = (reloc_entry->address
* OCTETS_PER_BYTE (abfd, input_section));
if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
input_section, octet))
return bfd_reloc_outofrange;
struct ecoff_section_tdata *sdata = ecoff_section_data (input_section);
if (sdata == NULL)
{
sdata = bfd_zalloc (abfd, sizeof (*sdata));
if (sdata == NULL)
return bfd_reloc_outofrange;
input_section->used_by_bfd = sdata;
}
/* Save the information, and let REFLO do the actual relocation. */
n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
n = bfd_malloc (sizeof (*n));
if (n == NULL)
return bfd_reloc_outofrange;
n->addr = (bfd_byte *) data + reloc_entry->address;
n->addend = relocation;
n->next = ecoff_data (abfd)->mips_refhi_list;
ecoff_data (abfd)->mips_refhi_list = n;
n->next = sdata->mips_refhi_list;
sdata->mips_refhi_list = n;
if (output_bfd != (bfd *) NULL)
reloc_entry->address += input_section->output_offset;
@ -491,11 +503,11 @@ mips_reflo_reloc (bfd *abfd,
bfd *output_bfd,
char **error_message)
{
if (ecoff_data (abfd)->mips_refhi_list != NULL)
struct ecoff_section_tdata *sdata = ecoff_section_data (input_section);
if (sdata != NULL)
{
struct mips_hi *l;
struct mips_hi *l = sdata->mips_refhi_list;
l = ecoff_data (abfd)->mips_refhi_list;
while (l != NULL)
{
unsigned long insn;
@ -537,8 +549,7 @@ mips_reflo_reloc (bfd *abfd,
free (l);
l = next;
}
ecoff_data (abfd)->mips_refhi_list = NULL;
sdata->mips_refhi_list = NULL;
}
/* Now do the REFLO reloc in the usual way. */

View file

@ -117,11 +117,18 @@ _bfd_ecoff_bfd_free_cached_info (bfd *abfd)
if (bfd_get_format (abfd) == bfd_object
&& (tdata = ecoff_data (abfd)) != NULL)
{
while (tdata->mips_refhi_list != NULL)
for (asection *sec = abfd->sections; sec != NULL; sec = sec->next)
{
struct mips_hi *ref = tdata->mips_refhi_list;
tdata->mips_refhi_list = ref->next;
free (ref);
struct ecoff_section_tdata *sdata = ecoff_section_data (sec);
if (sdata != NULL)
{
while (sdata->mips_refhi_list != NULL)
{
struct mips_hi *ref = sdata->mips_refhi_list;
sdata->mips_refhi_list = ref->next;
free (ref);
}
}
}
_bfd_ecoff_free_ecoff_debug_info (&tdata->debug_info);
}

View file

@ -153,9 +153,6 @@ typedef struct ecoff_tdata
particular ECOFF file. This is not valid until
ecoff_compute_section_file_positions is called. */
bool rdata_in_text;
/* Used by coff-mips.c to track REFHI relocs for pairing with REFLO. */
struct mips_hi *mips_refhi_list;
} ecoff_data_type;
/* Each canonical asymbol really looks like this. */
@ -201,10 +198,13 @@ struct ecoff_section_tdata
we need to keep track of the gp values that we picked for each
input .lita section . */
bfd_vma gp;
/* Used by coff-mips.c to track REFHI relocs for pairing with REFLO. */
struct mips_hi *mips_refhi_list;
};
/* An accessor macro for the ecoff_section_tdata structure. */
#define ecoff_section_data(abfd, sec) \
#define ecoff_section_data(sec) \
((struct ecoff_section_tdata *) (sec)->used_by_bfd)
/* ECOFF linker hash table entries. */