diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c9f46d6d67..96601f671e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,37 @@ +2020-06-03 Stephen Casner + + Copy several years of fixes from bfd/aoutx.h to bfd/pdp11.c. + + * pdp11.c (some_aout_object_p): 4c1534c7a2a - Don't set EXEC_P for + files with relocs. + (aout_get_external_symbols): 6b8f0fd579d - Return if count is zero. + 0301ce1486b PR 22306 - Handle stringsize of zero, and error for any + other size that doesn't qcover the header word. + bf82069dce1 PR 23056 - Allocate an extra byte at the end of the + string table, and zero it. + (translate_symbol_table): 0d329c0a83a PR 22887 - Print an error + message and set bfd_error on finding an invalid name string offset. + (add_to_stringtab): INLINE -> inline + (pdp11_aout_swap_reloc_in): 116acb2c268 PR 22887 - Correct r_index + bound check. + (squirt_out_relocs): e2996cc315d PR 20921 - Check for and report + any relocs that could not be recognised. + 92744f05809 PR 20929 - Check for relocs without an associated symbol. + (find_nearest_line): 808346fcfcf PR 23055 - Check that the symbol + name exists and is long enough, before attempting to see if it is + for a .o file. + c3864421222 - Correct case for N_SO being the last symbol. + 50455f1ab29 PR 20891 - Handle the case where the main file name + and the directory name are both empty. + e82ab856bb4 PR 20892 - Handle the case where function name is empty. + (aout_link_add_symbols): e517df3dbf7 PR 19629 - Check for out of + range string table offsets. + 531336e3a0b PR 20909 - Fix off-by-one error in check for an + illegal string offset. + (aout_link_includes_newfunc): Add comment. + (pdp11_aout_link_input_section): ad756e3f9e6 - Return with an error + on unexpected relocation type rather than ASSERT. + 2020-06-03 H.J. Lu PR ld/26066 diff --git a/bfd/pdp11.c b/bfd/pdp11.c index 375fbedccf..d41aefca2b 100644 --- a/bfd/pdp11.c +++ b/bfd/pdp11.c @@ -623,8 +623,11 @@ NAME (aout, some_aout_object_p) (bfd *abfd, sets the entry point, and that is likely to be non-zero for most systems. */ if (execp->a_entry != 0 - || (execp->a_entry >= obj_textsec(abfd)->vma - && execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->size)) + || (execp->a_entry >= obj_textsec (abfd)->vma + && execp->a_entry < (obj_textsec (abfd)->vma + + obj_textsec (abfd)->size) + && execp->a_trsize == 0 + && execp->a_drsize == 0)) abfd->flags |= EXEC_P; #ifdef STAT_FOR_EXEC else @@ -1241,7 +1244,7 @@ aout_get_external_symbols (bfd *abfd) syms = (struct external_nlist *) _bfd_malloc_and_read (abfd, count * EXTERNAL_NLIST_SIZE, count * EXTERNAL_NLIST_SIZE); - if (syms == NULL && count != 0) + if (syms == NULL) return FALSE; #endif @@ -1255,36 +1258,54 @@ aout_get_external_symbols (bfd *abfd) unsigned char string_chars[BYTES_IN_LONG]; bfd_size_type stringsize; char *strings; + bfd_size_type amt = BYTES_IN_LONG; /* Get the size of the strings. */ if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0 - || (bfd_bread ((void *) string_chars, (bfd_size_type) BYTES_IN_LONG, - abfd) != BYTES_IN_LONG)) + || bfd_bread ((void *) string_chars, amt, abfd) != amt) return FALSE; stringsize = H_GET_32 (abfd, string_chars); - -#ifdef USE_MMAP - if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize, - &obj_aout_string_window (abfd), TRUE)) - return FALSE; - strings = (char *) obj_aout_string_window (abfd).data; -#else - strings = bfd_malloc (stringsize + 1); - if (strings == NULL) - return FALSE; - - /* Skip space for the string count in the buffer for convenience - when using indexes. */ - if (bfd_bread (strings + 4, stringsize - 4, abfd) != stringsize - 4) + if (stringsize == 0) + stringsize = 1; + else if (stringsize < BYTES_IN_LONG + || (size_t) stringsize != stringsize) { - free (strings); + bfd_set_error (bfd_error_bad_value); return FALSE; } + +#ifdef USE_MMAP + if (stringsize >= BYTES_IN_LONG) + { + if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize + 1, + &obj_aout_string_window (abfd), TRUE)) + return FALSE; + strings = (char *) obj_aout_string_window (abfd).data; + } + else #endif + { + strings = (char *) bfd_malloc (stringsize + 1); + if (strings == NULL) + return FALSE; + + if (stringsize >= BYTES_IN_LONG) + { + /* Keep the string count in the buffer for convenience + when indexing with e_strx. */ + amt = stringsize - BYTES_IN_LONG; + if (bfd_bread (strings + BYTES_IN_LONG, amt, abfd) != amt) + { + free (strings); + return FALSE; + } + } + } /* Ensure that a zero index yields an empty string. */ strings[0] = '\0'; - strings[stringsize - 1] = 0; + /* Ensure that the string buffer is NUL terminated. */ + strings[stringsize] = 0; obj_aout_external_strings (abfd) = strings; obj_aout_external_string_size (abfd) = stringsize; @@ -1504,7 +1525,13 @@ NAME (aout, translate_symbol_table) (bfd *abfd, else if (x < strsize) in->symbol.name = str + x; else - return FALSE; + { + _bfd_error_handler + (_("%pB: invalid string offset %" PRIu64 " >= %" PRIu64), + abfd, (uint64_t) x, (uint64_t) strsize); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } in->symbol.value = GET_WORD (abfd, ext->e_value); /* TODO: is 0 a safe value here? */ @@ -1596,7 +1623,7 @@ NAME (aout, slurp_symbol_table) (bfd *abfd) /* Get the index of a string in a strtab, adding it if it is not already present. */ -static INLINE bfd_size_type +static inline bfd_size_type add_to_stringtab (bfd *abfd, struct bfd_strtab_hash *tab, const char *str, @@ -1834,10 +1861,12 @@ pdp11_aout_swap_reloc_in (bfd * abfd, local or global. */ r_extern = (reloc_entry & RTYPE) == REXT; - if (r_extern && r_index > symcount) + if (r_extern && r_index >= symcount) { /* We could arrange to return an error, but it might be useful - to see the file even if it is bad. */ + to see the file even if it is bad. FIXME: Of course this + means that objdump -r *doesn't* see the actual reloc, and + objcopy silently writes a different reloc. */ r_extern = 0; r_index = N_ABS; } @@ -1960,6 +1989,15 @@ NAME (aout, squirt_out_relocs) (bfd *abfd, asection *section) { bfd_byte *r; + if ((*generic)->howto == NULL + || (*generic)->sym_ptr_ptr == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + _bfd_error_handler (_("%pB: attempt to write out " + "unknown reloc type"), abfd); + bfd_release (abfd, native); + return FALSE; + } r = native + (*generic)->address; pdp11_aout_swap_reloc_out (abfd, *generic, r); count--; @@ -2229,7 +2267,7 @@ NAME (aout, find_nearest_line) (bfd *abfd, char *buf; *filename_ptr = bfd_get_filename (abfd); - *functionname_ptr = 0; + *functionname_ptr = NULL; *line_ptr = 0; if (discriminator_ptr) *discriminator_ptr = 0; @@ -2257,7 +2295,10 @@ NAME (aout, find_nearest_line) (bfd *abfd, const char * symname; symname = q->symbol.name; - if (strcmp (symname + strlen (symname) - 2, ".o") == 0) + + if (symname != NULL + && strlen (symname) > 2 + && strcmp (symname + strlen (symname) - 2, ".o") == 0) { if (q->symbol.value > low_line_vma) { @@ -2289,7 +2330,7 @@ NAME (aout, find_nearest_line) (bfd *abfd, /* Look ahead to next symbol to check if that too is an N_SO. */ p++; if (*p == NULL) - break; + goto done; q = (aout_symbol_type *)(*p); if (q->type != (int) N_SO) goto next; @@ -2367,9 +2408,17 @@ NAME (aout, find_nearest_line) (bfd *abfd, *filename_ptr = main_file_name; else { - sprintf (buf, "%s%s", directory_name, main_file_name); - *filename_ptr = buf; - buf += filelen + 1; + if (buf == NULL) + /* PR binutils/20891: In a corrupt input file both + main_file_name and directory_name can be empty... */ + * filename_ptr = NULL; + else + { + snprintf (buf, filelen + 1, "%s%s", directory_name, + main_file_name); + *filename_ptr = buf; + buf += filelen + 1; + } } } @@ -2378,6 +2427,12 @@ NAME (aout, find_nearest_line) (bfd *abfd, const char *function = func->name; char *colon; + if (buf == NULL) + { + /* PR binutils/20892: In a corrupt input file func can be empty. */ + * functionname_ptr = NULL; + return TRUE; + } /* The caller expects a symbol name. We actually have a function name, without the leading underscore. Put the underscore back in, so that the caller gets a symbol name. */ @@ -2808,6 +2863,9 @@ aout_link_add_symbols (bfd *abfd, struct bfd_link_info *info) type = H_GET_8 (abfd, p->e_type); + /* PR 19629: Corrupt binaries can contain illegal string offsets. */ + if (GET_WORD (abfd, p->e_strx) >= obj_aout_external_string_size (abfd)) + return FALSE; name = strings + GET_WORD (abfd, p->e_strx); value = GET_WORD (abfd, p->e_value); flags = BSF_GLOBAL; @@ -2920,6 +2978,9 @@ aout_link_includes_newfunc (struct bfd_hash_entry *entry, return (struct bfd_hash_entry *) ret; } +/* Write out a symbol that was not associated with an a.out input + object. */ + static bfd_boolean aout_link_write_other_symbol (struct bfd_hash_entry *bh, void *data) { @@ -3304,8 +3365,15 @@ pdp11_aout_link_input_section (struct aout_final_link_info *flaginfo, r_extern = (r_type == REXT); howto_idx = r_pcrel; - BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_pdp11)); - howto = howto_table_pdp11 + howto_idx; + if (howto_idx < TABLE_SIZE (howto_table_pdp11)) + howto = howto_table_pdp11 + howto_idx; + else + { + _bfd_error_handler (_("%pB: unsupported relocation type"), + input_bfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } if (relocatable)