From 8a5d35273342d707759dc0a0cfd8e13344ee0b72 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Thu, 12 Jul 2012 14:25:28 -0700 Subject: [PATCH] Portability: fix "EOFException: premature end of file" doing ELF on Windows. OutputFile::read() was bad news; fsync() should work, but was missing. --- src/file.cpp | 25 ++++++-------- src/file.h | 2 -- src/p_lx_elf.cpp | 80 ++++++++++++++++++++++++++------------------- src/p_lx_elf.h | 6 ++-- src/p_lx_interp.cpp | 6 ++-- src/p_lx_interp.h | 2 +- src/p_mach.cpp | 4 ++- src/p_mach.h | 2 +- src/p_unix.cpp | 17 ++++++---- src/p_unix.h | 2 +- 10 files changed, 79 insertions(+), 67 deletions(-) diff --git a/src/file.cpp b/src/file.cpp index 67003c5b..0a3ae6d7 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -410,21 +410,16 @@ void OutputFile::seek(off_t off, int whence) super::seek(off,whence); } -int OutputFile::read(void *buf, int len) -{ - InputFile infile; - infile.open(this->getName(), O_RDONLY); - infile.seek(this->tell(), SEEK_SET); - return infile.read(buf, len); -} - -int OutputFile::readx(void *buf, int len) -{ - InputFile infile; - infile.open(this->getName(), O_RDONLY); - infile.seek(this->tell(), SEEK_SET); - return infile.readx(buf, len); -} +// WARNING: fsync() does not exist in some Windows environments. +// This trick works only on UNIX-like systems. +//int OutputFile::read(void *buf, int len) +//{ +// fsync(_fd); +// InputFile infile; +// infile.open(this->getName(), O_RDONLY); +// infile.seek(this->tell(), SEEK_SET); +// return infile.read(buf, len); +//} void OutputFile::set_extent(off_t offset, off_t length) { diff --git a/src/file.h b/src/file.h index 417dcc8c..f5ae98a5 100644 --- a/src/file.h +++ b/src/file.h @@ -141,8 +141,6 @@ public: // FIXME - these won't work when using the '--stdout' option virtual void seek(off_t off, int whence); virtual void rewrite(const void *buf, int len); - virtual int read(void *buf, int len); - virtual int readx(void *buf, int len); // util static void dump(const char *name, const void *buf, int len, int flags=-1); diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 2f4c129f..2d1fb5c2 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -196,17 +196,6 @@ PackLinuxElf::~PackLinuxElf() delete[] file_image; file_image = NULL; } -// Swap the byte ranges fo[a to b] and fo[b to c]. -static void swap_byte_ranges(OutputFile *fo, unsigned a, unsigned b, unsigned c) -{ - MemBuffer buf(c - a); - fo->seek(a, SEEK_SET); - fo->readx(buf, c - a); - fo->seek(a, SEEK_SET); - fo->rewrite(&buf[b - a], c - b); - fo->rewrite(&buf[0], b - a); -} - void PackLinuxElf::pack3(OutputFile *fo, Filter &ft) { sz_pack2b = fpad4(fo); // after headers, all PT_LOAD, gaps @@ -245,16 +234,28 @@ void PackLinuxElf::pack3(OutputFile *fo, Filter &ft) get_te16(&linfo.l_lsize) + len - sz_pack2a)); len = fpad4(fo); - // Put the loader in the middle, after the compressed PT_LOADs - // and before the compressed gaps (and debuginfo!) - // As first written, loader is fo[sz_pack2b to len], - // and gaps and debuginfo are fo[sz_pack2a to sz_pack2b]. - swap_byte_ranges(fo, sz_pack2a, sz_pack2b, len); } void PackLinuxElf32::pack3(OutputFile *fo, Filter &ft) { - super::pack3(fo, ft); + super::pack3(fo, ft); // loader follows compressed PT_LOADs + // Then compressed gaps (including debuginfo.) + unsigned total_in = 0, total_out = 0; + for (unsigned k = 0; k < e_phnum; ++k) { + Extent x; + x.size = find_LOAD_gap(phdri, k, e_phnum); + if (x.size) { + x.offset = get_te32(&phdri[k].p_offset) + + get_te32(&phdri[k].p_filesz); + packExtent(x, total_in, total_out, 0, fo); + } + } + // write block end marker (uncompressed size 0) + b_info hdr; memset(&hdr, 0, sizeof(hdr)); + set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); + fo->write(&hdr, sizeof(hdr)); + fpad4(fo); + set_te32(&elfout.phdr[0].p_filesz, sz_pack2 + lsize); set_te32(&elfout.phdr[0].p_memsz, sz_pack2 + lsize); if (0!=xct_off) { // shared library @@ -331,7 +332,24 @@ void PackLinuxElf32::pack3(OutputFile *fo, Filter &ft) void PackLinuxElf64::pack3(OutputFile *fo, Filter &ft) { - super::pack3(fo, ft); + super::pack3(fo, ft); // loader follows compressed PT_LOADs + // Then compressed gaps (including debuginfo.) + unsigned total_in = 0, total_out = 0; + for (unsigned k = 0; k < e_phnum; ++k) { + Extent x; + x.size = find_LOAD_gap(phdri, k, e_phnum); + if (x.size) { + x.offset = get_te64(&phdri[k].p_offset) + + get_te64(&phdri[k].p_filesz); + packExtent(x, total_in, total_out, 0, fo); + } + } + // write block end marker (uncompressed size 0) + b_info hdr; memset(&hdr, 0, sizeof(hdr)); + set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); + fo->write(&hdr, sizeof(hdr)); + fpad4(fo); + set_te64(&elfout.phdr[0].p_filesz, sz_pack2 + lsize); set_te64(&elfout.phdr[0].p_memsz, sz_pack2 + lsize); if (0!=xct_off) { // shared library @@ -2298,7 +2316,7 @@ unsigned PackLinuxElf32::find_LOAD_gap( return lo - hi; } -void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) +int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) { Extent x; unsigned k; @@ -2356,17 +2374,15 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) } sz_pack2a = fpad4(fo); + // Accounting only; ::pack3 will do the compression and output for (k = 0; k < e_phnum; ++k) { - x.size = find_LOAD_gap(phdri, k, e_phnum); - if (x.size) { - x.offset = get_te32(&phdri[k].p_offset) + - get_te32(&phdri[k].p_filesz); - packExtent(x, total_in, total_out, 0, fo); - } + total_in += find_LOAD_gap(phdri, k, e_phnum); } if ((off_t)total_in != file_size) throwEOFException(); + + return 0; // omit end-of-compression bhdr for now } // Determine length of gap between PT_LOAD phdr[k] and closest PT_LOAD @@ -2409,7 +2425,7 @@ unsigned PackLinuxElf64::find_LOAD_gap( return lo - hi; } -void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) +int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) { Extent x; unsigned k; @@ -2467,17 +2483,15 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) } sz_pack2a = fpad4(fo); - for (k = 0; k < e_phnum; ++k) { - x.size = find_LOAD_gap(phdri, k, e_phnum); - if (x.size) { - x.offset = get_te64(&phdri[k].p_offset) + - get_te64(&phdri[k].p_filesz); - packExtent(x, total_in, total_out, 0, fo); - } + // Accounting only; ::pack3 will do the compression and output + for (k = 0; k < e_phnum; ++k) { // + total_in += find_LOAD_gap(phdri, k, e_phnum); } if ((off_t)total_in != file_size) throwEOFException(); + + return 0; // omit end-of-compression bhdr for now } // Filter 0x50, 0x51 assume HostPolicy::isLE diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index 154093ac..fd3040cd 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -50,7 +50,7 @@ protected: // because they depend on Elf32 or Elf64 data structures, which differ. virtual void pack1(OutputFile *, Filter &) = 0; // generate executable header - virtual void pack2(OutputFile *, Filter &) = 0; // append compressed data + virtual int pack2(OutputFile *, Filter &) = 0; // append compressed data virtual void pack3(OutputFile *, Filter &) = 0; // append loader //virtual void pack4(OutputFile *, Filter &) = 0; // append pack header @@ -111,7 +111,7 @@ protected: virtual int ARM_is_QNX(void); virtual void pack1(OutputFile *, Filter &); // generate executable header - virtual void pack2(OutputFile *, Filter &); // append compressed data + virtual int pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append pack header virtual void unpack(OutputFile *fo); @@ -228,7 +228,7 @@ protected: virtual int checkEhdr(Elf64_Ehdr const *ehdr) const; virtual void pack1(OutputFile *, Filter &); // generate executable header - virtual void pack2(OutputFile *, Filter &); // append compressed data + virtual int pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append pack header virtual void unpack(OutputFile *fo); diff --git a/src/p_lx_interp.cpp b/src/p_lx_interp.cpp index 5c347b1c..ec9213c9 100644 --- a/src/p_lx_interp.cpp +++ b/src/p_lx_interp.cpp @@ -124,12 +124,12 @@ void PackLinuxElf32x86interp::pack1(OutputFile *fo, Filter &) #undef E } -void PackLinuxElf32x86interp::pack2(OutputFile *fo, Filter &ft) +int PackLinuxElf32x86interp::pack2(OutputFile *fo, Filter &ft) { if (opt->o_unix.make_ptinterp) { - return; // ignore current input file! + return 1; // ignore current input file! } - super::pack2(fo, ft); + return super::pack2(fo, ft); } #undef PAGE_MASK diff --git a/src/p_lx_interp.h b/src/p_lx_interp.h index 85d92c6a..e4c2ae69 100644 --- a/src/p_lx_interp.h +++ b/src/p_lx_interp.h @@ -54,7 +54,7 @@ public: protected: virtual void pack1(OutputFile *, Filter &); // generate executable header - virtual void pack2(OutputFile *, Filter &); // append compressed data + virtual int pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &); // build loader }; diff --git a/src/p_mach.cpp b/src/p_mach.cpp index fd8dd0b0..71b4cf6e 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -899,7 +899,7 @@ void PackMachBase::pack3(OutputFile *fo, Filter &ft) } template -void PackMachBase::pack2(OutputFile *fo, Filter &ft) // append compressed body +int PackMachBase::pack2(OutputFile *fo, Filter &ft) // append compressed body { unsigned const lc_seg = lc_segment[sizeof(Addr)>>3]; Extent x; @@ -977,6 +977,8 @@ void PackMachBase::pack2(OutputFile *fo, Filter &ft) // append compressed bo if ((off_t)total_in != file_size) throwEOFException(); segcmdo.filesize = fo->getBytesWritten(); + + return 1; } void PackMachPPC32::pack1_setup_threado(OutputFile *const fo) diff --git a/src/p_mach.h b/src/p_mach.h index 5a95c83e..aa2f30c5 100644 --- a/src/p_mach.h +++ b/src/p_mach.h @@ -532,7 +532,7 @@ public: // called by the generic pack() virtual void pack1(OutputFile *, Filter &); // generate executable header - virtual void pack2(OutputFile *, Filter &); // append compressed data + virtual int pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &) = 0; // append loader virtual void pack4(OutputFile *, Filter &) = 0; // append PackHeader diff --git a/src/p_unix.cpp b/src/p_unix.cpp index 8c9d1bd8..58236313 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -130,7 +130,7 @@ int PackUnix::getStrategy(Filter &/*ft*/) return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); } -void PackUnix::pack2(OutputFile *fo, Filter &ft) +int PackUnix::pack2(OutputFile *fo, Filter &ft) { // compress blocks unsigned total_in = 0; @@ -224,6 +224,8 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft) if ((off_t)total_in != file_size) { throwEOFException(); } + + return 1; // default: write end-of-compression bhdr next } void @@ -285,12 +287,13 @@ void PackUnix::pack(OutputFile *fo) set_te32(&hbuf.p_blocksize, blocksize); fo->write(&hbuf, sizeof(hbuf)); - pack2(fo, ft); // append the compressed body - - // write block end marker (uncompressed size 0) - b_info hdr; memset(&hdr, 0, sizeof(hdr)); - set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); - fo->write(&hdr, sizeof(hdr)); + // append the compressed body + if (pack2(fo, ft)) { + // write block end marker (uncompressed size 0) + b_info hdr; memset(&hdr, 0, sizeof(hdr)); + set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); + fo->write(&hdr, sizeof(hdr)); + } pack3(fo, ft); // append loader diff --git a/src/p_unix.h b/src/p_unix.h index 866f79d9..3faa73b2 100644 --- a/src/p_unix.h +++ b/src/p_unix.h @@ -54,7 +54,7 @@ public: protected: // called by the generic pack() virtual void pack1(OutputFile *, Filter &); // generate executable header - virtual void pack2(OutputFile *, Filter &); // append compressed data + virtual int pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append PackHeader