More fixes for memory access violations triggered by fuzzed binaries.
PR binutils/17512 * objdump.c (display_any_bfd): Avoid infinite loop closing and opening the same archive again and again. * archive64.c (bfd_elf64_archive_slurp_armap): Add range checks. * libbfd.c (safe_read_leb128): New function. * libbfd-in.h (safe_read_leb128): Add prototype. * libbfd.h: Regenerate. * elf-attrs.c (_bfd_elf_parse_attributes): Use safe_read_leb128. Check for an over-long subsection length. * elf.c (elf_parse_notes): Check that the namedata is long enough for the string comparison that is about to be performed. (elf_read_notes): Zero-terminate the note buffer.
This commit is contained in:
parent
137d1369ac
commit
f64e188b58
|
@ -1,3 +1,16 @@
|
||||||
|
2014-12-09 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
PR binutils/17512
|
||||||
|
* archive64.c (bfd_elf64_archive_slurp_armap): Add range checks.
|
||||||
|
* libbfd.c (safe_read_leb128): New function.
|
||||||
|
* libbfd-in.h (safe_read_leb128): Add prototype.
|
||||||
|
* libbfd.h: Regenerate.
|
||||||
|
* elf-attrs.c (_bfd_elf_parse_attributes): Use safe_read_leb128.
|
||||||
|
Check for an over-long subsection length.
|
||||||
|
* elf.c (elf_parse_notes): Check that the namedata is long enough
|
||||||
|
for the string comparison that is about to be performed.
|
||||||
|
(elf_read_notes): Zero-terminate the note buffer.
|
||||||
|
|
||||||
2014-12-09 Alan Modra <amodra@gmail.com>
|
2014-12-09 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* elf64-ppc.c (sort_r_offset): Delete.
|
* elf64-ppc.c (sort_r_offset): Delete.
|
||||||
|
|
|
@ -46,6 +46,7 @@ bfd_elf64_archive_slurp_armap (bfd *abfd)
|
||||||
struct areltdata *mapdata;
|
struct areltdata *mapdata;
|
||||||
bfd_byte int_buf[8];
|
bfd_byte int_buf[8];
|
||||||
char *stringbase;
|
char *stringbase;
|
||||||
|
char *stringend;
|
||||||
bfd_byte *raw_armap = NULL;
|
bfd_byte *raw_armap = NULL;
|
||||||
carsym *carsyms;
|
carsym *carsyms;
|
||||||
bfd_size_type amt;
|
bfd_size_type amt;
|
||||||
|
@ -92,11 +93,18 @@ bfd_elf64_archive_slurp_armap (bfd *abfd)
|
||||||
ptrsize = 8 * nsymz;
|
ptrsize = 8 * nsymz;
|
||||||
|
|
||||||
amt = carsym_size + stringsize + 1;
|
amt = carsym_size + stringsize + 1;
|
||||||
|
if (carsym_size < nsymz || ptrsize < nsymz || amt < nsymz)
|
||||||
|
{
|
||||||
|
bfd_set_error (bfd_error_malformed_archive);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt);
|
ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt);
|
||||||
if (ardata->symdefs == NULL)
|
if (ardata->symdefs == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
carsyms = ardata->symdefs;
|
carsyms = ardata->symdefs;
|
||||||
stringbase = ((char *) ardata->symdefs) + carsym_size;
|
stringbase = ((char *) ardata->symdefs) + carsym_size;
|
||||||
|
stringbase[stringsize] = 0;
|
||||||
|
stringend = stringbase + stringsize;
|
||||||
|
|
||||||
raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize);
|
raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize);
|
||||||
if (raw_armap == NULL)
|
if (raw_armap == NULL)
|
||||||
|
@ -114,6 +122,7 @@ bfd_elf64_archive_slurp_armap (bfd *abfd)
|
||||||
{
|
{
|
||||||
carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
|
carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
|
||||||
carsyms->name = stringbase;
|
carsyms->name = stringbase;
|
||||||
|
if (stringbase < stringend)
|
||||||
stringbase += strlen (stringbase) + 1;
|
stringbase += strlen (stringbase) + 1;
|
||||||
++carsyms;
|
++carsyms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
|
||||||
bfd_vma subsection_len;
|
bfd_vma subsection_len;
|
||||||
bfd_byte *end;
|
bfd_byte *end;
|
||||||
|
|
||||||
tag = read_unsigned_leb128 (abfd, p, &n);
|
tag = safe_read_leb128 (abfd, p, &n, FALSE, p_end);
|
||||||
p += n;
|
p += n;
|
||||||
if (p < p_end - 4)
|
if (p < p_end - 4)
|
||||||
subsection_len = bfd_get_32 (abfd, p);
|
subsection_len = bfd_get_32 (abfd, p);
|
||||||
|
@ -506,6 +506,9 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
|
||||||
section_len -= subsection_len;
|
section_len -= subsection_len;
|
||||||
subsection_len -= n + 4;
|
subsection_len -= n + 4;
|
||||||
end = p + subsection_len;
|
end = p + subsection_len;
|
||||||
|
/* PR 17512: file: 0e8c0c90. */
|
||||||
|
if (end > p_end)
|
||||||
|
end = p_end;
|
||||||
switch (tag)
|
switch (tag)
|
||||||
{
|
{
|
||||||
case Tag_File:
|
case Tag_File:
|
||||||
|
@ -513,13 +516,13 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
tag = read_unsigned_leb128 (abfd, p, &n);
|
tag = safe_read_leb128 (abfd, p, &n, FALSE, end);
|
||||||
p += n;
|
p += n;
|
||||||
type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
|
type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
|
||||||
switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
|
switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL))
|
||||||
{
|
{
|
||||||
case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
|
case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL:
|
||||||
val = read_unsigned_leb128 (abfd, p, &n);
|
val = safe_read_leb128 (abfd, p, &n, FALSE, end);
|
||||||
p += n;
|
p += n;
|
||||||
bfd_elf_add_obj_attr_int_string (abfd, vendor, tag,
|
bfd_elf_add_obj_attr_int_string (abfd, vendor, tag,
|
||||||
val, (char *) p);
|
val, (char *) p);
|
||||||
|
@ -531,7 +534,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
|
||||||
p += strlen ((char *)p) + 1;
|
p += strlen ((char *)p) + 1;
|
||||||
break;
|
break;
|
||||||
case ATTR_TYPE_FLAG_INT_VAL:
|
case ATTR_TYPE_FLAG_INT_VAL:
|
||||||
val = read_unsigned_leb128 (abfd, p, &n);
|
val = safe_read_leb128 (abfd, p, &n, FALSE, end);
|
||||||
p += n;
|
p += n;
|
||||||
bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
|
bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
|
||||||
break;
|
break;
|
||||||
|
|
45
bfd/elf.c
45
bfd/elf.c
|
@ -9817,32 +9817,33 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
case bfd_core:
|
case bfd_core:
|
||||||
if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
|
|
||||||
{
|
{
|
||||||
if (! elfcore_grok_netbsd_note (abfd, &in))
|
struct
|
||||||
return FALSE;
|
{
|
||||||
|
const char * string;
|
||||||
|
bfd_boolean (* func)(bfd *, Elf_Internal_Note *);
|
||||||
}
|
}
|
||||||
else if (CONST_STRNEQ (in.namedata, "OpenBSD"))
|
grokers[] =
|
||||||
{
|
{
|
||||||
if (! elfcore_grok_openbsd_note (abfd, &in))
|
{ "", elfcore_grok_note },
|
||||||
return FALSE;
|
{ "NetBSD-CORE", elfcore_grok_netbsd_note },
|
||||||
}
|
{ "OpenBSD", elfcore_grok_openbsd_note },
|
||||||
else if (CONST_STRNEQ (in.namedata, "QNX"))
|
{ "QNX", elfcore_grok_nto_note },
|
||||||
|
{ "SPU/", elfcore_grok_spu_note }
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = ARRAY_SIZE (grokers); i--;)
|
||||||
|
if (in.namesz >= sizeof grokers[i].string - 1
|
||||||
|
&& strncmp (in.namedata, grokers[i].string,
|
||||||
|
sizeof (grokers[i].string) - 1) == 0)
|
||||||
{
|
{
|
||||||
if (! elfcore_grok_nto_note (abfd, &in))
|
if (! grokers[i].func (abfd, & in))
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else if (CONST_STRNEQ (in.namedata, "SPU/"))
|
|
||||||
{
|
|
||||||
if (! elfcore_grok_spu_note (abfd, &in))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (! elfcore_grok_note (abfd, &in))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case bfd_object:
|
case bfd_object:
|
||||||
if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
|
if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
|
||||||
|
@ -9876,10 +9877,14 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
|
||||||
if (bfd_seek (abfd, offset, SEEK_SET) != 0)
|
if (bfd_seek (abfd, offset, SEEK_SET) != 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
buf = (char *) bfd_malloc (size);
|
buf = (char *) bfd_malloc (size + 1);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* PR 17512: file: ec08f814
|
||||||
|
0-termintate the buffer so that string searches will not overflow. */
|
||||||
|
buf[size] = 0;
|
||||||
|
|
||||||
if (bfd_bread (buf, size, abfd) != size
|
if (bfd_bread (buf, size, abfd) != size
|
||||||
|| !elf_parse_notes (abfd, buf, size, offset))
|
|| !elf_parse_notes (abfd, buf, size, offset))
|
||||||
{
|
{
|
||||||
|
|
|
@ -839,3 +839,5 @@ extern void bfd_section_already_linked_table_traverse
|
||||||
|
|
||||||
extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *);
|
extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *);
|
||||||
extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *);
|
extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *);
|
||||||
|
extern bfd_vma safe_read_leb128 (bfd *, bfd_byte *, unsigned int *,
|
||||||
|
bfd_boolean, const bfd_byte * const);
|
||||||
|
|
39
bfd/libbfd.c
39
bfd/libbfd.c
|
@ -1003,6 +1003,45 @@ read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read in a LEB128 encoded value from ABFD starting at DATA.
|
||||||
|
If SIGN is true, return a signed LEB128 value.
|
||||||
|
If LENGTH_RETURN is not NULL, return in it the number of bytes read.
|
||||||
|
No bytes will be read at address END or beyond. */
|
||||||
|
|
||||||
|
bfd_vma
|
||||||
|
safe_read_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
|
bfd_byte *data,
|
||||||
|
unsigned int *length_return,
|
||||||
|
bfd_boolean sign,
|
||||||
|
const bfd_byte * const end)
|
||||||
|
{
|
||||||
|
bfd_vma result = 0;
|
||||||
|
unsigned int num_read = 0;
|
||||||
|
unsigned int shift = 0;
|
||||||
|
unsigned char byte = 0;
|
||||||
|
|
||||||
|
while (data < end)
|
||||||
|
{
|
||||||
|
byte = bfd_get_8 (abfd, data);
|
||||||
|
data++;
|
||||||
|
num_read++;
|
||||||
|
|
||||||
|
result |= ((bfd_vma) (byte & 0x7f)) << shift;
|
||||||
|
|
||||||
|
shift += 7;
|
||||||
|
if ((byte & 0x80) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length_return != NULL)
|
||||||
|
*length_return = num_read;
|
||||||
|
|
||||||
|
if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
|
||||||
|
result |= (bfd_vma) -1 << shift;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper function for reading sleb128 encoded data. */
|
/* Helper function for reading sleb128 encoded data. */
|
||||||
|
|
||||||
bfd_signed_vma
|
bfd_signed_vma
|
||||||
|
|
|
@ -844,6 +844,8 @@ extern void bfd_section_already_linked_table_traverse
|
||||||
|
|
||||||
extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *);
|
extern bfd_vma read_unsigned_leb128 (bfd *, bfd_byte *, unsigned int *);
|
||||||
extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *);
|
extern bfd_signed_vma read_signed_leb128 (bfd *, bfd_byte *, unsigned int *);
|
||||||
|
extern bfd_vma safe_read_leb128 (bfd *, bfd_byte *, unsigned int *,
|
||||||
|
bfd_boolean, const bfd_byte * const);
|
||||||
/* Extracted from init.c. */
|
/* Extracted from init.c. */
|
||||||
/* Extracted from libbfd.c. */
|
/* Extracted from libbfd.c. */
|
||||||
bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int);
|
bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2014-12-09 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
PR binutils/17512
|
||||||
|
* objdump.c (display_any_bfd): Avoid infinite loop closing and
|
||||||
|
opening the same archive again and again.
|
||||||
|
|
||||||
2014-12-09 Chen Gang <gang.chen.5i5j@gmail.com>
|
2014-12-09 Chen Gang <gang.chen.5i5j@gmail.com>
|
||||||
|
|
||||||
* windres.c (open_file_search): Free path buffer on failure.
|
* windres.c (open_file_search): Free path buffer on failure.
|
||||||
|
|
|
@ -3426,7 +3426,15 @@ display_any_bfd (bfd *file, int level)
|
||||||
display_any_bfd (arfile, level + 1);
|
display_any_bfd (arfile, level + 1);
|
||||||
|
|
||||||
if (last_arfile != NULL)
|
if (last_arfile != NULL)
|
||||||
|
{
|
||||||
bfd_close (last_arfile);
|
bfd_close (last_arfile);
|
||||||
|
/* PR 17512: file: ac585d01. */
|
||||||
|
if (arfile == last_arfile)
|
||||||
|
{
|
||||||
|
last_arfile = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
last_arfile = arfile;
|
last_arfile = arfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue