Ensure data pointer kept within bounds

* dwarf.c (process_extended_line_op): Don't bump data pointer past
	end when strnlen doesn't find string terminator.
	(decode_location_expression): Remove dead code.
	(skip_attr_bytes): Remove const from end param.  Ensure data
	pointer doesn't pass end.
	(get_type_signedness): Remove const from end param.
	(read_and_display_attr_value): Ensure data pointer doesn't pass end.
	(display_debug_lines_raw, display_debug_lines_decoded): Likewise.
	(display_debug_pubnames_worker): Likewise.
	(display_debug_pubnames_worker): Use SAFE_BYTE_GET_AND INC rather
	than blindly incrementing data pointer.
	(display_debug_addr, display_debug_str_offsets): Likewise.  Don't
	compare pointers, compare lengths.
This commit is contained in:
Alan Modra
2021-05-12 17:27:34 +09:30
parent 6d1ad6f783
commit a7077ce760
2 changed files with 72 additions and 40 deletions

View File

@ -1,3 +1,19 @@
2021-05-12 Alan Modra <amodra@gmail.com>
* dwarf.c (process_extended_line_op): Don't bump data pointer past
end when strnlen doesn't find string terminator.
(decode_location_expression): Remove dead code.
(skip_attr_bytes): Remove const from end param. Ensure data
pointer doesn't pass end.
(get_type_signedness): Remove const from end param.
(read_and_display_attr_value): Ensure data pointer doesn't pass end.
(display_debug_lines_raw, display_debug_lines_decoded): Likewise.
(display_debug_pubnames_worker): Likewise.
(display_debug_pubnames_worker): Use SAFE_BYTE_GET_AND INC rather
than blindly incrementing data pointer.
(display_debug_addr, display_debug_str_offsets): Likewise. Don't
compare pointers, compare lengths.
2021-05-12 Alan Modra <amodra@gmail.com> 2021-05-12 Alan Modra <amodra@gmail.com>
* dwarf.c (SAFE_BYTE_GET_INTERNAL): Define. * dwarf.c (SAFE_BYTE_GET_INTERNAL): Define.

View File

@ -508,7 +508,9 @@ process_extended_line_op (unsigned char * data,
name = data; name = data;
l = strnlen ((char *) data, end - data); l = strnlen ((char *) data, end - data);
data += l + 1; data += l;
if (data < end)
data++;
READ_ULEB (val, data, end); READ_ULEB (val, data, end);
printf ("%s\t", dwarf_vmatoa ("u", val)); printf ("%s\t", dwarf_vmatoa ("u", val));
READ_ULEB (val, data, end); READ_ULEB (val, data, end);
@ -1612,8 +1614,6 @@ decode_location_expression (unsigned char * data,
need_frame_base = 1; need_frame_base = 1;
putchar (')'); putchar (')');
data += uvalue; data += uvalue;
if (data > end)
data = end;
break; break;
case DW_OP_const_type: case DW_OP_const_type:
case DW_OP_GNU_const_type: case DW_OP_GNU_const_type:
@ -1915,7 +1915,7 @@ check_uvalue (const unsigned char * start,
static unsigned char * static unsigned char *
skip_attr_bytes (unsigned long form, skip_attr_bytes (unsigned long form,
unsigned char *data, unsigned char *data,
unsigned const char * end, unsigned char *end,
dwarf_vma pointer_size, dwarf_vma pointer_size,
dwarf_vma offset_size, dwarf_vma offset_size,
int dwarf_version, int dwarf_version,
@ -1923,6 +1923,7 @@ skip_attr_bytes (unsigned long form,
{ {
dwarf_signed_vma svalue; dwarf_signed_vma svalue;
dwarf_vma uvalue = 0; dwarf_vma uvalue = 0;
dwarf_vma inc = 0;
* value_return = 0; * value_return = 0;
@ -2000,51 +2001,54 @@ skip_attr_bytes (unsigned long form,
case DW_FORM_data8: case DW_FORM_data8:
case DW_FORM_ref_sig8: case DW_FORM_ref_sig8:
data += 8; inc = 8;
break; break;
case DW_FORM_data16: case DW_FORM_data16:
data += 16; inc = 16;
break; break;
case DW_FORM_string: case DW_FORM_string:
data += strnlen ((char *) data, end - data) + 1; inc = strnlen ((char *) data, end - data) + 1;
break; break;
case DW_FORM_block: case DW_FORM_block:
case DW_FORM_exprloc: case DW_FORM_exprloc:
READ_ULEB (uvalue, data, end); READ_ULEB (uvalue, data, end);
data += uvalue; inc = uvalue;
break; break;
case DW_FORM_block1: case DW_FORM_block1:
SAFE_BYTE_GET (uvalue, data, 1, end); SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
data += 1 + uvalue; inc = uvalue;
break; break;
case DW_FORM_block2: case DW_FORM_block2:
SAFE_BYTE_GET (uvalue, data, 2, end); SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
data += 2 + uvalue; inc = uvalue;
break; break;
case DW_FORM_block4: case DW_FORM_block4:
SAFE_BYTE_GET (uvalue, data, 4, end); SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
data += 4 + uvalue; inc = uvalue;
break; break;
case DW_FORM_indirect: case DW_FORM_indirect:
READ_ULEB (form, data, end); READ_ULEB (form, data, end);
if (form == DW_FORM_implicit_const) if (form == DW_FORM_implicit_const)
SKIP_ULEB (data, end); SKIP_ULEB (data, end);
return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return); return skip_attr_bytes (form, data, end, pointer_size, offset_size,
dwarf_version, value_return);
default: default:
return NULL; return NULL;
} }
* value_return = uvalue; * value_return = uvalue;
if (data > end) if (inc <= (dwarf_vma) (end - data))
data = (unsigned char *) end; data += inc;
else
data = end;
return data; return data;
} }
@ -2159,7 +2163,7 @@ static void
get_type_signedness (abbrev_entry *entry, get_type_signedness (abbrev_entry *entry,
const struct dwarf_section *section, const struct dwarf_section *section,
unsigned char *data, unsigned char *data,
unsigned const char *end, unsigned char *end,
dwarf_vma cu_offset, dwarf_vma cu_offset,
dwarf_vma pointer_size, dwarf_vma pointer_size,
dwarf_vma offset_size, dwarf_vma offset_size,
@ -2578,7 +2582,9 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_string: case DW_FORM_string:
if (!do_loc) if (!do_loc)
printf ("%c%.*s", delimiter, (int) (end - data), data); printf ("%c%.*s", delimiter, (int) (end - data), data);
data += strnlen ((char *) data, end - data) + 1; data += strnlen ((char *) data, end - data);
if (data < end)
data++;
break; break;
case DW_FORM_block: case DW_FORM_block:
@ -4493,7 +4499,9 @@ display_debug_lines_raw (struct dwarf_section * section,
{ {
printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data); printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
data += strnlen ((char *) data, end - data) + 1; data += strnlen ((char *) data, end - data);
if (data < end)
data++;
} }
/* PR 17512: file: 002-132094-0.004. */ /* PR 17512: file: 002-132094-0.004. */
@ -4502,10 +4510,11 @@ display_debug_lines_raw (struct dwarf_section * section,
} }
/* Skip the NUL at the end of the table. */ /* Skip the NUL at the end of the table. */
if (data < end)
data++; data++;
/* Display the contents of the File Name table. */ /* Display the contents of the File Name table. */
if (*data == 0) if (data >= end || *data == 0)
printf (_("\n The File Name Table is empty.\n")); printf (_("\n The File Name Table is empty.\n"));
else else
{ {
@ -4520,7 +4529,9 @@ display_debug_lines_raw (struct dwarf_section * section,
printf (" %d\t", ++state_machine_regs.last_file_entry); printf (" %d\t", ++state_machine_regs.last_file_entry);
name = data; name = data;
data += strnlen ((char *) data, end - data) + 1; data += strnlen ((char *) data, end - data);
if (data < end)
data++;
READ_ULEB (val, data, end); READ_ULEB (val, data, end);
printf ("%s\t", dwarf_vmatoa ("u", val)); printf ("%s\t", dwarf_vmatoa ("u", val));
@ -4539,6 +4550,7 @@ display_debug_lines_raw (struct dwarf_section * section,
} }
/* Skip the NUL at the end of the table. */ /* Skip the NUL at the end of the table. */
if (data < end)
data++; data++;
} }
@ -5039,7 +5051,9 @@ display_debug_lines_decoded (struct dwarf_section * section,
while (data < end && *data != 0) while (data < end && *data != 0)
{ {
data += strnlen ((char *) data, end - data) + 1; data += strnlen ((char *) data, end - data);
if (data < end)
data++;
n_directories++; n_directories++;
} }
@ -5076,7 +5090,9 @@ display_debug_lines_decoded (struct dwarf_section * section,
{ {
/* Skip Name, directory index, last modification /* Skip Name, directory index, last modification
time and length of file. */ time and length of file. */
data += strnlen ((char *) data, end - data) + 1; data += strnlen ((char *) data, end - data);
if (data < end)
data++;
SKIP_ULEB (data, end); SKIP_ULEB (data, end);
SKIP_ULEB (data, end); SKIP_ULEB (data, end);
SKIP_ULEB (data, end); SKIP_ULEB (data, end);
@ -5704,12 +5720,11 @@ display_debug_pubnames_worker (struct dwarf_section *section,
bfd_size_type maxprint; bfd_size_type maxprint;
dwarf_vma offset; dwarf_vma offset;
SAFE_BYTE_GET (offset, data, offset_size, end); SAFE_BYTE_GET_AND_INC (offset, data, offset_size, end);
if (offset == 0) if (offset == 0)
break; break;
data += offset_size;
if (data >= end) if (data >= end)
break; break;
maxprint = (end - data) - 1; maxprint = (end - data) - 1;
@ -5721,8 +5736,7 @@ display_debug_pubnames_worker (struct dwarf_section *section,
const char *kind_name; const char *kind_name;
int is_static; int is_static;
SAFE_BYTE_GET (kind_data, data, 1, end); SAFE_BYTE_GET_AND_INC (kind_data, data, 1, end);
data++;
maxprint --; maxprint --;
/* GCC computes the kind as the upper byte in the CU index /* GCC computes the kind as the upper byte in the CU index
word, and then right shifts it by the CU index size. word, and then right shifts it by the CU index size.
@ -5740,7 +5754,9 @@ display_debug_pubnames_worker (struct dwarf_section *section,
printf (" %-6lx\t%.*s\n", printf (" %-6lx\t%.*s\n",
(unsigned long) offset, (int) maxprint, data); (unsigned long) offset, (int) maxprint, data);
data += strnlen ((char *) data, maxprint) + 1; data += strnlen ((char *) data, maxprint);
if (data < end)
data++;
if (data >= end) if (data >= end)
break; break;
} }
@ -7382,7 +7398,7 @@ display_debug_addr (struct dwarf_section *section,
SAFE_BYTE_GET_AND_INC (length, curr_header, 4, entry); SAFE_BYTE_GET_AND_INC (length, curr_header, 4, entry);
if (length == 0xffffffff) if (length == 0xffffffff)
SAFE_BYTE_GET (length, curr_header, 8, entry); SAFE_BYTE_GET_AND_INC (length, curr_header, 8, entry);
end = curr_header + length; end = curr_header + length;
SAFE_BYTE_GET_AND_INC (version, curr_header, 2, entry); SAFE_BYTE_GET_AND_INC (version, curr_header, 2, entry);
@ -7451,7 +7467,7 @@ display_debug_str_offsets (struct dwarf_section *section,
/* FIXME: We assume that this means 64-bit DWARF is being used. */ /* FIXME: We assume that this means 64-bit DWARF is being used. */
if (length == 0xffffffff) if (length == 0xffffffff)
{ {
SAFE_BYTE_GET (length, curr, 8, end); SAFE_BYTE_GET_AND_INC (length, curr, 8, end);
entry_length = 8; entry_length = 8;
} }
else else
@ -7493,7 +7509,7 @@ display_debug_str_offsets (struct dwarf_section *section,
dwarf_vma offset; dwarf_vma offset;
const unsigned char * string; const unsigned char * string;
if (curr + entry_length > entries_end) if ((dwarf_vma) (entries_end - curr) < entry_length)
/* Not enough space to read one entry_length, give up. */ /* Not enough space to read one entry_length, give up. */
return 0; return 0;