From 3949af6d3ce1201968c805b596506e801318506c Mon Sep 17 00:00:00 2001 From: John Reiser Date: Thu, 28 Mar 2024 07:48:55 -0700 Subject: [PATCH] Unpacking detects and defends against malicious ELF --- src/p_lx_elf.cpp | 20 ++++++++++++++------ src/p_unix.cpp | 6 ++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 0ae0bcb8..8eff9431 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -6484,13 +6484,17 @@ void PackLinuxElf64::un_shlib_1( struct { struct l_info l; struct p_info p; + struct b_info b; } hdr; fi->readx(&hdr, sizeof(hdr)); if (hdr.l.l_magic != UPX_MAGIC_LE32 - || hdr.l.l_lsize != (unsigned)lsize - || hdr.p.p_filesize != ph.u_file_size) { - throwCantUnpack("corrupt l_info/p_info"); + || get_te16(&hdr.l.l_lsize) != (unsigned)lsize + || get_te32(&hdr.p.p_filesize) != ph.u_file_size + || get_te32(&hdr.b.sz_unc) < sz_elf_hdrs // peek: 1st b_info covers Elf headers + ) { + throwCantUnpack("corrupt l_info/p_info/b_info"); } + fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR); // hdr.b_info was a peek // The default layout for a shared library created by binutils-2.29 // (Fedora 28; 2018) has two PT_LOAD: permissions r-x and rw-. @@ -6680,13 +6684,17 @@ void PackLinuxElf32::un_shlib_1( struct { struct l_info l; struct p_info p; + struct b_info b; } hdr; fi->readx(&hdr, sizeof(hdr)); if (hdr.l.l_magic != UPX_MAGIC_LE32 - || hdr.l.l_lsize != (unsigned)lsize - || hdr.p.p_filesize != ph.u_file_size) { - throwCantUnpack("corrupt l_info/p_info"); + || get_te16(&hdr.l.l_lsize) != (unsigned)lsize + || get_te32(&hdr.p.p_filesize) != ph.u_file_size + || get_te32(&hdr.b.sz_unc) < sz_elf_hdrs // peek: 1st b_info covers Elf headers + ) { + throwCantUnpack("corrupt l_info/p_info/b_info"); } + fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR); // hdr.b_info was a peek // The default layout for a shared library created by binutils-2.29 // (Fedora 28; 2018) has two PT_LOAD: permissions r-x and rw-. diff --git a/src/p_unix.cpp b/src/p_unix.cpp index ee08e751..86f9bc6a 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -491,8 +491,10 @@ unsigned PackUnix::unpackExtent(unsigned wanted, OutputFile *fo, throwCantUnpack("corrupt b_info"); // place the input for overlapping de-compression - // FIXME: inlen cheats OVERHEAD; assumes small wanted peek length - int j = inlen + blocksize + OVERHEAD - sz_cpr; + int j = inlen + sz_unc + OVERHEAD - sz_cpr; + if (ibuf.getSize() < (unsigned)(j + sz_cpr)) { + throwCantUnpack("corrupt b_info"); + } fi->readx(ibuf+j, sz_cpr); total_in += sz_cpr; // update checksum of compressed data