get_line_filename_and_dirname

* dwarf.c (get_line_filename_and_dirname): Delete initial_length_size.
	Simplify length sanity check, and check for too small lengths.
	Constrain data reads to header length.  Avoid pointer UB.
This commit is contained in:
Alan Modra
2021-05-15 15:06:28 +09:30
parent c03df92247
commit 46d1214d88
2 changed files with 28 additions and 15 deletions

View File

@ -1,3 +1,9 @@
2021-05-15 Alan Modra <amodra@gmail.com>
* dwarf.c (get_line_filename_and_dirname): Delete initial_length_size.
Simplify length sanity check, and check for too small lengths.
Constrain data reads to header length. Avoid pointer UB.
2021-05-15 Alan Modra <amodra@gmail.com> 2021-05-15 Alan Modra <amodra@gmail.com>
* dwarf.c (display_debug_macinfo): Print strings that might not * dwarf.c (display_debug_macinfo): Print strings that might not

View File

@ -5827,7 +5827,7 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
{ {
struct dwarf_section *section = &debug_displays [line].section; struct dwarf_section *section = &debug_displays [line].section;
unsigned char *hdrptr, *dirtable, *file_name; unsigned char *hdrptr, *dirtable, *file_name;
unsigned int offset_size, initial_length_size; unsigned int offset_size;
unsigned int version, opcode_base; unsigned int version, opcode_base;
dwarf_vma length, diridx; dwarf_vma length, diridx;
const unsigned char * end; const unsigned char * end;
@ -5847,16 +5847,14 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
/* This section is 64-bit DWARF 3. */ /* This section is 64-bit DWARF 3. */
SAFE_BYTE_GET_AND_INC (length, hdrptr, 8, end); SAFE_BYTE_GET_AND_INC (length, hdrptr, 8, end);
offset_size = 8; offset_size = 8;
initial_length_size = 12;
} }
else else
{ offset_size = 4;
offset_size = 4;
initial_length_size = 4; if (length > (size_t) (end - hdrptr)
} || length < 2 + offset_size + 1 + 3 + 1)
if (length + initial_length_size < length
|| length + initial_length_size > section->size)
return NULL; return NULL;
end = hdrptr + length;
SAFE_BYTE_GET_AND_INC (version, hdrptr, 2, end); SAFE_BYTE_GET_AND_INC (version, hdrptr, 2, end);
if (version != 2 && version != 3 && version != 4) if (version != 2 && version != 3 && version != 4)
@ -5867,18 +5865,19 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
hdrptr += 3; /* Skip default_is_stmt, line_base, line_range. */ hdrptr += 3; /* Skip default_is_stmt, line_base, line_range. */
SAFE_BYTE_GET_AND_INC (opcode_base, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (opcode_base, hdrptr, 1, end);
if (opcode_base == 0) if (opcode_base == 0
|| opcode_base - 1 >= (size_t) (end - hdrptr))
return NULL; return NULL;
hdrptr += opcode_base - 1; hdrptr += opcode_base - 1;
if (hdrptr >= end)
return NULL;
dirtable = hdrptr; dirtable = hdrptr;
/* Skip over dirname table. */ /* Skip over dirname table. */
while (*hdrptr != '\0') while (*hdrptr != '\0')
{ {
hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
if (hdrptr < end)
hdrptr++;
if (hdrptr >= end) if (hdrptr >= end)
return NULL; return NULL;
} }
@ -5887,7 +5886,9 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
/* Now skip over preceding filename table entries. */ /* Now skip over preceding filename table entries. */
for (; hdrptr < end && *hdrptr != '\0' && fileidx > 1; fileidx--) for (; hdrptr < end && *hdrptr != '\0' && fileidx > 1; fileidx--)
{ {
hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
if (hdrptr < end)
hdrptr++;
SKIP_ULEB (hdrptr, end); SKIP_ULEB (hdrptr, end);
SKIP_ULEB (hdrptr, end); SKIP_ULEB (hdrptr, end);
SKIP_ULEB (hdrptr, end); SKIP_ULEB (hdrptr, end);
@ -5896,14 +5897,20 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
return NULL; return NULL;
file_name = hdrptr; file_name = hdrptr;
hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
if (hdrptr < end)
hdrptr++;
if (hdrptr >= end) if (hdrptr >= end)
return NULL; return NULL;
READ_ULEB (diridx, hdrptr, end); READ_ULEB (diridx, hdrptr, end);
if (diridx == 0) if (diridx == 0)
return file_name; return file_name;
for (; dirtable < end && *dirtable != '\0' && diridx > 1; diridx--) for (; dirtable < end && *dirtable != '\0' && diridx > 1; diridx--)
dirtable += strnlen ((char *) dirtable, end - dirtable) + 1; {
dirtable += strnlen ((char *) dirtable, end - dirtable);
if (dirtable < end)
dirtable++;
}
if (dirtable >= end || *dirtable == '\0') if (dirtable >= end || *dirtable == '\0')
return NULL; return NULL;
*dir_name = dirtable; *dir_name = dirtable;