diff --git a/src/compress_lzma.cpp b/src/compress_lzma.cpp index 4b1c42de..59999a5d 100644 --- a/src/compress_lzma.cpp +++ b/src/compress_lzma.cpp @@ -438,8 +438,10 @@ int upx_lzma_decompress ( const upx_bytep src, unsigned src_len, int r = UPX_E_ERROR; int rh; - if (src_len < 3) + if (src_len < 3) { + r = UPX_E_INPUT_OVERRUN; goto error; + } s.Properties.pb = src[0] & 7; s.Properties.lp = (src[1] >> 4); s.Properties.lc = src[1] & 15; @@ -470,12 +472,15 @@ int upx_lzma_decompress ( const upx_bytep src, unsigned src_len, rh = LzmaDecode(&s, src, src_len, &src_out, dst, *dst_len, &dst_out); assert(src_out <= src_len); assert(dst_out <= *dst_len); - if (rh == 0) - { + if (rh == 0) { r = UPX_E_OK; if (src_out != src_len) r = UPX_E_INPUT_NOT_CONSUMED; } + else if (rh == LZMA_RESULT_INPUT_OVERRUN) + r = UPX_E_INPUT_OVERRUN; + else if (rh == LZMA_RESULT_OUTPUT_OVERRUN) + r = UPX_E_OUTPUT_OVERRUN; error: *dst_len = dst_out; @@ -533,5 +538,26 @@ const char *upx_lzma_version_string(void) #endif } +/************************************************************************* +// doctest checks +**************************************************************************/ + +TEST_CASE("upx_lzma_decompress") { + typedef const upx_byte C; + C *c_data; + upx_byte d_buf[16]; + unsigned d_len; + int r; + + c_data = (C*) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00"; + d_len = 16; + r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr); + CHECK((r == 0 && d_len == 16)); + r = upx_lzma_decompress(c_data, 8, d_buf, &d_len, M_LZMA, nullptr); + CHECK(r == UPX_E_INPUT_OVERRUN); + d_len = 15; + r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr); + CHECK(r == UPX_E_OUTPUT_OVERRUN); +} /* vim:set ts=4 sw=4 et: */ diff --git a/src/compress_ucl.cpp b/src/compress_ucl.cpp index 8fbd136c..7bcd9c84 100644 --- a/src/compress_ucl.cpp +++ b/src/compress_ucl.cpp @@ -286,7 +286,7 @@ unsigned upx_ucl_crc32(const void *buf, unsigned len, unsigned crc) #endif /************************************************************************* -// Debug checks +// doctest checks **************************************************************************/ #if DEBUG && 1 @@ -340,5 +340,42 @@ TEST_CASE("compress_ucl") { #endif // DEBUG +TEST_CASE("upx_ucl_decompress") { + typedef const upx_byte C; + C *c_data; + upx_byte d_buf[16]; + unsigned d_len; + int r; + + c_data = (C*) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff"; + d_len = 16; + r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr); + CHECK((r == 0 && d_len == 16)); + r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2B_8, nullptr); + CHECK(r == UPX_E_INPUT_OVERRUN); + d_len = 15; + r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr); + CHECK(r == UPX_E_OUTPUT_OVERRUN); + + c_data = (C*) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff"; + d_len = 16; + r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr); + CHECK((r == 0 && d_len == 16)); + r = upx_ucl_decompress(c_data, 8, d_buf, &d_len, M_NRV2D_8, nullptr); + CHECK(r == UPX_E_INPUT_OVERRUN); + d_len = 15; + r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr); + CHECK(r == UPX_E_OUTPUT_OVERRUN); + + c_data = (C*) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff"; + d_len = 16; + r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr); + CHECK((r == 0 && d_len == 16)); + r = upx_ucl_decompress(c_data, 8, d_buf, &d_len, M_NRV2E_8, nullptr); + CHECK(r == UPX_E_INPUT_OVERRUN); + d_len = 15; + r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr); + CHECK(r == UPX_E_OUTPUT_OVERRUN); +} /* vim:set ts=4 sw=4 et: */ diff --git a/src/compress_zlib.cpp b/src/compress_zlib.cpp index f1991dc1..2ba67159 100644 --- a/src/compress_zlib.cpp +++ b/src/compress_zlib.cpp @@ -48,8 +48,11 @@ static int convert_errno_from_zlib(int zr) switch (zr) { case Z_OK: return UPX_E_OK; - case Z_DATA_ERROR: return UPX_E_ERROR; case Z_NEED_DICT: return UPX_E_ERROR; + case Z_DATA_ERROR: return UPX_E_ERROR; + case Z_MEM_ERROR: return UPX_E_OUT_OF_MEMORY; + case Z_BUF_ERROR: return UPX_E_OUTPUT_OVERRUN; + case -7: return UPX_E_INPUT_OVERRUN; } return UPX_E_ERROR; } @@ -158,8 +161,11 @@ int upx_zlib_decompress ( const upx_bytep src, unsigned src_len, if (zr != Z_OK) goto error; zr = inflate(&s, Z_FINISH); - if (zr != Z_STREAM_END) + if (zr != Z_STREAM_END) { + if (zr == Z_BUF_ERROR && s.avail_in == 0) + zr = -7; goto error; + } zr = inflateEnd(&s); if (zr != Z_OK) goto error; @@ -244,7 +250,7 @@ unsigned upx_zlib_crc32(const void *buf, unsigned len, unsigned crc) #endif /************************************************************************* -// Debug checks +// doctest checks **************************************************************************/ #if DEBUG && 1 @@ -291,5 +297,22 @@ TEST_CASE("compress_zlib") { #endif // DEBUG +TEST_CASE("upx_zlib_decompress") { + typedef const upx_byte C; + C *c_data; + upx_byte d_buf[16]; + unsigned d_len; + int r; + + c_data = (C*) "\xfb\xff\x1f\x15\x00\x00"; + d_len = 16; + r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr); + CHECK((r == 0 && d_len == 16)); + r = upx_zlib_decompress(c_data, 5, d_buf, &d_len, M_DEFLATE, nullptr); + CHECK(r == UPX_E_INPUT_OVERRUN); + d_len = 15; + r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr); + CHECK(r == UPX_E_OUTPUT_OVERRUN); +} /* vim:set ts=4 sw=4 et: */