[binutils-gdb] mips-coff: mips_reflo_reloc buffer overflow
Alan Modra via Binutils-cvs <[email protected]> Thu, 11 Jun 2026 07:09:11 +0000 (GMT)
| Newsgroups | gmane.comp.gnu.binutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f4441fd82f1cf477683ed3c08271cff7e975937a commit f4441fd82f1cf477683ed3c08271cff7e975937a Author: Alan Modra <[email protected]> Date: Thu Jun 11 11:10:40 2026 +0930 mips-coff: mips_reflo_reloc buffer overflow Like commit c2cb1bfb901e, 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. Diff: --- bfd/coff-alpha.c | 2 +- bfd/coff-mips.c | 29 ++++++++++++++++++++--------- bfd/ecoff.c | 15 +++++++++++---- bfd/libecoff.h | 8 ++++---- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index 0396a1fd9fc..35677e9a933 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -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)); diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c index 85abe9f4360..35848d94ca1 100644 --- a/bfd/coff-mips.c +++ b/bfd/coff-mips.c @@ -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. */ diff --git a/bfd/ecoff.c b/bfd/ecoff.c index cd56a46c460..906fe44725e 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -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); } diff --git a/bfd/libecoff.h b/bfd/libecoff.h index 1d781c7d309..25619b7346c 100644 --- a/bfd/libecoff.h +++ b/bfd/libecoff.h @@ -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. */