diff --git a/src/conf.h b/src/conf.h index 3725036e..4c852e58 100644 --- a/src/conf.h +++ b/src/conf.h @@ -631,7 +631,7 @@ struct upx_compress_result_t // globals **************************************************************************/ -#include "snprintf.h" +#include "snprintf.h" // must get included first! #include "stdcxx.h" #include "options.h" #include "except.h" diff --git a/src/mem.cpp b/src/mem.cpp index 920e2994..e0e97eb9 100644 --- a/src/mem.cpp +++ b/src/mem.cpp @@ -30,65 +30,6 @@ #include "mem.h" -/************************************************************************* -// assert sane memory buffer sizes to protect against integer overflows -// and malicious header fields -**************************************************************************/ - -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) - -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 > 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); -} - -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(upx_rsize_t, n); // return n -} - -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 > 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 > UPX_RSIZE_MAX) return false; - return true; -} - - -int ptr_diff(const void *p1, const void *p2) -{ - assert(p1 != NULL); - assert(p2 != NULL); - ptrdiff_t d = (const char *)p1 - (const char *)p2; - if (p1 >= p2) - assert(mem_size_valid_bytes(d)); - else - assert(mem_size_valid_bytes(-d)); - return ACC_ICONV(int, d); -} - - /************************************************************************* // bool use_simple_mcheck() **************************************************************************/ diff --git a/src/pefile.cpp b/src/pefile.cpp index 791080ad..6347b800 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -614,7 +614,7 @@ class PeFile::ImportLinker : public ElfLinkerAMD64 unsigned len = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1; tstr dlln(name_for_dll(dll, first_char)); char *procn = New(char, len); - upx_snprintf(procn, len - 1, "%s%c", (const char*) dlln, separator); + upx_snprintf(procn, len, "%s%c", (const char*) dlln, separator); encode_name(proc, procn + strlen(procn)); return procn; } diff --git a/src/snprintf.cpp b/src/snprintf.cpp index ae84d7c0..13cfcdb7 100644 --- a/src/snprintf.cpp +++ b/src/snprintf.cpp @@ -745,35 +745,35 @@ static size_t dopr(char *buffer, size_t maxsize, const char *format, va_list arg **************************************************************************/ // UPX version with assertions -int upx_vsnprintf(char *str, size_t count, const char *format, va_list ap) { +int upx_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap) { size_t size; // preconditions - assert(count <= UPX_RSIZE_MAX_STR); + assert(max_size <= UPX_RSIZE_MAX_STR); if (str != NULL) - assert(count > 0); + assert(max_size > 0); else - assert(count == 0); + assert(max_size == 0); - size = dopr(str, count, format, ap); + size = dopr(str, max_size, format, ap); // postconditions assert(size > 0); assert(size <= UPX_RSIZE_MAX_STR); if (str != NULL) { - assert(size <= count); + assert(size <= max_size); assert(str[size - 1] == '\0'); } return ACC_ICONV(int, size - 1); // snprintf() returns length, not size } -int __acc_cdecl_va upx_snprintf(char *str, size_t count, const char *format, ...) { +int __acc_cdecl_va upx_snprintf(char *str, upx_rsize_t max_size, const char *format, ...) { va_list ap; int len; va_start(ap, format); - len = upx_vsnprintf(str, count, format, ap); + len = upx_vsnprintf(str, max_size, format, ap); va_end(ap); return len; } diff --git a/src/snprintf.h b/src/snprintf.h index a795577c..e159452d 100644 --- a/src/snprintf.h +++ b/src/snprintf.h @@ -28,31 +28,50 @@ #ifndef __UPX_SNPRINTF_H #define __UPX_SNPRINTF_H 1 -#ifdef __cplusplus -extern "C" { -#endif - /************************************************************************* // **************************************************************************/ -int upx_vsnprintf(char *str, size_t count, const char *format, va_list ap); -int __acc_cdecl_va upx_snprintf (char *str, size_t count, const char *format, ...); +#ifdef __cplusplus +extern "C" { +#endif + +// info: snprintf() returns length and NOT size, but max_size is indeed size (incl NUL) +int upx_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap); +int __acc_cdecl_va upx_snprintf (char *str, upx_rsize_t max_size, const char *format, ...); int upx_vasprintf(char **ptr, const char *format, va_list ap); int __acc_cdecl_va upx_asprintf (char **ptr, const char *format, ...); -#undef sprintf -#define sprintf error_sprintf_is_dangerous_use_snprintf - upx_rsize_t upx_strlen(const char *); -#undef strlen -#define strlen upx_strlen - #ifdef __cplusplus } #endif +// globally redirect some functions +#undef sprintf +#define sprintf error_sprintf_is_dangerous_use_snprintf +#undef strlen +#define strlen upx_strlen + +/************************************************************************* +// some unsigned char string support functions +**************************************************************************/ + +inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) { + return (unsigned char *) strcpy((char *) s1, (const char *) s2); +} + +inline int strcmp(const unsigned char *s1, const unsigned char *s2) { + return strcmp((const char *) s1, (const char *) s2); +} + +inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) { + return strcasecmp((const char *) s1, (const char *) s2); +} + +inline size_t strlen(const unsigned char *s) { return strlen((const char *) s); } + #endif /* already included */ /* vim:set ts=4 sw=4 et: */ diff --git a/src/util.cpp b/src/util.cpp index 9b7888ed..bb75fbb1 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -46,6 +46,72 @@ #include "miniacc.h" +/************************************************************************* +// assert sane memory buffer sizes to protect against integer overflows +// and malicious header fields +**************************************************************************/ + +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) + +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 > 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); +} + +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(upx_rsize_t, n); // return n +} + +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 > 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 > UPX_RSIZE_MAX) return false; + return true; +} + + +int ptr_diff(const void *p1, const void *p2) +{ + assert(p1 != NULL); + assert(p2 != NULL); + ptrdiff_t d = (const char *)p1 - (const char *)p2; + if (p1 >= p2) + assert(mem_size_valid_bytes(d)); + else + assert(mem_size_valid_bytes(-d)); + return ACC_ICONV(int, d); +} + +unsigned ptr_udiff(const void *p1, const void *p2) +{ + int d = ptr_diff(p1, p2); + assert(d >= 0); + return ACC_ICONV(unsigned, d); +} + + /************************************************************************* // bele.h **************************************************************************/ diff --git a/src/util.h b/src/util.h index e3e98d3d..c28884d6 100644 --- a/src/util.h +++ b/src/util.h @@ -28,6 +28,28 @@ #ifndef __UPX_UTIL_H #define __UPX_UTIL_H 1 +/************************************************************************* +// protect against integer overflows and malicious header fields +**************************************************************************/ + +#define New(type, n) new type[mem_size_get_n(sizeof(type), 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 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 extra1 = 0, + upx_uint64_t extra2 = 0); +bool mem_size_valid_bytes(upx_uint64_t bytes); + +int ptr_diff(const void *p1, const void *p2); +unsigned ptr_udiff(const void *p1, const void *p2); // asserts p1 >= p2 + /************************************************************************* // misc. support functions **************************************************************************/ @@ -56,52 +78,6 @@ int find_le64(const void *b, int blen, upx_uint64_t what); int mem_replace(void *b, int blen, const void *what, int wlen, const void *r); -/************************************************************************* -// protect against integer overflows and malicious header fields -**************************************************************************/ - -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 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 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)] - -int ptr_diff(const void *p1, const void *p2); - -template -inline unsigned ptr_udiff(const T1 &p1, const T2 &p2) { - int d = ptr_diff(p1, p2); - assert(d >= 0); - return ACC_ICONV(unsigned, d); -} - -/************************************************************************* -// some unsigned char string support functions -**************************************************************************/ - -inline char *strcpy(unsigned char *s1, const unsigned char *s2) { - return strcpy((char *) s1, (const char *) s2); -} - -inline int strcmp(const unsigned char *s1, const unsigned char *s2) { - return strcmp((const char *) s1, (const char *) s2); -} - -inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) { - return strcasecmp((const char *) s1, (const char *) s2); -} - -inline size_t strlen(const unsigned char *s) { return strlen((const char *) s); } - #endif /* already included */ /* vim:set ts=4 sw=4 et: */