From 650df95b7240c864479844c87a040e453120c328 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sun, 18 Jun 2017 14:24:44 -0700 Subject: [PATCH] Fix thinko in PackMachBase::canUnpack(). Also detect more bad input values. https://github.com/upx/upx/issues/109 modified: p_mach.cpp --- src/p_mach.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 952878e5..bb62eb42 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -1639,6 +1639,10 @@ int PackMachBase::canUnpack() return false; my_cpusubtype = mhdri.cpusubtype; + int headway = (int)mhdri.sizeofcmds; + if (1024 < headway) { + infoWarning("Mach_header.sizeofcmds(%d) > 1024", headway); + } rawmseg = (Mach_segment_command *)new char[(unsigned) mhdri.sizeofcmds]; fi->readx(rawmseg, mhdri.sizeofcmds); @@ -1674,6 +1678,12 @@ int PackMachBase::canUnpack() } } pos_next = segptr->filesize + segptr->fileoff; + if ((headway -= ptr->cmdsize) < 0) { + infoWarning("Mach_command[%u]{@%lu}.cmdsize = %u", j, + sizeof(mhdri) + mhdri.sizeofcmds - (headway + ptr->cmdsize), + (unsigned)ptr->cmdsize); + throwCantUnpack("sum(.cmdsize) exceeds .sizeofcmds"); + } } else if (Mach_command::LC_UNIXTHREAD==ptr->cmd) { rip = entryVMA = threadc_getPC(ptr); @@ -1777,15 +1787,15 @@ int PackMachBase::canUnpack() // The first non-zero word scanning backwards from __LINKEDIT.fileoff // is the total length of compressed data which preceeds it //(distance to l_info), so that's another method. - fi->seek(offLINK-0x1000, SEEK_SET); + fi->seek(offLINK - 0x1000, SEEK_SET); fi->readx(buf, 0x1000); unsigned const *const lo = (unsigned const *)&buf[0]; unsigned const *p; for (p = (unsigned const *)&buf[0x1000]; p > lo; ) if (*--p) { overlay_offset = *(TE32 const *)p; if ((off_t)overlay_offset < offLINK) { - overlay_offset -= (char const *)p - (char const *)lo - + (offLINK - 0x1000) - sizeof(l_info); + overlay_offset = ((char const *)p - (char const *)lo) + + (offLINK - 0x1000) - overlay_offset + sizeof(l_info); fi->seek(overlay_offset, SEEK_SET); fi->readx(buf, bufsize); if (b_ptr->sz_unc < 0x4000