Check Mach_command.cmdsize

https://github.com/upx/upx/issues/426
Also use MemBuffer to avoid leaks that result from throw()
	modified:   p_mach.cpp
	modified:   p_mach.h
This commit is contained in:
John Reiser
2020-11-28 10:56:28 -08:00
parent d488122324
commit eb66470933
2 changed files with 27 additions and 15 deletions
+22 -15
View File
@@ -120,8 +120,6 @@ PackMachBase<T>::PackMachBase(InputFile *f, unsigned cputype, unsigned filetype,
template <class T> template <class T>
PackMachBase<T>::~PackMachBase() PackMachBase<T>::~PackMachBase()
{ {
delete [] rawmseg;
delete [] msegcmd;
} }
PackDylibI386::PackDylibI386(InputFile *f) : super(f) PackDylibI386::PackDylibI386(InputFile *f) : super(f)
@@ -388,7 +386,8 @@ PackMachBase<T>::buildMachLoader(
} }
unsigned char const *const uncLoader = fold_hdrlen + fold; unsigned char const *const uncLoader = fold_hdrlen + fold;
unsigned char *const cprLoader = New(unsigned char, sizeof(h) + h.sz_unc); MemBuffer cprLoader_buf(sizeof(h) + h.sz_unc);
unsigned char *const cprLoader = (unsigned char *)cprLoader_buf.getVoidPtr();
if (0 < szfold) { if (0 < szfold) {
unsigned sz_cpr = 0; unsigned sz_cpr = 0;
int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &sz_cpr, int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &sz_cpr,
@@ -401,7 +400,6 @@ PackMachBase<T>::buildMachLoader(
// This adds the definition to the "library", to be used later. // This adds the definition to the "library", to be used later.
linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr, 0); linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr, 0);
delete [] cprLoader;
int const GAP = 128; // must match stub/l_mac_ppc.S int const GAP = 128; // must match stub/l_mac_ppc.S
int const NO_LAP = 64; // must match stub/src/*darwin*.S int const NO_LAP = 64; // must match stub/src/*darwin*.S
@@ -1385,7 +1383,9 @@ void PackMachBase<T>::unpack(OutputFile *fo)
if ((sizeof(mhdri) + sz_cmds) > (size_t)fi->st_size()) { if ((sizeof(mhdri) + sz_cmds) > (size_t)fi->st_size()) {
throwCantUnpack("file header corrupted"); throwCantUnpack("file header corrupted");
} }
rawmseg = (Mach_segment_command *) New(char, sz_cmds); rawmseg_buf.dealloc(); // discard "same" contents from ::canUnpack()
rawmseg_buf.alloc(sz_cmds);
rawmseg = (Mach_segment_command *)rawmseg_buf.getVoidPtr();
fi->readx(rawmseg, mhdri.sizeofcmds); fi->readx(rawmseg, mhdri.sizeofcmds);
// FIXME forgot space left for LC_CODE_SIGNATURE; // FIXME forgot space left for LC_CODE_SIGNATURE;
@@ -1418,7 +1418,8 @@ void PackMachBase<T>::unpack(OutputFile *fo)
// Uncompress Macho headers // Uncompress Macho headers
fi->readx(ibuf, ph.c_len); fi->readx(ibuf, ph.c_len);
Mach_header *const mhdr = (Mach_header *) New(upx_byte, ph.u_len); MemBuffer mhdr_buf(ph.u_len);
Mach_header *const mhdr = (Mach_header *)mhdr_buf.getVoidPtr();
decompress(ibuf, (upx_byte *)mhdr, false); decompress(ibuf, (upx_byte *)mhdr, false);
if (mhdri.magic != mhdr->magic if (mhdri.magic != mhdr->magic
|| mhdri.cputype != mhdr->cputype || mhdri.cputype != mhdr->cputype
@@ -1427,15 +1428,19 @@ void PackMachBase<T>::unpack(OutputFile *fo)
throwCantUnpack("file header corrupted"); throwCantUnpack("file header corrupted");
unsigned const ncmds = mhdr->ncmds; unsigned const ncmds = mhdr->ncmds;
msegcmd = New(Mach_segment_command, ncmds); msegcmd_buf.alloc(sizeof(Mach_segment_command) * ncmds);
msegcmd = (Mach_segment_command *)msegcmd_buf.getVoidPtr();
unsigned char const *ptr = (unsigned char const *)(1+mhdr); unsigned char const *ptr = (unsigned char const *)(1+mhdr);
for (unsigned j= 0; j < ncmds; ++j) { for (unsigned j= 0; j < ncmds; ++j) {
unsigned char const *const next = ((Mach_command const *)ptr)->cmdsize + ptr;
if (ptr_udiff(next, (1+ mhdr)) > ph.u_len) {
char msg[50]; snprintf(msg, sizeof(msg), "cmdsize[%d] %#x",
j, (unsigned)(next - ptr));
throwCantUnpack(msg);
}
memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command),
((Mach_command const *)ptr)->cmdsize)); ((Mach_command const *)ptr)->cmdsize));
ptr += (unsigned) ((Mach_command const *)ptr)->cmdsize; ptr = next;
if (ptr_udiff(ptr, (1+ mhdr)) > ph.u_len) {
throwCantUnpack("cmdsize");
}
} }
// Put LC_SEGMENT together at the beginning // Put LC_SEGMENT together at the beginning
@@ -1510,7 +1515,6 @@ void PackMachBase<T>::unpack(OutputFile *fo)
c_adler, u_adler, false, sizeof(bhdr)); c_adler, u_adler, false, sizeof(bhdr));
} }
} }
delete [] mhdr;
} }
// The prize is the value of overlay_offset: the offset of compressed data // The prize is the value of overlay_offset: the offset of compressed data
@@ -1538,7 +1542,8 @@ int PackMachBase<T>::canUnpack()
if (2048 < headway) { if (2048 < headway) {
infoWarning("Mach_header.sizeofcmds(%d) > 1024", headway); infoWarning("Mach_header.sizeofcmds(%d) > 1024", headway);
} }
rawmseg = (Mach_segment_command *) New(char, mhdri.sizeofcmds); rawmseg_buf.alloc(mhdri.sizeofcmds);
rawmseg = (Mach_segment_command *)rawmseg_buf.getVoidPtr();
fi->readx(rawmseg, mhdri.sizeofcmds); fi->readx(rawmseg, mhdri.sizeofcmds);
Mach_segment_command const *ptrTEXT = 0; Mach_segment_command const *ptrTEXT = 0;
@@ -1807,14 +1812,16 @@ bool PackMachBase<T>::canPack()
if (16384 < sz_mhcmds) { // somewhat arbitrary, but amd64-darwin.macho-upxmain.c if (16384 < sz_mhcmds) { // somewhat arbitrary, but amd64-darwin.macho-upxmain.c
throwCantPack("16384 < Mach_header.sizeofcmds"); throwCantPack("16384 < Mach_header.sizeofcmds");
} }
rawmseg = (Mach_segment_command *) New(char, sz_mhcmds); rawmseg_buf.alloc(sz_mhcmds);
rawmseg = (Mach_segment_command *)(void *)rawmseg_buf;
fi->readx(rawmseg, mhdri.sizeofcmds); fi->readx(rawmseg, mhdri.sizeofcmds);
unsigned const ncmds = mhdri.ncmds; unsigned const ncmds = mhdri.ncmds;
if (256 < ncmds) { // arbitrary, but guard against garbage if (256 < ncmds) { // arbitrary, but guard against garbage
throwCantPack("256 < Mach_header.ncmds"); throwCantPack("256 < Mach_header.ncmds");
} }
msegcmd = New(Mach_segment_command, ncmds); msegcmd_buf.alloc(sizeof(Mach_segment_command) * ncmds);
msegcmd = (Mach_segment_command *)msegcmd_buf.getVoidPtr();
unsigned char const *ptr = (unsigned char const *)rawmseg; unsigned char const *ptr = (unsigned char const *)rawmseg;
for (unsigned j= 0; j < ncmds; ++j) { for (unsigned j= 0; j < ncmds; ++j) {
Mach_segment_command const *segptr = (Mach_segment_command const *)ptr; Mach_segment_command const *segptr = (Mach_segment_command const *)ptr;
+5
View File
@@ -818,8 +818,13 @@ protected:
upx_byte const *stub_entry; upx_byte const *stub_entry;
upx_byte const *stub_fold; upx_byte const *stub_fold;
upx_byte const *stub_main; upx_byte const *stub_main;
MemBuffer rawmseg_buf; // Mach_segment_command[];
Mach_segment_command *rawmseg; // as input, with sections Mach_segment_command *rawmseg; // as input, with sections
MemBuffer msegcmd_buf; // Mach_segment_command[];
Mach_segment_command *msegcmd; // LC_SEGMENT first, without sections Mach_segment_command *msegcmd; // LC_SEGMENT first, without sections
unsigned o__mod_init_func; // file offset to __DATA.__mod_init_func Mach_section_command unsigned o__mod_init_func; // file offset to __DATA.__mod_init_func Mach_section_command
upx_uint64_t prev_mod_init_func; upx_uint64_t prev_mod_init_func;
upx_uint64_t pagezero_vmsize; upx_uint64_t pagezero_vmsize;