summaryrefslogtreecommitdiff
path: root/src/strip.c
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-05-12 15:59:04 +0200
committerMark Wielaard <mjw@redhat.com>2015-05-18 15:48:04 +0200
commit6d93c8c46d9b2b381c889e5f176451996845b055 (patch)
tree7ed9e6ec8c9cfa1a2b49936b87c87cb4b9ce4717 /src/strip.c
parentc0748eff8473b0caa6d51812aa31349bf1dce042 (diff)
downloadelfutils-6d93c8c46d9b2b381c889e5f176451996845b055.tar.gz
strip: Harden against bogus input files. Don't leak tmp debug file on error.
There were various places where a bogus/unexpected input file would cause eu-strip to crash. Also on an unexpected error eu-strip would leak the temp debug file it was writing. https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c34 Signed-off-by: Mark Wielaard <mjw@redhat.com>
Diffstat (limited to 'src/strip.c')
-rw-r--r--src/strip.c268
1 files changed, 191 insertions, 77 deletions
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,