diff --git a/src/Makefile b/src/Makefile index 1879c686..35b5f537 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,19 +12,19 @@ BUILD_USE_DEPEND ?= 1 MAKEFLAGS += -r .SUFFIXES: export SHELL = /bin/sh -override e = $($1) $(EXTRA_$1) $(upx_$1) $(upx_EXTRA_$1) $($(basename $(notdir $@)).$1) +override ee = $($1) $(EXTRA_$1) $(upx_$1) $(upx_EXTRA_$1) $($(basename $(notdir $@)).$1) ifndef srcdir -srcdir := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) -srcdir := $(shell echo '$(srcdir)' | sed 's,/*$$,,') +srcdir := $(dir $(lastword $(MAKEFILE_LIST))) +srcdir := $(shell echo '$(srcdir)' | sed 's,/*$$,,' || echo 'ERROR') endif ifndef top_srcdir top_srcdir := $(srcdir)/.. endif include $(wildcard $(top_srcdir)/Makevars.global ./Makevars.local) ifneq ($(srcdir),.) -##$(info Info: using VPATH . $(srcdir)) -VPATH := . $(srcdir) +vpath %.cpp .:$(srcdir) +vpath %.h .:$(srcdir) endif # toolchain @@ -75,9 +75,8 @@ CXXFLAGS += $(CXXFLAGS_WERROR) ifeq ($(BUILD_TYPE_SANITIZE),1) CXXFLAGS_SANITIZE ?= -fsanitize=address,undefined -fno-omit-frame-pointer -DACC_CFG_NO_UNALIGNED CXXFLAGS += $(CXXFLAGS_SANITIZE) -LDFLAGS += $(CXXFLAGS_SANITIZE) # these are the only 2 objects that are actually speed-sensitive -compress_lzma$(objext) filteri$(objext) : CXXFLAGS_SANITIZE = +compress_lzma$(objext) filteri$(objext) : override CXXFLAGS_SANITIZE = endif # rules @@ -86,20 +85,20 @@ all: upx$(exeext) | ./.depend upx$(exeext): $(upx_OBJECTS) $(upx_DEPENDENCIES) $($(notdir $@).PRE_LINK_STEP) - $(strip $(CXXLD) $(call e,CPPFLAGS) $(call e,CXXFLAGS) $(call e,LDFLAGS) -o $@ $(upx_OBJECTS) $(call e,LDADD) $(call e,LIBS)) + $(strip $(CXXLD) $(call ee,CXXFLAGS) $(call ee,LDFLAGS) -o $@ $(upx_OBJECTS) $(call ee,LDADD) $(call ee,LIBS)) $($(notdir $@).POST_LINK_STEP) $(CHECK_WHITESPACE) %.o : %.cpp | ./.depend - $(strip $(CXX) $(call e,CPPFLAGS) $(call e,CXXFLAGS) -o $@ -c $<) + $(strip $(CXX) $(call ee,CPPFLAGS) $(call ee,CXXFLAGS) -o $@ -c $<) %.cpp.ii : %.cpp - $(strip $(CXX) $(call e,CPPFLAGS) $(call e,CXXFLAGS) -o $@ -E $<) + $(strip $(CXX) $(call ee,CPPFLAGS) $(call ee,CXXFLAGS) -o $@ -E $<) ifeq ($(BUILD_USE_DEPEND),1) ./.depend: $(sort $(wildcard $(srcdir)/*.cpp $(srcdir)/*.h)) $(MAKEFILE_LIST) @rm -f $@ @echo "Updating $@" - @$(strip $(CXX) $(call e,CPPFLAGS) -MM) $(filter %.cpp,$^) > $@ + @$(strip $(CXX) $(call ee,CPPFLAGS) -MM) $(filter %.cpp,$^) > $@ else ./.depend: .PHONY: ./.depend @@ -115,16 +114,14 @@ check-whitespace : ; $(CHECK_WHITESPACE) endif .PHONY: check-whitespace +mostlyclean clean distclean maintainer-clean: + rm -f *.d *.map *.o *.obj *.res ./.depend upx.exe upx.out upx.ttp upx$(exeext) -./.depend compress_lzma$(objext) : INCLUDES += -I$(UPX_LZMADIR) +./.depend compress_lzma$(objext) : override INCLUDES += -I$(UPX_LZMADIR) compress_lzma$(objext) : CXXFLAGS += -Wno-shadow p_mach$(objext) : CXXFLAGS += -Wno-cast-align - -mostlyclean clean distclean maintainer-clean: - rm -f *.d *.map *.o *.obj *.res ./.depend upx.exe upx.out upx.ttp upx$(exeext) - .PHONY: all mostlyclean clean distclean maintainer-clean ifeq ($(MAKECMDGOALS),mostlyclean) @@ -140,11 +137,9 @@ endif help$(objext): $(MAKEFILE_LIST) endif - # "make run-testsuite" -# # search for the UPX testsuite -- git clone https://github.com/upx/upx-testsuite.git -# you also can set upx_testsuite_SRCDIR +# you also can override upx_testsuite_SRCDIR ifndef upx_testsuite_SRCDIR # search standard locations below $(top_srcdir) ifneq ($(wildcard $(top_srcdir)/../upx-testsuite.git/files/packed/.),) @@ -165,7 +160,6 @@ run-testsuite: ./upx$(exeext) endif endif - # automatically format some C++ source code files ifeq ($(shell uname),Linux) CLANG_FORMAT_FILES += packhead.cpp diff --git a/src/compress_lzma.cpp b/src/compress_lzma.cpp index b277565a..7fd1bef9 100644 --- a/src/compress_lzma.cpp +++ b/src/compress_lzma.cpp @@ -783,7 +783,7 @@ int upx_lzma_test_overlap ( const upx_bytep buf, return UPX_E_ERROR; // NOTE: there is a very tiny possibility that decompression has // succeeded but the data is not restored correctly because of - // in-place buffer overlapping. + // in-place buffer overlapping, so we use an extra memcmp(). if (tbuf != NULL && memcmp(tbuf, b, *dst_len) != 0) return UPX_E_ERROR; return UPX_E_OK; diff --git a/src/compress_zlib.cpp b/src/compress_zlib.cpp index 94beec6c..543725a6 100644 --- a/src/compress_zlib.cpp +++ b/src/compress_zlib.cpp @@ -211,7 +211,7 @@ int upx_zlib_test_overlap ( const upx_bytep buf, return UPX_E_ERROR; // NOTE: there is a very tiny possibility that decompression has // succeeded but the data is not restored correctly because of - // in-place buffer overlapping. + // in-place buffer overlapping, so we use an extra memcmp(). if (tbuf != NULL && memcmp(tbuf, b, *dst_len) != 0) return UPX_E_ERROR; return UPX_E_OK; @@ -236,10 +236,12 @@ const char *upx_zlib_version_string(void) return zlibVersion(); } +#if 0 /* UNUSED */ unsigned upx_zlib_adler32(const void *buf, unsigned len, unsigned adler) { return adler32(adler, (const Bytef *) buf, len); } +#endif #if 0 /* UNUSED */ unsigned upx_zlib_crc32(const void *buf, unsigned len, unsigned crc) diff --git a/src/conf.h b/src/conf.h index 9db19dda..3725036e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -163,6 +163,13 @@ typedef unsigned char upx_byte; #undef NDEBUG #include +// protect against integer overflows and malicious header fields +// see C 11 standard, Annex K +typedef size_t upx_rsize_t; +#define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM +#define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE +#define UPX_RSIZE_MAX_STR (1024 * 1024) + /************************************************************************* // portab diff --git a/src/mem.cpp b/src/mem.cpp index 84721e2f..52977382 100644 --- a/src/mem.cpp +++ b/src/mem.cpp @@ -35,41 +35,43 @@ // and malicious header fields **************************************************************************/ -// DO NOT CHANGE -#define MAX_BUF_SIZE (768 * 1024 * 1024) -ACC_COMPILE_TIME_ASSERT_HEADER(2ull * MAX_BUF_SIZE * 9 / 8 + 16*1024*1024 < INT_MAX) +ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX) +ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR <= UPX_RSIZE_MAX / 256) +ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16*1024*1024 < INT_MAX) -size_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra) +upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { assert(element_size > 0); - if (element_size > MAX_BUF_SIZE) throwCantPack("mem_size 1; take care"); - if (n > MAX_BUF_SIZE) throwCantPack("mem_size 2; take care"); - if (extra > MAX_BUF_SIZE) throwCantPack("mem_size 3; take care"); - upx_uint64_t bytes = element_size * n + extra; // cannot overflow - if (bytes > MAX_BUF_SIZE) throwCantPack("mem_size 4; take care"); - return ACC_ICONV(size_t, bytes); + if (element_size > UPX_RSIZE_MAX) throwCantPack("mem_size 1; take care"); + if (n > UPX_RSIZE_MAX) throwCantPack("mem_size 2; take care"); + if (extra1 > UPX_RSIZE_MAX) throwCantPack("mem_size 3; take care"); + if (extra2 > UPX_RSIZE_MAX) throwCantPack("mem_size 4; take care"); + upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow + if (bytes > UPX_RSIZE_MAX) throwCantPack("mem_size 5; take care"); + return ACC_ICONV(upx_rsize_t, bytes); } -size_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n) +upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n) { mem_size_assert(element_size, n); - return ACC_ICONV(size_t, n); // return n + return ACC_ICONV(upx_rsize_t, n); // return n } -bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra) +bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { assert(element_size > 0); - if (element_size > MAX_BUF_SIZE) return false; - if (n > MAX_BUF_SIZE) return false; - if (extra > MAX_BUF_SIZE) return false; - upx_uint64_t bytes = element_size * n + extra; // cannot overflow - if (bytes > MAX_BUF_SIZE) return false; + if (element_size > UPX_RSIZE_MAX) return false; + if (n > UPX_RSIZE_MAX) return false; + if (extra1 > UPX_RSIZE_MAX) return false; + if (extra2 > UPX_RSIZE_MAX) return false; + upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow + if (bytes > UPX_RSIZE_MAX) return false; return true; } bool mem_size_valid_bytes(upx_uint64_t bytes) { - if (bytes > MAX_BUF_SIZE) return false; + if (bytes > UPX_RSIZE_MAX) return false; return true; } @@ -86,8 +88,6 @@ int ptr_diff(const char *p1, const char *p2) return ACC_ICONV(int, d); } -#undef MAX_BUF_SIZE - /************************************************************************* // bool use_simple_mcheck() diff --git a/src/pefile.cpp b/src/pefile.cpp index 7539e163..0f1bce79 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -1609,7 +1609,7 @@ PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode, branch->name = NULL; branch->parent = parent; branch->nc = ic; - branch->children = new upx_rnode*[ic]; + branch->children = New(upx_rnode *, ic); branch->data = *node; for (const res_dir_entry *rde = node->entries + ic - 1; --ic >= 0; rde--) diff --git a/src/snprintf.cpp b/src/snprintf.cpp index 3d2a73e7..ae84d7c0 100644 --- a/src/snprintf.cpp +++ b/src/snprintf.cpp @@ -744,15 +744,12 @@ static size_t dopr(char *buffer, size_t maxsize, const char *format, va_list arg // public entries **************************************************************************/ -// protect against integer overflows and malicious header fields -#define MAX_STR_SIZE (1024 * 1024) - // UPX version with assertions int upx_vsnprintf(char *str, size_t count, const char *format, va_list ap) { size_t size; // preconditions - assert(count <= MAX_STR_SIZE); + assert(count <= UPX_RSIZE_MAX_STR); if (str != NULL) assert(count > 0); else @@ -762,7 +759,7 @@ int upx_vsnprintf(char *str, size_t count, const char *format, va_list ap) { // postconditions assert(size > 0); - assert(size <= MAX_STR_SIZE); + assert(size <= UPX_RSIZE_MAX_STR); if (str != NULL) { assert(size <= count); assert(str[size - 1] == '\0'); @@ -809,14 +806,13 @@ int __acc_cdecl_va upx_asprintf(char **ptr, const char *format, ...) { } #undef strlen -size_t upx_strlen(const char *s) { +upx_rsize_t upx_strlen(const char *s) { + assert(s != NULL); size_t len = strlen(s); - assert(len < MAX_STR_SIZE); + assert(len < UPX_RSIZE_MAX_STR); return len; } -#undef MAX_STR_SIZE - /************************************************************************* // **************************************************************************/ diff --git a/src/snprintf.h b/src/snprintf.h index 8abaced6..a795577c 100644 --- a/src/snprintf.h +++ b/src/snprintf.h @@ -44,7 +44,7 @@ int __acc_cdecl_va upx_asprintf (char **ptr, const char *format, ...); #undef sprintf #define sprintf error_sprintf_is_dangerous_use_snprintf -size_t upx_strlen(const char *); +upx_rsize_t upx_strlen(const char *); #undef strlen #define strlen upx_strlen diff --git a/src/stub/i386-darwin.macho-upxmain.exe b/src/stub/i386-darwin.macho-upxmain.exe old mode 100755 new mode 100644 diff --git a/src/stub/scripts/check_whitespace.sh b/src/stub/scripts/check_whitespace.sh index c10fcda7..996116e4 100755 --- a/src/stub/scripts/check_whitespace.sh +++ b/src/stub/scripts/check_whitespace.sh @@ -30,7 +30,7 @@ LC_ALL=C sort -z | xargs -0r perl -n -e ' if ($ARGV =~ m,(^|/)\.gitmodules$,) { } elsif ($ARGV =~ m,(^|/)(gnu|m)?make(file|vars),i) { } elsif ($ARGV =~ m,/tmp/.*\.(disasm|dump)$,) { } - elsif ($ARGV =~ m,/src/stub/src/arch/.*\.S$,) { } + elsif ($ARGV =~ m,/src/stub/src/arch/.*/lzma.*\.S$,) { } else { print "ERROR: hard TAB detected $ARGV: $_"; exit(1); } } ' || exit 1 diff --git a/src/stub/scripts/check_whitespace_git.sh b/src/stub/scripts/check_whitespace_git.sh index 7caed2c3..69765e50 100755 --- a/src/stub/scripts/check_whitespace_git.sh +++ b/src/stub/scripts/check_whitespace_git.sh @@ -27,7 +27,7 @@ git ls-files --full-name -z | perl -0 -n -e ' if ($ARGV =~ m,(^|/)\.gitmodules$,) { } elsif ($ARGV =~ m,(^|/)(gnu|m)?make(file|vars),i) { } elsif ($ARGV =~ m,/tmp/.*\.(disasm|dump)$,) { } - elsif ($ARGV =~ m,/src/stub/src/arch/.*\.S$,) { } + elsif ($ARGV =~ m,/src/stub/src/arch/.*/lzma.*\.S$,) { } else { print "ERROR: hard TAB detected $ARGV: $_"; exit(1); } } ' || exit 1 diff --git a/src/util.h b/src/util.h index 9d8aff74..0f1aebf2 100644 --- a/src/util.h +++ b/src/util.h @@ -60,14 +60,17 @@ int mem_replace(void *b, int blen, const void *what, int wlen, const void *r); // protect against integer overflows and malicious header fields **************************************************************************/ -size_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra = 0); -size_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n); +upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, + upx_uint64_t extra2 = 0); +upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n); -inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra = 0) { - (void) mem_size(element_size, n, extra); // sanity check +inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, + upx_uint64_t extra2 = 0) { + (void) mem_size(element_size, n, extra1, extra2); // sanity check } -bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra = 0); +bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, + upx_uint64_t extra2 = 0); bool mem_size_valid_bytes(upx_uint64_t bytes); #define New(type, n) new type[mem_size_get_n(sizeof(type), n)]