diff options
-rw-r--r-- | src/ChangeLog | 13 | ||||
-rw-r--r-- | src/strip.c | 268 |
2 files changed, 204 insertions, 77 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 55bd4ccf..02f65842 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2015-05-12 Mark Wielaard <mjw@redhat.com> + + * strip.c (debug_fd): New static variable. + (tmp_debug_fname): Likewise. + (cleanup_debug): New function using the above to clean up temporary + debug file. + (INTERNAL_ERROR): Call cleanup_debug. + (handle_elf): Use debug_fd and tmp_debug_fname statics and call + cleanup_debug before any error. Use output_fname instead of fname in + error messages when it exists (-o was given). SHT_NOBITS sections + can also be moved freely even if SHF_ALLOC is set. Add various + sanity checks. Use elf_assert instead of plain assert. + 2015-05-08 Mark Wielaard <mjw@redhat.com> * nm.c (show_symbols): Call gelf_fsize with EV_CURRENT. diff --git a/src/strip.c b/src/strip.c index 365b18dd..d63b6a82 100644 --- a/src/strip.c +++ b/src/strip.c @@ -115,9 +115,18 @@ static int handle_elf (int fd, Elf *elf, const char *prefix, static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, struct timespec tvp[2]); +static int debug_fd = -1; +static char *tmp_debug_fname = NULL; + +/* Close debug file descriptor, if opened. And remove temporary debug file. */ +static void cleanup_debug (); + #define INTERNAL_ERROR(fname) \ - error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"), \ - fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)) + do { \ + cleanup_debug (); \ + error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"), \ + fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)); \ + } while (0) /* Name of the output file. */ @@ -395,7 +404,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, char *fullname = alloca (prefix_len + 1 + fname_len); char *cp = fullname; Elf *debugelf = NULL; - char *tmp_debug_fname = NULL; + tmp_debug_fname = NULL; int result = 0; size_t shdridx = 0; size_t shstrndx; @@ -449,7 +458,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } } - int debug_fd = -1; + debug_fd = -1; /* Get the EBL handling. Removing all debugging symbols with the -g option or resolving all relocations between debug sections with @@ -474,7 +483,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, the debug file if the file would not contain any information. */ size_t debug_fname_len = strlen (debug_fname); - tmp_debug_fname = (char *) alloca (debug_fname_len + sizeof (".XXXXXX")); + tmp_debug_fname = (char *) xmalloc (debug_fname_len + sizeof (".XXXXXX")); strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len), ".XXXXXX"); @@ -495,13 +504,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Get the section header string table index. */ if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0)) - error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + } /* Get the number of phdrs in the old file. */ size_t phnum; if (elf_getphdrnum (elf, &phnum) != 0) - error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs")); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs")); + } /* We now create a new ELF descriptor for the same file. We construct it almost exactly in the same way with some information @@ -517,7 +532,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, && unlikely (gelf_newphdr (newelf, phnum) == 0))) { error (0, 0, gettext ("cannot create new file '%s': %s"), - output_fname, elf_errmsg (-1)); + output_fname ?: fname, elf_errmsg (-1)); goto fail; } @@ -619,9 +634,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, goto illformed; /* Sections in files other than relocatable object files which - are not loaded can be freely moved by us. In relocatable - object files everything can be moved. */ + don't contain any file content or are not loaded can be freely + moved by us. In relocatable object files everything can be moved. */ if (ehdr->e_type == ET_REL + || shdr_info[cnt].shdr.sh_type == SHT_NOBITS || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) shdr_info[cnt].shdr.sh_offset = 0; @@ -637,7 +653,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Cross-reference the sections contained in the section group. */ shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); - if (shdr_info[cnt].data == NULL) + if (shdr_info[cnt].data == NULL + || shdr_info[cnt].data->d_size < sizeof (Elf32_Word)) INTERNAL_ERROR (fname); /* XXX Fix for unaligned access. */ @@ -708,7 +725,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, while (idx != 0) { /* The section group data is already loaded. */ - assert (shdr_info[idx].data != NULL); + elf_assert (shdr_info[idx].data != NULL + && shdr_info[idx].data->d_buf != NULL + && shdr_info[idx].data->d_size >= sizeof (Elf32_Word)); /* If the references section group is a normal section group and has one element remaining, or if it is an @@ -764,11 +783,16 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, for (size_t in = 1; in < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); ++in) - if (shdr_info[grpref[in]].idx != 0) + if (grpref[in] < shnum) { - shdr_info[cnt].idx = 1; - break; + if (shdr_info[grpref[in]].idx != 0) + { + shdr_info[cnt].idx = 1; + break; + } } + else + goto illformed; } } @@ -897,7 +921,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, inline void check_preserved (size_t i) { - if (i != 0 && shdr_info[i].idx != 0 + if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 && shdr_info[i].debug_data == NULL) { if (shdr_info[i].data == NULL) @@ -926,9 +950,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { scn = elf_newscn (debugelf); if (scn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while generating output file: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("while generating output file: %s"), + elf_errmsg (-1)); + } bool discard_section = (shdr_info[cnt].idx > 0 && shdr_info[cnt].debug_data == NULL @@ -968,6 +995,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { /* Copy the original data before it gets modified. */ shdr_info[cnt].debug_data = debugdata; + if (debugdata->d_buf == NULL) + INTERNAL_ERROR (fname); debugdata->d_buf = memcpy (xmalloc (debugdata->d_size), debugdata->d_buf, debugdata->d_size); } @@ -1003,8 +1032,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* We need a string table for the section headers. */ shst = ebl_strtabinit (true); if (shst == NULL) - error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"), - output_fname ?: fname); + { + cleanup_debug (); + error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"), + output_fname ?: fname); + } /* Assign new section numbers. */ shdr_info[0].idx = 0; @@ -1016,8 +1048,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Create a new section. */ shdr_info[cnt].newscn = elf_newscn (newelf); if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("while generating output file: %s"), + elf_errmsg (-1)); + } elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); @@ -1053,15 +1089,21 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Create the section. */ shdr_info[cnt].newscn = elf_newscn (newelf); if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header section: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + } elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn); if (shdr_info[cnt].data == NULL) - error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), + elf_errmsg (-1)); + } char *debug_basename = basename (debug_fname_embed ?: debug_fname); off_t crc_offset = strlen (debug_basename) + 1; @@ -1110,18 +1152,24 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Create the section. */ shdr_info[cnt].newscn = elf_newscn (newelf); if (shdr_info[cnt].newscn == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header section: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("while create section header section: %s"), + elf_errmsg (-1)); + } elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == idx); /* Finalize the string table and fill in the correct indices in the section headers. */ shstrtab_data = elf_newdata (shdr_info[cnt].newscn); if (shstrtab_data == NULL) - error (EXIT_FAILURE, 0, - gettext ("while create section header string table: %s"), - elf_errmsg (-1)); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, + gettext ("while create section header string table: %s"), + elf_errmsg (-1)); + } ebl_strtabfinalize (shst, shstrtab_data); /* We have to set the section size. */ @@ -1135,7 +1183,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, Elf_Data *newdata; scn = elf_getscn (newelf, shdr_info[cnt].idx); - assert (scn != NULL); + elf_assert (scn != NULL); /* Update the name. */ shdr_info[cnt].shdr.sh_name = ebl_strtaboffset (shdr_info[cnt].se); @@ -1148,13 +1196,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) { - assert (shdr_info[cnt].data != NULL); + elf_assert (shdr_info[cnt].data != NULL + && shdr_info[cnt].data->d_buf != NULL); Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; for (size_t inner = 0; inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); ++inner) - grpref[inner] = shdr_info[grpref[inner]].idx; + if (grpref[inner] < shnum) + grpref[inner] = shdr_info[grpref[inner]].idx; + else + goto illformed; } /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag. */ @@ -1196,14 +1248,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[cnt].symtab_idx != 0) { - assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX); + elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX); /* This section has extended section information. We have to modify that information, too. */ shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn, NULL); elf_assert ((versiondata->d_size / sizeof (Elf32_Word)) - >= shdr_info[cnt].data->d_size / elsize); + >= shdr_info[cnt].data->d_size / elsize); } if (shdr_info[cnt].version_idx != 0) @@ -1215,8 +1267,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn, NULL); - elf_assert ((versiondata->d_size / sizeof (GElf_Versym)) - >= shdr_info[cnt].data->d_size / elsize); + elf_assert (versiondata != NULL + && versiondata->d_buf != NULL + && ((versiondata->d_size / sizeof (GElf_Versym)) + >= shdr_info[cnt].data->d_size / elsize)); } shdr_info[cnt].newsymidx @@ -1270,7 +1324,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, sec = shdr_info[sym->st_shndx].idx; else { - elf_assert (shndxdata != NULL); + elf_assert (shndxdata != NULL + && shndxdata->d_buf != NULL); sec = shdr_info[xshndx].idx; } @@ -1379,6 +1434,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* libelf will use d_size to set sh_size. */ Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, cnt), NULL); + if (debugdata == NULL) + INTERNAL_ERROR (fname); debugdata->d_size = newdata->d_size; } } @@ -1390,6 +1447,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, continue; const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; + elf_assert (symtabidx < shnum + 2); const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx; switch (shdr_info[cnt].shdr.sh_type) { @@ -1416,10 +1474,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, : elf_getscn (newelf, shdr_info[cnt].idx), NULL); - assert (d != NULL); + elf_assert (d != NULL && d->d_buf != NULL + && shdr_info[cnt].shdr.sh_entsize != 0); size_t nrels = (shdr_info[cnt].shdr.sh_size / shdr_info[cnt].shdr.sh_entsize); + size_t symsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT); + const Elf32_Word symidxn = (shdr_info[symtabidx].data->d_size + / symsize); if (shdr_info[cnt].shdr.sh_type == SHT_REL) for (size_t relidx = 0; relidx < nrels; ++relidx) { @@ -1428,6 +1490,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, INTERNAL_ERROR (fname); size_t symidx = GELF_R_SYM (rel_mem.r_info); + elf_assert (symidx < symidxn); if (newsymidx[symidx] != symidx) { rel_mem.r_info @@ -1446,6 +1509,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, INTERNAL_ERROR (fname); size_t symidx = GELF_R_SYM (rel_mem.r_info); + elf_assert (symidx < symidxn); if (newsymidx[symidx] != symidx) { rel_mem.r_info @@ -1464,7 +1528,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* We have to recompute the hash table. */ - assert (shdr_info[cnt].idx > 0); + elf_assert (shdr_info[cnt].idx > 0); /* The hash section in the new file. */ scn = elf_getscn (newelf, shdr_info[cnt].idx); @@ -1473,30 +1537,38 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, Elf_Data *symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx), NULL); - assert (symd != NULL); + elf_assert (symd != NULL && symd->d_buf != NULL); /* The hash table data. */ Elf_Data *hashd = elf_getdata (scn, NULL); - assert (hashd != NULL); + elf_assert (hashd != NULL && hashd->d_buf != NULL); if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word)) { /* Sane arches first. */ + elf_assert (hashd->d_size >= 2 * sizeof (Elf32_Word)); Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf; size_t strshndx = shdr_info[symtabidx].old_sh_link; size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT); + Elf32_Word nchain = bucket[1]; + Elf32_Word nbucket = bucket[0]; + uint64_t used_buf = ((2ULL + nchain + nbucket) + * sizeof (Elf32_Word)); + elf_assert (used_buf <= hashd->d_size); + /* Adjust the nchain value. The symbol table size changed. We keep the same size for the bucket array. */ bucket[1] = symd->d_size / elsize; - Elf32_Word nbucket = bucket[0]; bucket += 2; Elf32_Word *chain = bucket + nbucket; /* New size of the section. */ - hashd->d_size = ((2 + symd->d_size / elsize + nbucket) + size_t n_size = ((2 + symd->d_size / elsize + nbucket) * sizeof (Elf32_Word)); + elf_assert (n_size <= hashd->d_size); + hashd->d_size = n_size; update_section_size (hashd); /* Clear the arrays. */ @@ -1513,7 +1585,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *name = elf_strptr (elf, strshndx, sym->st_name); - elf_assert (name != NULL); + elf_assert (name != NULL && nbucket != 0); size_t hidx = elf_hash (name) % nbucket; if (bucket[hidx] == 0) @@ -1522,7 +1594,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { hidx = bucket[hidx]; - while (chain[hidx] != 0) + while (chain[hidx] != 0 && chain[hidx] < nchain) hidx = chain[hidx]; chain[hidx] = inner; @@ -1540,16 +1612,25 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, size_t strshndx = shdr_info[symtabidx].old_sh_link; size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT); + elf_assert (symd->d_size >= 2 * sizeof (Elf64_Xword)); + Elf64_Xword nbucket = bucket[0]; + Elf64_Xword nchain = bucket[1]; + uint64_t maxwords = hashd->d_size / sizeof (Elf64_Xword); + elf_assert (maxwords >= 2 + && maxwords - 2 >= nbucket + && maxwords - 2 - nbucket >= nchain); + /* Adjust the nchain value. The symbol table size changed. We keep the same size for the bucket array. */ bucket[1] = symd->d_size / elsize; - Elf64_Xword nbucket = bucket[0]; bucket += 2; Elf64_Xword *chain = bucket + nbucket; /* New size of the section. */ - hashd->d_size = ((2 + symd->d_size / elsize + nbucket) + size_t n_size = ((2 + symd->d_size / elsize + nbucket) * sizeof (Elf64_Xword)); + elf_assert (n_size <= hashd->d_size); + hashd->d_size = n_size; update_section_size (hashd); /* Clear the arrays. */ @@ -1566,7 +1647,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *name = elf_strptr (elf, strshndx, sym->st_name); - elf_assert (name != NULL); + elf_assert (name != NULL && nbucket != 0); size_t hidx = elf_hash (name) % nbucket; if (bucket[hidx] == 0) @@ -1575,7 +1656,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { hidx = bucket[hidx]; - while (chain[hidx] != 0) + while (chain[hidx] != 0 && chain[hidx] < nchain) hidx = chain[hidx]; chain[hidx] = inner; @@ -1589,7 +1670,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (no_symtab_updates ()) break; - assert (shdr_info[cnt].idx > 0); + elf_assert (shdr_info[cnt].idx > 0); /* The symbol version section in the new file. */ scn = elf_getscn (newelf, shdr_info[cnt].idx); @@ -1597,19 +1678,22 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* The symbol table data. */ symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx), NULL); - assert (symd != NULL); + elf_assert (symd != NULL && symd->d_buf != NULL); + size_t symz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT); + const Elf32_Word syms = (shdr_info[symtabidx].data->d_size / symz); /* The version symbol data. */ Elf_Data *verd = elf_getdata (scn, NULL); - assert (verd != NULL); + elf_assert (verd != NULL && verd->d_buf != NULL); /* The symbol version array. */ GElf_Half *verstab = (GElf_Half *) verd->d_buf; /* Walk through the list and */ size_t elsize = gelf_fsize (elf, verd->d_type, 1, EV_CURRENT); - for (size_t inner = 1; inner < verd->d_size / elsize; ++inner) - if (newsymidx[inner] != 0) + Elf32_Word vers = verd->d_size / elsize; + for (size_t inner = 1; inner < vers && inner < syms; ++inner) + if (newsymidx[inner] != 0 && newsymidx[inner] < vers) /* Overwriting the same array works since the reordering can only move entries to lower indices in the array. */ @@ -1633,8 +1717,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, scn = elf_getscn (newelf, shdr_info[cnt].idx); GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - assert (shdr != NULL); + elf_assert (shdr != NULL); + size_t symsz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT); + const Elf32_Word symn = (shdr_info[symtabidx].data->d_size + / symsz); + elf_assert (shdr->sh_info < symn); shdr->sh_info = newsymidx[shdr->sh_info]; (void) gelf_update_shdr (scn, shdr); @@ -1678,18 +1766,23 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* OK, lets relocate all trivial cross debug section relocations. */ Elf_Data *reldata = elf_getdata (scn, NULL); + if (reldata == NULL || reldata->d_buf == NULL) + INTERNAL_ERROR (fname); /* We actually wanted the rawdata, but since we already accessed it earlier as elf_getdata () that won't work. But debug sections are all ELF_T_BYTE, so it doesn't really matter. */ Elf_Data *tdata = elf_getdata (tscn, NULL); - if (tdata->d_type != ELF_T_BYTE) + if (tdata == NULL || tdata->d_buf == NULL + || tdata->d_type != ELF_T_BYTE) INTERNAL_ERROR (fname); /* Pick up the symbol table and shndx table to resolve relocation symbol indexes. */ Elf64_Word symt = shdr->sh_link; Elf_Data *symdata, *xndxdata; + elf_assert (symt < shnum + 2); + elf_assert (shdr_info[symt].symtab_idx < shnum + 2); symdata = (shdr_info[symt].debug_data ?: shdr_info[symt].data); xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data @@ -1722,6 +1815,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, &xndx); Elf32_Word sec = (sym->st_shndx == SHN_XINDEX ? xndx : sym->st_shndx); + if (sec >= shnum + 2) + INTERNAL_ERROR (fname); + if (ebl_debugscn_p (ebl, shdr_info[sec].name)) { size_t size; @@ -1745,7 +1841,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (offset > tdata->d_size || tdata->d_size - offset < size) - error (0, 0, gettext ("bad relocation")); + { + cleanup_debug (); + error (EXIT_FAILURE, 0, gettext ("bad relocation")); + } /* When the symbol value is zero then for SHT_REL sections this is all that needs to be checked. @@ -1817,6 +1916,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, return false; } + if (shdr->sh_entsize == 0) + INTERNAL_ERROR (fname); + size_t nrels = shdr->sh_size / shdr->sh_entsize; size_t next = 0; if (shdr->sh_type == SHT_REL) @@ -1863,7 +1965,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (unlikely (elf_update (debugelf, ELF_C_WRITE) == -1)) { error (0, 0, gettext ("while writing '%s': %s"), - debug_fname, elf_errmsg (-1)); + tmp_debug_fname, elf_errmsg (-1)); result = 1; goto fail_close; } @@ -1879,6 +1981,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } /* The temporary file does not exist anymore. */ + free (tmp_debug_fname); tmp_debug_fname = NULL; if (!remove_shdrs) @@ -1951,7 +2054,8 @@ while computing checksum for debug information")); if (gelf_update_ehdr (newelf, newehdr) == 0) { error (0, 0, gettext ("%s: error while creating ELF header: %s"), - fname, elf_errmsg (-1)); + output_fname ?: fname, elf_errmsg (-1)); + cleanup_debug (); return 1; } @@ -1960,6 +2064,7 @@ while computing checksum for debug information")); { error (0, 0, gettext ("%s: error while reading the file: %s"), fname, elf_errmsg (-1)); + cleanup_debug (); return 1; } @@ -1973,7 +2078,7 @@ while computing checksum for debug information")); if (elf_update (newelf, ELF_C_WRITE) == -1) { error (0, 0, gettext ("while writing '%s': %s"), - fname, elf_errmsg (-1)); + output_fname ?: fname, elf_errmsg (-1)); result = 1; } @@ -1998,7 +2103,7 @@ while computing checksum for debug information")); || ftruncate64 (fd, shdr_info[shdridx].shdr.sh_offset) < 0) { error (0, errno, gettext ("while writing '%s'"), - fname); + output_fname ?: fname); result = 1; } } @@ -2018,7 +2123,7 @@ while computing checksum for debug information")); || ftruncate64 (fd, shdr_info[shdridx].shdr.sh_offset) < 0) { error (0, errno, gettext ("while writing '%s'"), - fname); + output_fname ?: fname); result = 1; } } @@ -2054,8 +2159,8 @@ while computing checksum for debug information")); /* That was it. Close the descriptors. */ if (elf_end (newelf) != 0) { - error (0, 0, gettext ("error while finishing '%s': %s"), fname, - elf_errmsg (-1)); + error (0, 0, gettext ("error while finishing '%s': %s"), + output_fname ?: fname, elf_errmsg (-1)); result = 1; } @@ -2071,13 +2176,7 @@ while computing checksum for debug information")); if (ebl != NULL) ebl_closebackend (ebl); - /* Close debug file descriptor, if opened */ - if (debug_fd >= 0) - { - if (tmp_debug_fname != NULL) - unlink (tmp_debug_fname); - close (debug_fd); - } + cleanup_debug (); /* If requested, preserve the timestamp. */ if (tvp != NULL) @@ -2098,6 +2197,21 @@ cannot set access and modification date of '%s'"), return result; } +static void +cleanup_debug () +{ + if (debug_fd >= 0) + { + if (tmp_debug_fname != NULL) + { + unlink (tmp_debug_fname); + free (tmp_debug_fname); + tmp_debug_fname = NULL; + } + close (debug_fd); + debug_fd = -1; + } +} static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, |