bfd dwarf2 sanity checking

This patch is aimed at the many places in dwarf2.c that blindly
increment a data pointer after calling functions that are meant to
read a fixed number of bytes.  The problem with that is with damaged
dwarf we might increment a data pointer past the end of data, which is
UB and complicates (ie. bugs likely) any further use of that data
pointer.  To fix those problems, I've moved incrementing of the data
pointer into the functions that do the reads.  _bfd_safe_read_leb128
gets the same treatment for consistency.

	* libbfd.c (_bfd_safe_read_leb128): Remove length_return parameter.
	Replace data pointer with pointer to pointer.  Increment pointer
	over bytes read.
	* libbfd-in.h (_bfd_safe_read_leb128): Update prototype.
	* elf-attrs.c (_bfd_elf_parse_attributes): Adjust to suit.  Be
	careful not to increment data pointer past end.  Remove now
	redundant pr17512 check.
	* wasm-module.c (READ_LEB128): Adjust to suit changes to
	_bfd_safe_read_leb128.
	* dwarf2.c (read_n_bytes): New inline function, old one renamed to..
	(read_blk): ..this.  Allocate and return block.  Increment bfd_byte**
	arg.
	(read_3_bytes): New function.
	(read_1_byte, read_1_signed_byte, read_2_bytes, read_4_bytes),
	(read_8_bytes, read_string, read_indirect_string),
	(read_indirect_line_string, read_alt_indirect_string): Take a
	byte_byte** arg which is incremented over bytes read.  Remove any
	bytes_read return.  Rewrite limit checks to compare lengths
	rather than pointers.
	(read_abbrevs, read_attribute_value, read_formatted_entries),
	(decode_line_info, find_abstract_instance, read_ranges),
	(read_rnglists, scan_unit_for_symbols, parse_comp_unit),
	(stash_comp_unit): Adjust to suit.  Rewrite limit checks to
	compare lengths rather than pointers.
	* libbfd.h: Regenerate.
This commit is contained in:
Alan Modra 2021-05-21 22:34:34 +09:30
parent 1f1fb219fd
commit 574ec1084d
7 changed files with 290 additions and 413 deletions

View file

@ -1,3 +1,31 @@
2021-05-22 Alan Modra <amodra@gmail.com>
* libbfd.c (_bfd_safe_read_leb128): Remove length_return parameter.
Replace data pointer with pointer to pointer. Increment pointer
over bytes read.
* libbfd-in.h (_bfd_safe_read_leb128): Update prototype.
* elf-attrs.c (_bfd_elf_parse_attributes): Adjust to suit. Be
careful not to increment data pointer past end. Remove now
redundant pr17512 check.
* wasm-module.c (READ_LEB128): Adjust to suit changes to
_bfd_safe_read_leb128.
* dwarf2.c (read_n_bytes): New inline function, old one renamed to..
(read_blk): ..this. Allocate and return block. Increment bfd_byte**
arg.
(read_3_bytes): New function.
(read_1_byte, read_1_signed_byte, read_2_bytes, read_4_bytes),
(read_8_bytes, read_string, read_indirect_string),
(read_indirect_line_string, read_alt_indirect_string): Take a
byte_byte** arg which is incremented over bytes read. Remove any
bytes_read return. Rewrite limit checks to compare lengths
rather than pointers.
(read_abbrevs, read_attribute_value, read_formatted_entries),
(decode_line_info, find_abstract_instance, read_ranges),
(read_rnglists, scan_unit_for_symbols, parse_comp_unit),
(stash_comp_unit): Adjust to suit. Rewrite limit checks to
compare lengths rather than pointers.
* libbfd.h: Regenerate.
2021-05-21 Luis Machado <luis.machado@linaro.org>
* elf.c (elfcore_make_memtag_note_section): New function.

File diff suppressed because it is too large Load diff

View file

@ -471,7 +471,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
{
len = hdr->sh_size - 1;
while (len > 0 && p < p_end - 4)
while (len > 0 && p_end - p >= 4)
{
unsigned namelen;
bfd_vma section_len;
@ -511,28 +511,28 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
while (section_len > 0 && p < p_end)
{
unsigned int tag;
unsigned int n;
unsigned int val;
bfd_vma subsection_len;
bfd_byte *end;
bfd_byte *end, *orig_p;
tag = _bfd_safe_read_leb128 (abfd, p, &n, false, p_end);
p += n;
if (p < p_end - 4)
orig_p = p;
tag = _bfd_safe_read_leb128 (abfd, &p, false, p_end);
if (p_end - p >= 4)
{
subsection_len = bfd_get_32 (abfd, p);
else
subsection_len = 0;
p += 4;
}
else
{
subsection_len = 0;
p = p_end;
}
if (subsection_len == 0)
break;
if (subsection_len > section_len)
subsection_len = section_len;
section_len -= subsection_len;
subsection_len -= n + 4;
end = p + subsection_len;
/* PR 17512: file: 0e8c0c90. */
if (end > p_end)
end = p_end;
end = orig_p + subsection_len;
switch (tag)
{
case Tag_File:
@ -540,14 +540,12 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
{
int type;
tag = _bfd_safe_read_leb128 (abfd, p, &n, false, end);
p += n;
tag = _bfd_safe_read_leb128 (abfd, &p, false, end);
type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
{
case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
val = _bfd_safe_read_leb128 (abfd, p, &n, false, end);
p += n;
val = _bfd_safe_read_leb128 (abfd, &p, false, end);
bfd_elf_add_obj_attr_int_string (abfd, vendor, tag,
val, (char *) p);
p += strlen ((char *)p) + 1;
@ -558,8 +556,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
p += strlen ((char *)p) + 1;
break;
case ATTR_TYPE_FLAG_INT_VAL:
val = _bfd_safe_read_leb128 (abfd, p, &n, false, end);
p += n;
val = _bfd_safe_read_leb128 (abfd, &p, false, end);
bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
break;
default:
@ -572,8 +569,8 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
/* Don't have anywhere convenient to attach these.
Fall through for now. */
default:
/* Ignore things we don't kow about. */
p += subsection_len;
/* Ignore things we don't know about. */
p = end;
subsection_len = 0;
break;
}

View file

@ -888,8 +888,7 @@ extern bfd_vma _bfd_read_unsigned_leb128
extern bfd_signed_vma _bfd_read_signed_leb128
(bfd *, bfd_byte *, unsigned int *) ATTRIBUTE_HIDDEN;
extern bfd_vma _bfd_safe_read_leb128
(bfd *, bfd_byte *, unsigned int *, bool, const bfd_byte * const)
ATTRIBUTE_HIDDEN;
(bfd *, bfd_byte **, bool, const bfd_byte * const) ATTRIBUTE_HIDDEN;
extern bfd_byte * _bfd_write_unsigned_leb128
(bfd_byte *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;

View file

@ -1170,28 +1170,26 @@ _bfd_read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
return result;
}
/* Read in a LEB128 encoded value from ABFD starting at DATA.
/* Read in a LEB128 encoded value from ABFD starting at *PTR.
If SIGN is true, return a signed LEB128 value.
If LENGTH_RETURN is not NULL, return in it the number of bytes read.
*PTR is incremented by the number of bytes read.
No bytes will be read at address END or beyond. */
bfd_vma
_bfd_safe_read_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
bfd_byte *data,
unsigned int *length_return,
bfd_byte **ptr,
bool sign,
const bfd_byte * const end)
{
bfd_vma result = 0;
unsigned int num_read = 0;
unsigned int shift = 0;
unsigned char byte = 0;
bfd_byte *data = *ptr;
while (data < end)
{
byte = bfd_get_8 (abfd, data);
data++;
num_read++;
if (shift < 8 * sizeof (result))
{
result |= ((bfd_vma) (byte & 0x7f)) << shift;
@ -1201,8 +1199,7 @@ _bfd_safe_read_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
break;
}
if (length_return != NULL)
*length_return = num_read;
*ptr = data;
if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
result |= -((bfd_vma) 1 << shift);

View file

@ -893,8 +893,7 @@ extern bfd_vma _bfd_read_unsigned_leb128
extern bfd_signed_vma _bfd_read_signed_leb128
(bfd *, bfd_byte *, unsigned int *) ATTRIBUTE_HIDDEN;
extern bfd_vma _bfd_safe_read_leb128
(bfd *, bfd_byte *, unsigned int *, bool, const bfd_byte * const)
ATTRIBUTE_HIDDEN;
(bfd *, bfd_byte **, bool, const bfd_byte * const) ATTRIBUTE_HIDDEN;
extern bfd_byte * _bfd_write_unsigned_leb128
(bfd_byte *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;

View file

@ -182,12 +182,9 @@ wasm_write_uleb128 (bfd *abfd, bfd_vma v)
#define READ_LEB128(x, p, end) \
do \
{ \
unsigned int length_read; \
(x) = _bfd_safe_read_leb128 (abfd, (p), &length_read, \
false, (end)); \
(p) += length_read; \
if (length_read == 0) \
if ((p) >= (end)) \
goto error_return; \
(x) = _bfd_safe_read_leb128 (abfd, &(p), false, (end)); \
} \
while (0)