mips-coff: mips_reflo_reloc buffer overflow
Alan Modra
amodra@gmail.com
Thu Jun 11 07:08:10 GMT 2026
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 --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. */
--
Alan Modra
More information about the Binutils
mailing list