mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 01:50:24 +08:00
SAFE_BYTE_GET
This rearranges SAFE_BYTE_GET* macros, eliminating some duplication, and making sure that the _INC variants never increment their PTR arg past END. I've added an assertion that should show us places where we use them improperly with user derived PTR args, which I'm sure the fuzzers will find for us. * dwarf.c (SAFE_BYTE_GET_INTERNAL): Define. (SAFE_BYTE_GET, SAFE_BYTE_GET_AND_INC): Define using the above. (SAFE_SIGNED_BYTE_GET, SAFE_SIGNED_BYTE_GET_AND_INC): Likewise. (display_discr_list): Use SAFE_BYTE_GET_AND_INC rather than SAFE_BYTE_GET followed by increment. (process_debug_info): Likewise, and test bytes remaining before incrementing section_begin rather than using pointer comparison. (display_debug_names): Pass lvalue as SAFE_BYTE_GET PTR. (process_cu_tu_index): Likewise for SAFE_BYTE_GET_AND_INC.
This commit is contained in:
@ -1,3 +1,15 @@
|
|||||||
|
2021-05-12 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* dwarf.c (SAFE_BYTE_GET_INTERNAL): Define.
|
||||||
|
(SAFE_BYTE_GET, SAFE_BYTE_GET_AND_INC): Define using the above.
|
||||||
|
(SAFE_SIGNED_BYTE_GET, SAFE_SIGNED_BYTE_GET_AND_INC): Likewise.
|
||||||
|
(display_discr_list): Use SAFE_BYTE_GET_AND_INC rather than
|
||||||
|
SAFE_BYTE_GET followed by increment.
|
||||||
|
(process_debug_info): Likewise, and test bytes remaining before
|
||||||
|
incrementing section_begin rather than using pointer comparison.
|
||||||
|
(display_debug_names): Pass lvalue as SAFE_BYTE_GET PTR.
|
||||||
|
(process_cu_tu_index): Likewise for SAFE_BYTE_GET_AND_INC.
|
||||||
|
|
||||||
2021-05-12 Alan Modra <amodra@gmail.com>
|
2021-05-12 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* dwarf.c (dwarf_vmatoa64, SAFE_BYTE_GET64, add64): Delete.
|
* dwarf.c (dwarf_vmatoa64, SAFE_BYTE_GET64, add64): Delete.
|
||||||
|
143
binutils/dwarf.c
143
binutils/dwarf.c
@ -368,73 +368,52 @@ read_leb128 (unsigned char *data,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read AMOUNT bytes from PTR and store them in VAL as an unsigned value.
|
/* Read AMOUNT bytes from PTR and store them in VAL.
|
||||||
Checks to make sure that the read will not reach or pass END
|
Checks to make sure that the read will not reach or pass END.
|
||||||
and that VAL is big enough to hold AMOUNT bytes. */
|
FUNC chooses whether the value read is unsigned or signed, and may
|
||||||
#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \
|
be either byte_get or byte_get_signed. If INC is true, PTR is
|
||||||
do \
|
incremented after reading the value.
|
||||||
{ \
|
This macro cannot protect against PTR values derived from user input.
|
||||||
unsigned int amount = (AMOUNT); \
|
The C standard sections 6.5.6 and 6.5.8 say attempts to do so using
|
||||||
if (sizeof (VAL) < amount) \
|
pointers is undefined behaviour. */
|
||||||
{ \
|
#define SAFE_BYTE_GET_INTERNAL(VAL, PTR, AMOUNT, END, FUNC, INC) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
size_t amount = (AMOUNT); \
|
||||||
|
if (sizeof (VAL) < amount) \
|
||||||
|
{ \
|
||||||
error (ngettext ("internal error: attempt to read %d byte " \
|
error (ngettext ("internal error: attempt to read %d byte " \
|
||||||
"of data in to %d sized variable", \
|
"of data in to %d sized variable", \
|
||||||
"internal error: attempt to read %d bytes " \
|
"internal error: attempt to read %d bytes " \
|
||||||
"of data in to %d sized variable", \
|
"of data in to %d sized variable", \
|
||||||
amount), \
|
amount), \
|
||||||
amount, (int) sizeof (VAL)); \
|
(int) amount, (int) sizeof (VAL)); \
|
||||||
amount = sizeof (VAL); \
|
amount = sizeof (VAL); \
|
||||||
} \
|
} \
|
||||||
if ((PTR) >= (END) - amount) \
|
assert ((PTR) <= (END)); \
|
||||||
{ \
|
size_t avail = (END) - (PTR); \
|
||||||
if ((PTR) < (END)) \
|
if (amount > avail) \
|
||||||
amount = (END) - (PTR); \
|
amount = avail; \
|
||||||
else \
|
if (amount == 0) \
|
||||||
amount = 0; \
|
(VAL) = 0; \
|
||||||
} \
|
else \
|
||||||
if (amount == 0 || amount > 8) \
|
(VAL) = (FUNC) ((PTR), amount); \
|
||||||
VAL = 0; \
|
if (INC) \
|
||||||
else \
|
(PTR) += amount; \
|
||||||
VAL = byte_get ((PTR), amount); \
|
} \
|
||||||
} \
|
|
||||||
while (0)
|
while (0)
|
||||||
|
|
||||||
/* Like SAFE_BYTE_GET, but also increments PTR by AMOUNT. */
|
#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \
|
||||||
|
SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get, false)
|
||||||
|
|
||||||
#define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \
|
#define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \
|
||||||
do \
|
SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get, true)
|
||||||
{ \
|
|
||||||
SAFE_BYTE_GET (VAL, PTR, AMOUNT, END); \
|
|
||||||
PTR += AMOUNT; \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
/* Like SAFE_BYTE_GET, but reads a signed value. */
|
|
||||||
#define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END) \
|
#define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END) \
|
||||||
do \
|
SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get_signed, false)
|
||||||
{ \
|
|
||||||
unsigned int amount = (AMOUNT); \
|
|
||||||
if ((PTR) >= (END) - amount) \
|
|
||||||
{ \
|
|
||||||
if ((PTR) < (END)) \
|
|
||||||
amount = (END) - (PTR); \
|
|
||||||
else \
|
|
||||||
amount = 0; \
|
|
||||||
} \
|
|
||||||
if (amount) \
|
|
||||||
VAL = byte_get_signed ((PTR), amount); \
|
|
||||||
else \
|
|
||||||
VAL = 0; \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
/* Like SAFE_SIGNED_BYTE_GET, but also increments PTR by AMOUNT. */
|
|
||||||
#define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \
|
#define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \
|
||||||
do \
|
SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get_signed, true)
|
||||||
{ \
|
|
||||||
SAFE_SIGNED_BYTE_GET (VAL, PTR, AMOUNT, END); \
|
|
||||||
PTR += AMOUNT; \
|
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
typedef struct State_Machine_Registers
|
typedef struct State_Machine_Registers
|
||||||
{
|
{
|
||||||
@ -2336,9 +2315,8 @@ display_discr_list (unsigned long form,
|
|||||||
unsigned char discriminant;
|
unsigned char discriminant;
|
||||||
unsigned int bytes_read;
|
unsigned int bytes_read;
|
||||||
|
|
||||||
SAFE_BYTE_GET (discriminant, data, 1, end);
|
SAFE_BYTE_GET_AND_INC (discriminant, data, 1, end);
|
||||||
-- uvalue;
|
-- uvalue;
|
||||||
data ++;
|
|
||||||
|
|
||||||
assert (uvalue > 0);
|
assert (uvalue > 0);
|
||||||
switch (discriminant)
|
switch (discriminant)
|
||||||
@ -3455,31 +3433,27 @@ process_debug_info (struct dwarf_section * section,
|
|||||||
/* Read the first 4 bytes. For a 32-bit DWARF section, this
|
/* Read the first 4 bytes. For a 32-bit DWARF section, this
|
||||||
will be the length. For a 64-bit DWARF section, it'll be
|
will be the length. For a 64-bit DWARF section, it'll be
|
||||||
the escape code 0xffffffff followed by an 8 byte length. */
|
the escape code 0xffffffff followed by an 8 byte length. */
|
||||||
SAFE_BYTE_GET (length, section_begin, 4, end);
|
SAFE_BYTE_GET_AND_INC (length, section_begin, 4, end);
|
||||||
|
|
||||||
if (length == 0xffffffff)
|
if (length == 0xffffffff)
|
||||||
{
|
SAFE_BYTE_GET_AND_INC (length, section_begin, 8, end);
|
||||||
SAFE_BYTE_GET (length, section_begin + 4, 8, end);
|
|
||||||
section_begin += length + 12;
|
|
||||||
}
|
|
||||||
else if (length >= 0xfffffff0 && length < 0xffffffff)
|
else if (length >= 0xfffffff0 && length < 0xffffffff)
|
||||||
{
|
{
|
||||||
warn (_("Reserved length value (0x%s) found in section %s\n"),
|
warn (_("Reserved length value (0x%s) found in section %s\n"),
|
||||||
dwarf_vmatoa ("x", length), section->name);
|
dwarf_vmatoa ("x", length), section->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
section_begin += length + 4;
|
|
||||||
|
|
||||||
/* Negative values are illegal, they may even cause infinite
|
/* Negative values are illegal, they may even cause infinite
|
||||||
looping. This can happen if we can't accurately apply
|
looping. This can happen if we can't accurately apply
|
||||||
relocations to an object file, or if the file is corrupt. */
|
relocations to an object file, or if the file is corrupt. */
|
||||||
if ((signed long) length <= 0 || section_begin < start)
|
if (length > (size_t) (end - section_begin))
|
||||||
{
|
{
|
||||||
warn (_("Corrupt unit length (0x%s) found in section %s\n"),
|
warn (_("Corrupt unit length (0x%s) found in section %s\n"),
|
||||||
dwarf_vmatoa ("x", length), section->name);
|
dwarf_vmatoa ("x", length), section->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
section_begin += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_units == 0)
|
if (num_units == 0)
|
||||||
@ -9829,13 +9803,12 @@ display_debug_names (struct dwarf_section *section, void *file)
|
|||||||
for (namei = 0; namei < name_count; ++namei)
|
for (namei = 0; namei < name_count; ++namei)
|
||||||
{
|
{
|
||||||
uint64_t string_offset, entry_offset;
|
uint64_t string_offset, entry_offset;
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
SAFE_BYTE_GET (string_offset,
|
p = name_table_string_offsets + namei * offset_size;
|
||||||
name_table_string_offsets + namei * offset_size,
|
SAFE_BYTE_GET (string_offset, p, offset_size, unit_end);
|
||||||
offset_size, unit_end);
|
p = name_table_entry_offsets + namei * offset_size;
|
||||||
SAFE_BYTE_GET (entry_offset,
|
SAFE_BYTE_GET (entry_offset, p, offset_size, unit_end);
|
||||||
name_table_entry_offsets + namei * offset_size,
|
|
||||||
offset_size, unit_end);
|
|
||||||
|
|
||||||
printf ("[%3u] #%08x %s:", namei, hash_table_hashes[namei],
|
printf ("[%3u] #%08x %s:", namei, hash_table_hashes[namei],
|
||||||
fetch_indirect_string (string_offset));
|
fetch_indirect_string (string_offset));
|
||||||
@ -10333,13 +10306,13 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_BYTE_GET (version, phdr, 4, limit);
|
phash = phdr;
|
||||||
|
SAFE_BYTE_GET_AND_INC (version, phash, 4, limit);
|
||||||
if (version >= 2)
|
if (version >= 2)
|
||||||
SAFE_BYTE_GET (ncols, phdr + 4, 4, limit);
|
SAFE_BYTE_GET_AND_INC (ncols, phash, 4, limit);
|
||||||
SAFE_BYTE_GET (nused, phdr + 8, 4, limit);
|
SAFE_BYTE_GET_AND_INC (nused, phash, 4, limit);
|
||||||
SAFE_BYTE_GET (nslots, phdr + 12, 4, limit);
|
SAFE_BYTE_GET_AND_INC (nslots, phash, 4, limit);
|
||||||
|
|
||||||
phash = phdr + 16;
|
|
||||||
pindex = phash + (size_t) nslots * 8;
|
pindex = phash + (size_t) nslots * 8;
|
||||||
ppool = pindex + (size_t) nslots * 4;
|
ppool = pindex + (size_t) nslots * 4;
|
||||||
|
|
||||||
@ -10474,7 +10447,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
|
|||||||
{
|
{
|
||||||
for (j = 0; j < ncols; j++)
|
for (j = 0; j < ncols; j++)
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
|
unsigned char *p = ppool + j * 4;
|
||||||
|
SAFE_BYTE_GET (dw_sect, p, 4, limit);
|
||||||
printf (" %8s", get_DW_SECT_short_name (dw_sect));
|
printf (" %8s", get_DW_SECT_short_name (dw_sect));
|
||||||
}
|
}
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
@ -10523,12 +10497,14 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
|
|||||||
i, dwarf_vmatoa ("x", signature));
|
i, dwarf_vmatoa ("x", signature));
|
||||||
for (j = 0; j < ncols; j++)
|
for (j = 0; j < ncols; j++)
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (val, prow + j * 4, 4, limit);
|
unsigned char *p = prow + j * 4;
|
||||||
|
SAFE_BYTE_GET (val, p, 4, limit);
|
||||||
if (do_display)
|
if (do_display)
|
||||||
printf (" %8d", val);
|
printf (" %8d", val);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
|
p = ppool + j * 4;
|
||||||
|
SAFE_BYTE_GET (dw_sect, p, 4, limit);
|
||||||
|
|
||||||
/* PR 17531: file: 10796eb3. */
|
/* PR 17531: file: 10796eb3. */
|
||||||
if (dw_sect >= DW_SECT_MAX)
|
if (dw_sect >= DW_SECT_MAX)
|
||||||
@ -10557,7 +10533,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
|
|||||||
|
|
||||||
for (j = 0; j < ncols; j++)
|
for (j = 0; j < ncols; j++)
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (val, ppool + j * 4, 4, limit);
|
unsigned char *p = ppool + j * 4;
|
||||||
|
SAFE_BYTE_GET (val, p, 4, limit);
|
||||||
if (do_display)
|
if (do_display)
|
||||||
printf (" %8s", get_DW_SECT_short_name (val));
|
printf (" %8s", get_DW_SECT_short_name (val));
|
||||||
}
|
}
|
||||||
@ -10580,12 +10557,14 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
|
|||||||
|
|
||||||
for (j = 0; j < ncols; j++)
|
for (j = 0; j < ncols; j++)
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (val, prow + j * 4, 4, limit);
|
unsigned char *p = prow + j * 4;
|
||||||
|
SAFE_BYTE_GET (val, p, 4, limit);
|
||||||
if (do_display)
|
if (do_display)
|
||||||
printf (" %8d", val);
|
printf (" %8d", val);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
|
p = ppool + j * 4;
|
||||||
|
SAFE_BYTE_GET (dw_sect, p, 4, limit);
|
||||||
if (dw_sect >= DW_SECT_MAX)
|
if (dw_sect >= DW_SECT_MAX)
|
||||||
warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
|
warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user