mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-12-17 16:18:37 +08:00
USE_MMAP fuzzed object file attacks
If mmap is used without sanity checking, then we'll get a SIGBUS if an access is done to the mmap'd memory corresponding to a page past end of file. * aoutx.h (aout_get_external_symbols): Check that mmap regions are within file contents. Catch stringsize overflow. (some_aout_object_p): Don't clear already zeroed fields. Tidy. * pdp11.c: As for aoutx.h. Copy some fixes too.
This commit is contained in:
65
bfd/aoutx.h
65
bfd/aoutx.h
@@ -498,9 +498,9 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
{
|
{
|
||||||
struct aout_data_struct *rawptr, *oldrawptr;
|
struct aout_data_struct *rawptr, *oldrawptr;
|
||||||
bfd_cleanup result;
|
bfd_cleanup result;
|
||||||
size_t amt = sizeof (* rawptr);
|
size_t amt = sizeof (*rawptr);
|
||||||
|
|
||||||
rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, amt);
|
rawptr = bfd_zalloc (abfd, amt);
|
||||||
if (rawptr == NULL)
|
if (rawptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -551,7 +551,6 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
|
|
||||||
abfd->start_address = execp->a_entry;
|
abfd->start_address = execp->a_entry;
|
||||||
|
|
||||||
obj_aout_symbols (abfd) = NULL;
|
|
||||||
abfd->symcount = execp->a_syms / sizeof (struct external_nlist);
|
abfd->symcount = execp->a_syms / sizeof (struct external_nlist);
|
||||||
|
|
||||||
/* The default relocation entry size is that of traditional V7 Unix. */
|
/* The default relocation entry size is that of traditional V7 Unix. */
|
||||||
@@ -564,9 +563,6 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
bfd_init_window (&obj_aout_sym_window (abfd));
|
bfd_init_window (&obj_aout_sym_window (abfd));
|
||||||
bfd_init_window (&obj_aout_string_window (abfd));
|
bfd_init_window (&obj_aout_string_window (abfd));
|
||||||
#endif
|
#endif
|
||||||
obj_aout_external_syms (abfd) = NULL;
|
|
||||||
obj_aout_external_strings (abfd) = NULL;
|
|
||||||
obj_aout_sym_hashes (abfd) = NULL;
|
|
||||||
|
|
||||||
if (! NAME (aout, make_sections) (abfd))
|
if (! NAME (aout, make_sections) (abfd))
|
||||||
goto error_ret;
|
goto error_ret;
|
||||||
@@ -594,7 +590,6 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
/* Call back to the format-dependent code to fill in the rest of the
|
/* Call back to the format-dependent code to fill in the rest of the
|
||||||
fields and do any further cleanup. Things that should be filled
|
fields and do any further cleanup. Things that should be filled
|
||||||
in by the callback: */
|
in by the callback: */
|
||||||
|
|
||||||
struct exec *execp = exec_hdr (abfd);
|
struct exec *execp = exec_hdr (abfd);
|
||||||
|
|
||||||
obj_textsec (abfd)->size = N_TXTSIZE (execp);
|
obj_textsec (abfd)->size = N_TXTSIZE (execp);
|
||||||
@@ -618,18 +613,13 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
obj_sym_filepos (abfd) = N_SYMOFF (execp);
|
obj_sym_filepos (abfd) = N_SYMOFF (execp);
|
||||||
|
|
||||||
/* Determine the architecture and machine type of the object file. */
|
/* Determine the architecture and machine type of the object file. */
|
||||||
switch (N_MACHTYPE (exec_hdr (abfd)))
|
abfd->obj_arch = bfd_arch_obscure;
|
||||||
{
|
|
||||||
default:
|
|
||||||
abfd->obj_arch = bfd_arch_obscure;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
adata (abfd)->page_size = TARGET_PAGE_SIZE;
|
adata (abfd)->page_size = TARGET_PAGE_SIZE;
|
||||||
adata (abfd)->segment_size = SEGMENT_SIZE;
|
adata (abfd)->segment_size = SEGMENT_SIZE;
|
||||||
adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
|
adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
|
||||||
|
|
||||||
return _bfd_no_cleanup
|
return _bfd_no_cleanup;
|
||||||
|
|
||||||
/* The architecture is encoded in various ways in various a.out variants,
|
/* The architecture is encoded in various ways in various a.out variants,
|
||||||
or is not encoded at all in some of them. The relocation size depends
|
or is not encoded at all in some of them. The relocation size depends
|
||||||
@@ -639,7 +629,7 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
|
|
||||||
Formats such as b.out, which have additional fields in the a.out
|
Formats such as b.out, which have additional fields in the a.out
|
||||||
header, should cope with them in this callback as well. */
|
header, should cope with them in this callback as well. */
|
||||||
#endif /* DOCUMENTATION */
|
#endif /* DOCUMENTATION */
|
||||||
|
|
||||||
result = (*callback_to_real_object_p) (abfd);
|
result = (*callback_to_real_object_p) (abfd);
|
||||||
|
|
||||||
@@ -1311,30 +1301,41 @@ NAME (aout, set_section_contents) (bfd *abfd,
|
|||||||
static bool
|
static bool
|
||||||
aout_get_external_symbols (bfd *abfd)
|
aout_get_external_symbols (bfd *abfd)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_MMAP
|
||||||
|
ufile_ptr filesize = bfd_get_file_size (abfd);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (obj_aout_external_syms (abfd) == NULL)
|
if (obj_aout_external_syms (abfd) == NULL)
|
||||||
{
|
{
|
||||||
bfd_size_type count;
|
bfd_size_type count;
|
||||||
struct external_nlist *syms;
|
struct external_nlist *syms = NULL;
|
||||||
bfd_size_type amt = exec_hdr (abfd)->a_syms;
|
bfd_size_type amt = exec_hdr (abfd)->a_syms;
|
||||||
|
|
||||||
count = amt / EXTERNAL_NLIST_SIZE;
|
count = amt / EXTERNAL_NLIST_SIZE;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return true; /* Nothing to do. */
|
return true;
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd), amt,
|
if (filesize >= (ufile_ptr) obj_sym_filepos (abfd)
|
||||||
&obj_aout_sym_window (abfd), true))
|
&& filesize - obj_sym_filepos (abfd) >= amt)
|
||||||
return false;
|
{
|
||||||
syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
|
if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd), amt,
|
||||||
|
&obj_aout_sym_window (abfd), true))
|
||||||
|
return false;
|
||||||
|
syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
|
||||||
|
}
|
||||||
|
else
|
||||||
#else
|
#else
|
||||||
/* We allocate using malloc to make the values easy to free
|
{
|
||||||
later on. If we put them on the objalloc it might not be
|
/* We allocate using malloc to make the values easy to free
|
||||||
possible to free them. */
|
later on. If we put them on the objalloc it might not be
|
||||||
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
|
possible to free them. */
|
||||||
return false;
|
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
|
||||||
syms = (struct external_nlist *) _bfd_malloc_and_read (abfd, amt, amt);
|
return false;
|
||||||
if (syms == NULL)
|
syms = (struct external_nlist *) _bfd_malloc_and_read (abfd, amt, amt);
|
||||||
return false;
|
if (syms == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_aout_external_syms (abfd) = syms;
|
obj_aout_external_syms (abfd) = syms;
|
||||||
@@ -1356,7 +1357,7 @@ aout_get_external_symbols (bfd *abfd)
|
|||||||
stringsize = GET_WORD (abfd, string_chars);
|
stringsize = GET_WORD (abfd, string_chars);
|
||||||
if (stringsize == 0)
|
if (stringsize == 0)
|
||||||
stringsize = 1;
|
stringsize = 1;
|
||||||
else if (stringsize < BYTES_IN_WORD
|
else if (stringsize + 1 < BYTES_IN_WORD + 1
|
||||||
|| (size_t) stringsize != stringsize)
|
|| (size_t) stringsize != stringsize)
|
||||||
{
|
{
|
||||||
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
||||||
@@ -1364,7 +1365,9 @@ aout_get_external_symbols (bfd *abfd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
if (stringsize >= BYTES_IN_WORD)
|
if (stringsize >= BYTES_IN_WORD
|
||||||
|
&& filesize >= (ufile_ptr) obj_str_filepos (abfd)
|
||||||
|
&& filesize - obj_str_filepos (abfd) >= stringsize + 1)
|
||||||
{
|
{
|
||||||
if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize + 1,
|
if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize + 1,
|
||||||
&obj_aout_string_window (abfd), true))
|
&obj_aout_string_window (abfd), true))
|
||||||
|
|||||||
96
bfd/pdp11.c
96
bfd/pdp11.c
@@ -534,12 +534,12 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
bfd_cleanup (*callback_to_real_object_p) (bfd *))
|
bfd_cleanup (*callback_to_real_object_p) (bfd *))
|
||||||
{
|
{
|
||||||
struct aout_data_struct *rawptr, *oldrawptr;
|
struct aout_data_struct *rawptr, *oldrawptr;
|
||||||
bfd_cleanup cleanup;
|
bfd_cleanup result;
|
||||||
size_t amt = sizeof (struct aout_data_struct);
|
size_t amt = sizeof (*rawptr);
|
||||||
|
|
||||||
rawptr = bfd_zalloc (abfd, amt);
|
rawptr = bfd_zalloc (abfd, amt);
|
||||||
if (rawptr == NULL)
|
if (rawptr == NULL)
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
oldrawptr = abfd->tdata.aout_data;
|
oldrawptr = abfd->tdata.aout_data;
|
||||||
abfd->tdata.aout_data = rawptr;
|
abfd->tdata.aout_data = rawptr;
|
||||||
@@ -549,7 +549,8 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
*abfd->tdata.aout_data = *oldrawptr;
|
*abfd->tdata.aout_data = *oldrawptr;
|
||||||
|
|
||||||
abfd->tdata.aout_data->a.hdr = &rawptr->e;
|
abfd->tdata.aout_data->a.hdr = &rawptr->e;
|
||||||
*(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct. */
|
/* Copy in the internal_exec struct. */
|
||||||
|
*(abfd->tdata.aout_data->a.hdr) = *execp;
|
||||||
execp = abfd->tdata.aout_data->a.hdr;
|
execp = abfd->tdata.aout_data->a.hdr;
|
||||||
|
|
||||||
/* Set the file flags. */
|
/* Set the file flags. */
|
||||||
@@ -585,7 +586,6 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
|
|
||||||
abfd->start_address = execp->a_entry;
|
abfd->start_address = execp->a_entry;
|
||||||
|
|
||||||
obj_aout_symbols (abfd) = NULL;
|
|
||||||
abfd->symcount = execp->a_syms / sizeof (struct external_nlist);
|
abfd->symcount = execp->a_syms / sizeof (struct external_nlist);
|
||||||
|
|
||||||
/* The default relocation entry size is that of traditional V7 Unix. */
|
/* The default relocation entry size is that of traditional V7 Unix. */
|
||||||
@@ -599,12 +599,8 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
bfd_init_window (&obj_aout_string_window (abfd));
|
bfd_init_window (&obj_aout_string_window (abfd));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_aout_external_syms (abfd) = NULL;
|
|
||||||
obj_aout_external_strings (abfd) = NULL;
|
|
||||||
obj_aout_sym_hashes (abfd) = NULL;
|
|
||||||
|
|
||||||
if (! NAME (aout, make_sections) (abfd))
|
if (! NAME (aout, make_sections) (abfd))
|
||||||
return NULL;
|
goto error_ret;
|
||||||
|
|
||||||
obj_datasec (abfd)->size = execp->a_data;
|
obj_datasec (abfd)->size = execp->a_data;
|
||||||
obj_bsssec (abfd)->size = execp->a_bss;
|
obj_bsssec (abfd)->size = execp->a_bss;
|
||||||
@@ -654,9 +650,9 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
/* Determine the architecture and machine type of the object file. */
|
/* Determine the architecture and machine type of the object file. */
|
||||||
abfd->obj_arch = bfd_arch_obscure;
|
abfd->obj_arch = bfd_arch_obscure;
|
||||||
|
|
||||||
adata(abfd)->page_size = TARGET_PAGE_SIZE;
|
adata (abfd)->page_size = TARGET_PAGE_SIZE;
|
||||||
adata(abfd)->segment_size = SEGMENT_SIZE;
|
adata (abfd)->segment_size = SEGMENT_SIZE;
|
||||||
adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
|
adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
|
||||||
|
|
||||||
return _bfd_no_cleanup;
|
return _bfd_no_cleanup;
|
||||||
|
|
||||||
@@ -670,7 +666,7 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
header, should cope with them in this callback as well. */
|
header, should cope with them in this callback as well. */
|
||||||
#endif /* DOCUMENTATION */
|
#endif /* DOCUMENTATION */
|
||||||
|
|
||||||
cleanup = (*callback_to_real_object_p)(abfd);
|
result = (*callback_to_real_object_p) (abfd);
|
||||||
|
|
||||||
/* Now that the segment addresses have been worked out, take a better
|
/* Now that the segment addresses have been worked out, take a better
|
||||||
guess at whether the file is executable. If the entry point
|
guess at whether the file is executable. If the entry point
|
||||||
@@ -685,7 +681,7 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
|
|
||||||
To fix this, we now accept any non-zero entry point as an indication of
|
To fix this, we now accept any non-zero entry point as an indication of
|
||||||
executability. This will work most of the time, since only the linker
|
executability. This will work most of the time, since only the linker
|
||||||
sets the entry point, and that is likely to be non-zero for most systems. */
|
sets the entry point, and that is likely to be non-zero for most systems. */
|
||||||
|
|
||||||
if (execp->a_entry != 0
|
if (execp->a_entry != 0
|
||||||
|| (execp->a_entry >= obj_textsec (abfd)->vma
|
|| (execp->a_entry >= obj_textsec (abfd)->vma
|
||||||
@@ -708,18 +704,19 @@ NAME (aout, some_aout_object_p) (bfd *abfd,
|
|||||||
issue. Many kernels are loaded at non standard addresses. */
|
issue. Many kernels are loaded at non standard addresses. */
|
||||||
if (abfd->iostream != NULL
|
if (abfd->iostream != NULL
|
||||||
&& (abfd->flags & BFD_IN_MEMORY) == 0
|
&& (abfd->flags & BFD_IN_MEMORY) == 0
|
||||||
&& (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
|
&& (fstat (fileno ((FILE *) (abfd->iostream)), &stat_buf) == 0)
|
||||||
&& ((stat_buf.st_mode & 0111) != 0))
|
&& ((stat_buf.st_mode & 0111) != 0))
|
||||||
abfd->flags |= EXEC_P;
|
abfd->flags |= EXEC_P;
|
||||||
}
|
}
|
||||||
#endif /* STAT_FOR_EXEC */
|
#endif /* STAT_FOR_EXEC */
|
||||||
|
|
||||||
if (!cleanup)
|
if (result)
|
||||||
{
|
return result;
|
||||||
free (rawptr);
|
|
||||||
abfd->tdata.aout_data = oldrawptr;
|
error_ret:
|
||||||
}
|
bfd_release (abfd, rawptr);
|
||||||
return cleanup;
|
abfd->tdata.aout_data = oldrawptr;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize ABFD for use with a.out files. */
|
/* Initialize ABFD for use with a.out files. */
|
||||||
@@ -1279,38 +1276,43 @@ NAME (aout, set_section_contents) (bfd *abfd,
|
|||||||
static bool
|
static bool
|
||||||
aout_get_external_symbols (bfd *abfd)
|
aout_get_external_symbols (bfd *abfd)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_MMAP
|
||||||
|
ufile_ptr filesize = bfd_get_file_size (abfd);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (obj_aout_external_syms (abfd) == NULL)
|
if (obj_aout_external_syms (abfd) == NULL)
|
||||||
{
|
{
|
||||||
bfd_size_type count;
|
bfd_size_type count;
|
||||||
struct external_nlist *syms;
|
struct external_nlist *syms = NULL;
|
||||||
|
bfd_size_type amt = exec_hdr (abfd)->a_syms;
|
||||||
|
|
||||||
count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
|
count = amt / EXTERNAL_NLIST_SIZE;
|
||||||
|
|
||||||
/* PR 17512: file: 011f5a08. */
|
/* PR 17512: file: 011f5a08. */
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
return true;
|
||||||
obj_aout_external_syms (abfd) = NULL;
|
|
||||||
obj_aout_external_sym_count (abfd) = count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd),
|
if (filesize >= (ufile_ptr) obj_sym_filepos (abfd)
|
||||||
exec_hdr (abfd)->a_syms,
|
&& filesize - obj_sym_filepos (abfd) >= amt)
|
||||||
&obj_aout_sym_window (abfd), true))
|
{
|
||||||
return false;
|
if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd), amt,
|
||||||
syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
|
&obj_aout_sym_window (abfd), true))
|
||||||
|
return false;
|
||||||
|
syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
|
||||||
|
}
|
||||||
|
else
|
||||||
#else
|
#else
|
||||||
/* We allocate using malloc to make the values easy to free
|
{
|
||||||
later on. If we put them on the objalloc it might not be
|
/* We allocate using malloc to make the values easy to free
|
||||||
possible to free them. */
|
later on. If we put them on the objalloc it might not be
|
||||||
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
|
possible to free them. */
|
||||||
return false;
|
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
|
||||||
syms = (struct external_nlist *)
|
return false;
|
||||||
_bfd_malloc_and_read (abfd, count * EXTERNAL_NLIST_SIZE,
|
syms = (struct external_nlist *) _bfd_malloc_and_read (abfd, amt, amt);
|
||||||
count * EXTERNAL_NLIST_SIZE);
|
if (syms == NULL)
|
||||||
if (syms == NULL)
|
return false;
|
||||||
return false;
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_aout_external_syms (abfd) = syms;
|
obj_aout_external_syms (abfd) = syms;
|
||||||
@@ -1332,7 +1334,7 @@ aout_get_external_symbols (bfd *abfd)
|
|||||||
stringsize = H_GET_32 (abfd, string_chars);
|
stringsize = H_GET_32 (abfd, string_chars);
|
||||||
if (stringsize == 0)
|
if (stringsize == 0)
|
||||||
stringsize = 1;
|
stringsize = 1;
|
||||||
else if (stringsize < BYTES_IN_LONG
|
else if (stringsize + 1 < BYTES_IN_LONG + 1
|
||||||
|| (size_t) stringsize != stringsize)
|
|| (size_t) stringsize != stringsize)
|
||||||
{
|
{
|
||||||
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
||||||
@@ -1340,7 +1342,9 @@ aout_get_external_symbols (bfd *abfd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
if (stringsize >= BYTES_IN_LONG)
|
if (stringsize >= BYTES_IN_LONG
|
||||||
|
&& filesize >= (ufile_ptr) obj_str_filepos (abfd)
|
||||||
|
&& filesize - obj_str_filepos (abfd) >= stringsize + 1)
|
||||||
{
|
{
|
||||||
if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize + 1,
|
if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize + 1,
|
||||||
&obj_aout_string_window (abfd), true))
|
&obj_aout_string_window (abfd), true))
|
||||||
|
|||||||
Reference in New Issue
Block a user