Resetting section vma after _bfd_dwarf2_find_nearest_line

There are failure paths in _bfd_dwarf2_slurp_debug_info that can
result in altered section vmas.  Also, when setting ET_REL section
vmas it's not too difficult to handle cases where the original vma was
non-zero, so do that too.

This patch was really in response to an addr2line buffer overflow
processing a fuzzed mips relocatable object file.  The file had a
number of .debug_info sections with relocations that included lo16 and
hi16 relocs, and in that order.  At least one section VMA was
non-zero.  This resulted in processing of DWARF info twice, once via
the call to _bfd_dwarf2_find_nearest_line in
_bfd_mips_elf_find_nearest_line, and because that failed leaving VMAs
altered, the second via the call in _bfd_elf_find_nearest_line.  The
first call left entries on mips_hi16_list pointing at buffers
allocated during the first call, the second call processed the
mips_hi16_list after the buffers had been freed.  (At least when
running with asan and under valgrind.  Under gdb with a non-asan
addr2line the second call allocated exactly the same buffer and the
bug didn't show.)  Now I don't really care too much what happens with
fuzzed files, but the logic in _bfd_dwarf2_find_nearest_line is meant
to result in only one read of .debug_info, not multiple reads of the
same info when there are errors.  This patch fixes that problem.

	* dwarf2.c (struct adjusted_section): Add orig_vma.
	(unset_sections): Reset vma to it.
	(place_sections): Handle non-zero vma too.  Save orig_vma.
	(_bfd_dwarf2_slurp_debug_info): Tidy.  Correct outdated comment.
	On error returns after calling place_sections, call
	unset_sections.
	(_bfd_dwarf2_find_nearest_line_with_alt): Simplify call to
	unset_sections.
This commit is contained in:
Alan Modra
2023-02-04 11:29:05 +10:30
parent 023b960d59
commit d4a8b80189

View File

@ -82,6 +82,7 @@ struct adjusted_section
{
asection *section;
bfd_vma adj_vma;
bfd_vma orig_vma;
};
/* A trie to map quickly from address range to compilation unit.
@ -4952,7 +4953,7 @@ unset_sections (struct dwarf2_debug *stash)
i = stash->adjusted_section_count;
p = stash->adjusted_sections;
for (; i > 0; i--, p++)
p->section->vma = 0;
p->section->vma = p->orig_vma;
}
/* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a
@ -4993,10 +4994,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
{
int is_debug_info;
if ((sect->output_section != NULL
&& sect->output_section != sect
&& (sect->flags & SEC_DEBUGGING) == 0)
|| sect->vma != 0)
if (sect->output_section != NULL
&& sect->output_section != sect
&& (sect->flags & SEC_DEBUGGING) == 0)
continue;
is_debug_info = (strcmp (sect->name, debug_info_name) == 0
@ -5037,10 +5037,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
bfd_size_type sz;
int is_debug_info;
if ((sect->output_section != NULL
&& sect->output_section != sect
&& (sect->flags & SEC_DEBUGGING) == 0)
|| sect->vma != 0)
if (sect->output_section != NULL
&& sect->output_section != sect
&& (sect->flags & SEC_DEBUGGING) == 0)
continue;
is_debug_info = (strcmp (sect->name, debug_info_name) == 0
@ -5052,24 +5051,17 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
sz = sect->rawsize ? sect->rawsize : sect->size;
if (is_debug_info)
{
BFD_ASSERT (sect->alignment_power == 0);
sect->vma = last_dwarf;
last_dwarf += sz;
}
else
{
/* Align the new address to the current section
alignment. */
last_vma = ((last_vma
+ ~(-((bfd_vma) 1 << sect->alignment_power)))
& (-((bfd_vma) 1 << sect->alignment_power)));
sect->vma = last_vma;
last_vma += sz;
}
p->section = sect;
p->orig_vma = sect->vma;
bfd_vma *v = is_debug_info ? &last_dwarf : &last_vma;
/* Align the new address to the current section
alignment. */
bfd_vma mask = -(bfd_vma) 1 << sect->alignment_power;
*v = (*v + ~mask) & mask;
sect->vma = *v;
*v += sz;
p->adj_vma = sect->vma;
p++;
}
@ -5379,7 +5371,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
void **pinfo,
bool do_place)
{
size_t amt = sizeof (struct dwarf2_debug);
bfd_size_type total_size;
asection *msec;
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
@ -5401,11 +5392,11 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
return false;
}
_bfd_dwarf2_cleanup_debug_info (abfd, pinfo);
memset (stash, 0, amt);
memset (stash, 0, sizeof (*stash));
}
else
{
stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
stash = (struct dwarf2_debug *) bfd_zalloc (abfd, sizeof (*stash));
if (! stash)
return false;
*pinfo = stash;
@ -5482,14 +5473,11 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
/* There can be more than one DWARF2 info section in a BFD these
days. First handle the easy case when there's only one. If
there's more than one, try case two: none of the sections is
compressed. In that case, read them all in and produce one
large stash. We do this in two passes - in the first pass we
there's more than one, try case two: read them all in and produce
one large stash. We do this in two passes - in the first pass we
just accumulate the section sizes, and in the second pass we
read in the section's contents. (The allows us to avoid
reallocing the data as we add sections to the stash.) If
some or all sections are compressed, then do things the slow
way, with a bunch of reallocs. */
reallocing the data as we add sections to the stash.) */
if (! find_debug_info (debug_bfd, debug_sections, msec))
{
@ -5498,7 +5486,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
if (! read_section (debug_bfd, &stash->debug_sections[debug_info],
symbols, 0,
&stash->f.dwarf_info_buffer, &total_size))
return false;
goto restore_vma;
}
else
{
@ -5508,19 +5496,19 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
msec = find_debug_info (debug_bfd, debug_sections, msec))
{
if (_bfd_section_size_insane (debug_bfd, msec))
return false;
goto restore_vma;
/* Catch PR25070 testcase overflowing size calculation here. */
if (total_size + msec->size < total_size)
{
bfd_set_error (bfd_error_no_memory);
return false;
goto restore_vma;
}
total_size += msec->size;
}
stash->f.dwarf_info_buffer = (bfd_byte *) bfd_malloc (total_size);
if (stash->f.dwarf_info_buffer == NULL)
return false;
goto restore_vma;
total_size = 0;
for (msec = find_debug_info (debug_bfd, debug_sections, NULL);
@ -5536,7 +5524,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
if (!(bfd_simple_get_relocated_section_contents
(debug_bfd, msec, stash->f.dwarf_info_buffer + total_size,
symbols)))
return false;
goto restore_vma;
total_size += size;
}
@ -5545,6 +5533,10 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
stash->f.info_ptr = stash->f.dwarf_info_buffer;
stash->f.dwarf_info_size = total_size;
return true;
restore_vma:
unset_sections (stash);
return false;
}
/* Parse the next DWARF2 compilation unit at FILE->INFO_PTR. */
@ -6038,8 +6030,7 @@ _bfd_dwarf2_find_nearest_line_with_alt
}
}
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
unset_sections (stash);
unset_sections (stash);
return found;
}