elftoolchain: stop leaving tempfiles on error

Temporary files were not cleaned up, resulting in $TMPDIR or even
the current directory becoming littered with ecp.* files.

This happened with error and even sometimes on success!

Approved by:		dim
MFC after:		4 weeks
Accepted upstream:	https://sourceforge.net/p/elftoolchain/code/3918/
Differential Revision:	https://reviews.freebsd.org/D28651
This commit is contained in:
Chris Rees 2021-02-15 11:37:06 +00:00
parent 37cd6c20db
commit 5ac70383c8
3 changed files with 86 additions and 23 deletions

View File

@ -69,9 +69,11 @@ process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj)
/* Output to a temporary file. */ /* Output to a temporary file. */
create_tempfile(NULL, &tempfile, &fd); create_tempfile(NULL, &tempfile, &fd);
if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) {
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "elf_begin() failed: %s", errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1)); elf_errmsg(-1));
}
elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT);
create_elf(ecp); create_elf(ecp);
elf_end(ecp->ein); elf_end(ecp->ein);
@ -80,27 +82,40 @@ process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj)
obj->buf = NULL; obj->buf = NULL;
/* Extract archive symbols. */ /* Extract archive symbols. */
if (lseek(fd, 0, SEEK_SET) < 0) if (lseek(fd, 0, SEEK_SET) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); err(EXIT_FAILURE, "lseek failed for '%s'", tempfile);
if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) }
if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "elf_begin() failed: %s", errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1)); elf_errmsg(-1));
}
extract_arsym(ecp); extract_arsym(ecp);
elf_end(ecp->eout); elf_end(ecp->eout);
if (fstat(fd, &sb) == -1) if (fstat(fd, &sb) == -1) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "fstat %s failed", tempfile); err(EXIT_FAILURE, "fstat %s failed", tempfile);
if (lseek(fd, 0, SEEK_SET) < 0) }
if (lseek(fd, 0, SEEK_SET) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "lseek %s failed", tempfile); err(EXIT_FAILURE, "lseek %s failed", tempfile);
}
obj->size = sb.st_size; obj->size = sb.st_size;
if ((obj->maddr = malloc(obj->size)) == NULL) if ((obj->maddr = malloc(obj->size)) == NULL) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "memory allocation failed for '%s'", err(EXIT_FAILURE, "memory allocation failed for '%s'",
tempfile); tempfile);
if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) }
if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "read failed for '%s'", tempfile); err(EXIT_FAILURE, "read failed for '%s'", tempfile);
if (unlink(tempfile)) }
if (cleanup_tempfile(tempfile) < 0)
err(EXIT_FAILURE, "unlink %s failed", tempfile); err(EXIT_FAILURE, "unlink %s failed", tempfile);
free(tempfile); free(tempfile);
tempfile = NULL;
close(fd); close(fd);
if (strlen(obj->name) > _MAXNAMELEN_SVR4) if (strlen(obj->name) > _MAXNAMELEN_SVR4)
add_to_ar_str_table(ecp, obj->name); add_to_ar_str_table(ecp, obj->name);

View File

@ -277,6 +277,7 @@ void add_to_symtab(struct elfcopy *_ecp, const char *_name,
unsigned char _st_info, unsigned char _st_other, int _ndx_known); unsigned char _st_info, unsigned char _st_other, int _ndx_known);
int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec); int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec);
void adjust_addr(struct elfcopy *_ecp); void adjust_addr(struct elfcopy *_ecp);
int cleanup_tempfile(char *_fn);
void copy_content(struct elfcopy *_ecp); void copy_content(struct elfcopy *_ecp);
void copy_data(struct section *_s); void copy_data(struct section *_s);
void copy_phdr(struct elfcopy *_ecp); void copy_phdr(struct elfcopy *_ecp);

View File

@ -510,6 +510,27 @@ free_elf(struct elfcopy *ecp)
} }
} }
/*
* Remove a temporary file, without freeing its filename.
*
* Safe to pass NULL, will just ignore it.
*/
int
cleanup_tempfile(char *fn)
{
int errno_save, retval;
if (fn == NULL)
return 0;
errno_save = errno;
if ((retval = unlink(fn)) < 0) {
warn("unlink tempfile %s failed", fn);
errno = errno_save;
return retval;
}
return 0;
}
/* Create a temporary file. */ /* Create a temporary file. */
void void
create_tempfile(const char *src, char **fn, int *fd) create_tempfile(const char *src, char **fn, int *fd)
@ -656,8 +677,10 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
} }
#endif #endif
if (lseek(ifd, 0, SEEK_SET) < 0) if (lseek(ifd, 0, SEEK_SET) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "lseek failed"); err(EXIT_FAILURE, "lseek failed");
}
/* /*
* If input object is not ELF file, convert it to an intermediate * If input object is not ELF file, convert it to an intermediate
@ -677,9 +700,12 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
ecp->oed = ELFDATA2LSB; ecp->oed = ELFDATA2LSB;
} }
create_tempfile(src, &elftemp, &efd); create_tempfile(src, &elftemp, &efd);
if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL) if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL) {
cleanup_tempfile(elftemp);
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "elf_begin() failed: %s", errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1)); elf_errmsg(-1));
}
elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT);
if (ecp->itf == ETF_BINARY) if (ecp->itf == ETF_BINARY)
create_elf_from_binary(ecp, ifd, src); create_elf_from_binary(ecp, ifd, src);
@ -687,31 +713,45 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
create_elf_from_ihex(ecp, ifd); create_elf_from_ihex(ecp, ifd);
else if (ecp->itf == ETF_SREC) else if (ecp->itf == ETF_SREC)
create_elf_from_srec(ecp, ifd); create_elf_from_srec(ecp, ifd);
else else {
cleanup_tempfile(elftemp);
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "Internal: invalid target flavour"); errx(EXIT_FAILURE, "Internal: invalid target flavour");
}
elf_end(ecp->eout); elf_end(ecp->eout);
/* Open intermediate ELF object as new input object. */ /* Open intermediate ELF object as new input object. */
close(ifd); close(ifd);
if ((ifd = open(elftemp, O_RDONLY)) == -1) if ((ifd = open(elftemp, O_RDONLY)) == -1) {
cleanup_tempfile(elftemp);
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "open %s failed", src); err(EXIT_FAILURE, "open %s failed", src);
}
close(efd); close(efd);
if (unlink(elftemp) < 0) if (cleanup_tempfile(elftemp) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "unlink %s failed", elftemp); err(EXIT_FAILURE, "unlink %s failed", elftemp);
}
free(elftemp); free(elftemp);
elftemp = NULL;
} }
if ((ecp->ein = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) if ((ecp->ein = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) {
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "elf_begin() failed: %s", errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1)); elf_errmsg(-1));
}
switch (elf_kind(ecp->ein)) { switch (elf_kind(ecp->ein)) {
case ELF_K_NONE: case ELF_K_NONE:
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "file format not recognized"); errx(EXIT_FAILURE, "file format not recognized");
case ELF_K_ELF: case ELF_K_ELF:
if ((ecp->eout = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL) if ((ecp->eout = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL) {
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "elf_begin() failed: %s", errx(EXIT_FAILURE, "elf_begin() failed: %s",
elf_errmsg(-1)); elf_errmsg(-1));
}
/* elfcopy(1) manage ELF layout by itself. */ /* elfcopy(1) manage ELF layout by itself. */
elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT);
@ -730,21 +770,21 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
* Create (another) tempfile for binary/srec/ihex * Create (another) tempfile for binary/srec/ihex
* output object. * output object.
*/ */
if (tempfile != NULL) { if (cleanup_tempfile(tempfile) < 0)
if (unlink(tempfile) < 0) errx(EXIT_FAILURE, "unlink %s failed",
err(EXIT_FAILURE, "unlink %s failed", tempfile);
tempfile); free(tempfile);
free(tempfile);
}
create_tempfile(src, &tempfile, &ofd0); create_tempfile(src, &tempfile, &ofd0);
/* /*
* Rewind the file descriptor being processed. * Rewind the file descriptor being processed.
*/ */
if (lseek(ofd, 0, SEEK_SET) < 0) if (lseek(ofd, 0, SEEK_SET) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, err(EXIT_FAILURE,
"lseek failed for the output object"); "lseek failed for the output object");
}
/* /*
* Call flavour-specific conversion routine. * Call flavour-specific conversion routine.
@ -765,11 +805,13 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
#if WITH_PE #if WITH_PE
create_pe(ecp, ofd, ofd0); create_pe(ecp, ofd, ofd0);
#else #else
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "PE/EFI support not enabled" errx(EXIT_FAILURE, "PE/EFI support not enabled"
" at compile time"); " at compile time");
#endif #endif
break; break;
default: default:
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "Internal: unsupported" errx(EXIT_FAILURE, "Internal: unsupported"
" output flavour %d", ecp->oec); " output flavour %d", ecp->oec);
} }
@ -784,6 +826,7 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
/* XXX: Not yet supported. */ /* XXX: Not yet supported. */
break; break;
default: default:
cleanup_tempfile(tempfile);
errx(EXIT_FAILURE, "file format not supported"); errx(EXIT_FAILURE, "file format not supported");
} }
@ -802,9 +845,13 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst)
in_place = 1; in_place = 1;
} }
if (copy_from_tempfile(tempfile, dst, ofd, &tfd, in_place) < 0) if (copy_from_tempfile(tempfile, dst, ofd,
&tfd, in_place) < 0) {
cleanup_tempfile(tempfile);
err(EXIT_FAILURE, "creation of %s failed", dst); err(EXIT_FAILURE, "creation of %s failed", dst);
}
/* 'tempfile' has been removed by copy_from_tempfile(). */
free(tempfile); free(tempfile);
tempfile = NULL; tempfile = NULL;