mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
src/bele.h: try to detect possible size-mismatches
This commit is contained in:
parent
25a3c109c1
commit
d65fea1147
154
src/bele.h
154
src/bele.h
|
@ -42,39 +42,103 @@
|
|||
#define bswap64 upx_bswap64
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// XE - eXtended Endian compatibility
|
||||
// try to detect XX16 vs XX32 vs XX64 size mismatches
|
||||
**************************************************************************/
|
||||
|
||||
#if 0 // permissive version using "void *"
|
||||
|
||||
#define REQUIRE_XE16 /*empty*/
|
||||
#define REQUIRE_XE24 /*empty*/
|
||||
#define REQUIRE_XE32 /*empty*/
|
||||
#define REQUIRE_XE64 /*empty*/
|
||||
typedef void XE16;
|
||||
typedef void XE24;
|
||||
typedef void XE32;
|
||||
typedef void XE64;
|
||||
|
||||
#else // permissive version
|
||||
|
||||
// forward declarations
|
||||
struct BE16;
|
||||
struct BE32;
|
||||
struct BE64;
|
||||
struct LE16;
|
||||
struct LE32;
|
||||
struct LE64;
|
||||
|
||||
// Note:
|
||||
// void is explicitly allowed, but there is no automatic pointer conversion because of template
|
||||
// char is explicitly allowed
|
||||
// byte is explicitly allowed
|
||||
template <class T>
|
||||
static inline constexpr bool is_xe16_type =
|
||||
upx::is_same_any_v<T, void, char, byte, upx_int16_t, upx_uint16_t, BE16, LE16>;
|
||||
template <class T>
|
||||
static inline constexpr bool is_xe24_type = upx::is_same_any_v<T, void, char, byte>;
|
||||
template <class T>
|
||||
static inline constexpr bool is_xe32_type =
|
||||
upx::is_same_any_v<T, void, char, byte, upx_int32_t, upx_uint32_t, BE32, LE32>;
|
||||
template <class T>
|
||||
static inline constexpr bool is_xe64_type =
|
||||
upx::is_same_any_v<T, void, char, byte, upx_int64_t, upx_uint64_t, BE64, LE64>;
|
||||
|
||||
template <class T>
|
||||
using enable_if_xe16 = std::enable_if_t<is_xe16_type<T>, T>;
|
||||
template <class T>
|
||||
using enable_if_xe24 = std::enable_if_t<is_xe24_type<T>, T>;
|
||||
template <class T>
|
||||
using enable_if_xe32 = std::enable_if_t<is_xe32_type<T>, T>;
|
||||
template <class T>
|
||||
using enable_if_xe64 = std::enable_if_t<is_xe64_type<T>, T>;
|
||||
|
||||
#define REQUIRE_XE16 template <class XE16, class = enable_if_xe16<XE16> >
|
||||
#define REQUIRE_XE24 template <class XE24, class = enable_if_xe24<XE24> >
|
||||
#define REQUIRE_XE32 template <class XE32, class = enable_if_xe32<XE32> >
|
||||
#define REQUIRE_XE64 template <class XE64, class = enable_if_xe64<XE64> >
|
||||
|
||||
#endif // permissive version
|
||||
|
||||
/*************************************************************************
|
||||
// core - NE
|
||||
**************************************************************************/
|
||||
|
||||
static forceinline unsigned get_ne16(const void *p) noexcept {
|
||||
REQUIRE_XE16
|
||||
static forceinline unsigned get_ne16(const XE16 *p) noexcept {
|
||||
upx_uint16_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline unsigned get_ne32(const void *p) noexcept {
|
||||
REQUIRE_XE32
|
||||
static forceinline unsigned get_ne32(const XE32 *p) noexcept {
|
||||
upx_uint32_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline upx_uint64_t get_ne64(const void *p) noexcept {
|
||||
REQUIRE_XE64
|
||||
static forceinline upx_uint64_t get_ne64(const XE64 *p) noexcept {
|
||||
upx_uint64_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline void set_ne16(void *p, unsigned vv) noexcept {
|
||||
REQUIRE_XE16
|
||||
static forceinline void set_ne16(XE16 *p, unsigned vv) noexcept {
|
||||
upx_uint16_t v = (upx_uint16_t) (vv & 0xffff);
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
|
||||
static forceinline void set_ne32(void *p, unsigned vv) noexcept {
|
||||
REQUIRE_XE32
|
||||
static forceinline void set_ne32(XE32 *p, unsigned vv) noexcept {
|
||||
upx_uint32_t v = vv;
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
|
||||
static forceinline void set_ne64(void *p, upx_uint64_t vv) noexcept {
|
||||
REQUIRE_XE64
|
||||
static forceinline void set_ne64(XE64 *p, upx_uint64_t vv) noexcept {
|
||||
upx_uint64_t v = vv;
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
|
@ -138,41 +202,58 @@ static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept {
|
|||
// get/set 16/32/64
|
||||
**************************************************************************/
|
||||
|
||||
inline unsigned get_be16(const void *p) noexcept { return ne16_to_be16(get_ne16(p)); }
|
||||
inline unsigned get_be32(const void *p) noexcept { return ne32_to_be32(get_ne32(p)); }
|
||||
inline upx_uint64_t get_be64(const void *p) noexcept { return ne64_to_be64(get_ne64(p)); }
|
||||
inline unsigned get_le16(const void *p) noexcept { return ne16_to_le16(get_ne16(p)); }
|
||||
inline unsigned get_le32(const void *p) noexcept { return ne32_to_le32(get_ne32(p)); }
|
||||
inline upx_uint64_t get_le64(const void *p) noexcept { return ne64_to_le64(get_ne64(p)); }
|
||||
inline void set_be16(void *p, unsigned v) noexcept { set_ne16(p, ne16_to_be16(v)); }
|
||||
inline void set_be32(void *p, unsigned v) noexcept { set_ne32(p, ne32_to_be32(v)); }
|
||||
inline void set_be64(void *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_be64(v)); }
|
||||
inline void set_le16(void *p, unsigned v) noexcept { set_ne16(p, ne16_to_le16(v)); }
|
||||
inline void set_le32(void *p, unsigned v) noexcept { set_ne32(p, ne32_to_le32(v)); }
|
||||
inline void set_le64(void *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_le64(v)); }
|
||||
REQUIRE_XE16
|
||||
inline unsigned get_be16(const XE16 *p) noexcept { return ne16_to_be16(get_ne16(p)); }
|
||||
REQUIRE_XE32
|
||||
inline unsigned get_be32(const XE32 *p) noexcept { return ne32_to_be32(get_ne32(p)); }
|
||||
REQUIRE_XE64
|
||||
inline upx_uint64_t get_be64(const XE64 *p) noexcept { return ne64_to_be64(get_ne64(p)); }
|
||||
REQUIRE_XE16
|
||||
inline unsigned get_le16(const XE16 *p) noexcept { return ne16_to_le16(get_ne16(p)); }
|
||||
REQUIRE_XE32
|
||||
inline unsigned get_le32(const XE32 *p) noexcept { return ne32_to_le32(get_ne32(p)); }
|
||||
REQUIRE_XE64
|
||||
inline upx_uint64_t get_le64(const XE64 *p) noexcept { return ne64_to_le64(get_ne64(p)); }
|
||||
|
||||
REQUIRE_XE16
|
||||
inline void set_be16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_be16(v)); }
|
||||
REQUIRE_XE32
|
||||
inline void set_be32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_be32(v)); }
|
||||
REQUIRE_XE64
|
||||
inline void set_be64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_be64(v)); }
|
||||
REQUIRE_XE16
|
||||
inline void set_le16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_le16(v)); }
|
||||
REQUIRE_XE32
|
||||
inline void set_le32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_le32(v)); }
|
||||
REQUIRE_XE64
|
||||
inline void set_le64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_le64(v)); }
|
||||
|
||||
/*************************************************************************
|
||||
// get/set 24/26
|
||||
**************************************************************************/
|
||||
|
||||
inline unsigned get_be24(const void *p) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline unsigned get_be24(const XE24 *p) noexcept {
|
||||
const byte *b = ACC_CCAST(const byte *, p);
|
||||
return (b[0] << 16) | (b[1] << 8) | (b[2] << 0);
|
||||
}
|
||||
|
||||
inline unsigned get_le24(const void *p) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline unsigned get_le24(const XE24 *p) noexcept {
|
||||
const byte *b = ACC_CCAST(const byte *, p);
|
||||
return (b[0] << 0) | (b[1] << 8) | (b[2] << 16);
|
||||
}
|
||||
|
||||
inline void set_be24(void *p, unsigned v) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline void set_be24(XE24 *p, unsigned v) noexcept {
|
||||
byte *b = ACC_PCAST(byte *, p);
|
||||
b[0] = ACC_ICONV(byte, (v >> 16) & 0xff);
|
||||
b[1] = ACC_ICONV(byte, (v >> 8) & 0xff);
|
||||
b[2] = ACC_ICONV(byte, (v >> 0) & 0xff);
|
||||
}
|
||||
|
||||
inline void set_le24(void *p, unsigned v) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline void set_le24(XE24 *p, unsigned v) noexcept {
|
||||
byte *b = ACC_PCAST(byte *, p);
|
||||
b[0] = ACC_ICONV(byte, (v >> 0) & 0xff);
|
||||
b[1] = ACC_ICONV(byte, (v >> 8) & 0xff);
|
||||
|
@ -201,56 +282,64 @@ inline void set_le14_5(void *p, unsigned v) noexcept {
|
|||
// get signed values
|
||||
**************************************************************************/
|
||||
|
||||
static forceinline int sign_extend(unsigned v, unsigned bits) noexcept {
|
||||
static forceinline constexpr int sign_extend(unsigned v, unsigned bits) noexcept {
|
||||
const unsigned sign_bit = 1u << (bits - 1);
|
||||
v &= sign_bit | (sign_bit - 1);
|
||||
v |= 0u - (v & sign_bit);
|
||||
return ACC_ICAST(int, v);
|
||||
}
|
||||
|
||||
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept {
|
||||
static forceinline constexpr upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept {
|
||||
const upx_uint64_t sign_bit = 1ull << (bits - 1);
|
||||
v &= sign_bit | (sign_bit - 1);
|
||||
v |= 0ull - (v & sign_bit);
|
||||
return ACC_ICAST(upx_int64_t, v);
|
||||
}
|
||||
|
||||
inline int get_be16_signed(const void *p) noexcept {
|
||||
REQUIRE_XE16
|
||||
inline int get_be16_signed(const XE16 *p) noexcept {
|
||||
unsigned v = get_be16(p);
|
||||
return sign_extend(v, 16);
|
||||
}
|
||||
|
||||
inline int get_be24_signed(const void *p) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline int get_be24_signed(const XE24 *p) noexcept {
|
||||
unsigned v = get_be24(p);
|
||||
return sign_extend(v, 24);
|
||||
}
|
||||
|
||||
inline int get_be32_signed(const void *p) noexcept {
|
||||
REQUIRE_XE32
|
||||
inline int get_be32_signed(const XE32 *p) noexcept {
|
||||
unsigned v = get_be32(p);
|
||||
return sign_extend(v, 32);
|
||||
}
|
||||
|
||||
inline upx_int64_t get_be64_signed(const void *p) noexcept {
|
||||
REQUIRE_XE64
|
||||
inline upx_int64_t get_be64_signed(const XE64 *p) noexcept {
|
||||
upx_uint64_t v = get_be64(p);
|
||||
return sign_extend(v, 64);
|
||||
}
|
||||
|
||||
inline int get_le16_signed(const void *p) noexcept {
|
||||
REQUIRE_XE16
|
||||
inline int get_le16_signed(const XE16 *p) noexcept {
|
||||
unsigned v = get_le16(p);
|
||||
return sign_extend(v, 16);
|
||||
}
|
||||
|
||||
inline int get_le24_signed(const void *p) noexcept {
|
||||
REQUIRE_XE24
|
||||
inline int get_le24_signed(const XE24 *p) noexcept {
|
||||
unsigned v = get_le24(p);
|
||||
return sign_extend(v, 24);
|
||||
}
|
||||
|
||||
inline int get_le32_signed(const void *p) noexcept {
|
||||
REQUIRE_XE32
|
||||
inline int get_le32_signed(const XE32 *p) noexcept {
|
||||
unsigned v = get_le32(p);
|
||||
return sign_extend(v, 32);
|
||||
}
|
||||
|
||||
inline upx_int64_t get_le64_signed(const void *p) noexcept {
|
||||
REQUIRE_XE64
|
||||
inline upx_int64_t get_le64_signed(const XE64 *p) noexcept {
|
||||
upx_uint64_t v = get_le64(p);
|
||||
return sign_extend(v, 64);
|
||||
}
|
||||
|
@ -633,6 +722,7 @@ inline unsigned ALIGN_DOWN(const LE32 &a, unsigned b) { return ALIGN_DOWN(unsign
|
|||
inline unsigned ALIGN_UP(unsigned a, const LE32 &b) { return ALIGN_UP(a, unsigned(b)); }
|
||||
inline unsigned ALIGN_UP(const LE32 &a, unsigned b) { return ALIGN_UP(unsigned(a), b); }
|
||||
|
||||
// TODO: introduce upx::umax() and upx::umin()
|
||||
inline unsigned UPX_MAX(unsigned a, const BE16 &b) { return UPX_MAX(a, unsigned(b)); }
|
||||
inline unsigned UPX_MAX(const BE16 &a, unsigned b) { return UPX_MAX(unsigned(a), b); }
|
||||
inline unsigned UPX_MIN(unsigned a, const BE16 &b) { return UPX_MIN(a, unsigned(b)); }
|
||||
|
|
|
@ -113,6 +113,17 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(bswap64(0xf8f7f6f5f4f3f2f1ull)) ==
|
|||
no_bswap64(0xf8f7f6f5f4f3f2f1ull))
|
||||
#endif
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 0, 8) == 0)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 1, 8) == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 127, 8) == 127)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 128, 8) == -128)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u - 1, 8) == -1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 256, 8) == 0)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 257, 8) == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 383, 8) == 127)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 384, 8) == -128)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 511, 8) == -1)
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8)
|
||||
#if 0 // does not work with MSVC
|
||||
#if '\0' - 1 < 0
|
||||
|
|
|
@ -109,8 +109,7 @@ inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
|
|||
// protect against integer overflows and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
//
|
||||
// this limits uncompressed_size to about 640 MiB which is perfectly fine:
|
||||
// "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-)
|
||||
// this limits uncompressed_size to about 682 MiB (715_128_832 bytes)
|
||||
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 !!!
|
||||
|
|
|
@ -321,8 +321,11 @@ TEST_CASE("MemBuffer::getSizeForCompression") {
|
|||
CHECK(MemBuffer::getSizeForCompression(1024 * 1024) == 1180160); // 0x00100000
|
||||
CHECK(MemBuffer::getSizeForCompression(64 * 1024 * 1024) == 75497984); // 0x04000000
|
||||
CHECK(MemBuffer::getSizeForCompression(512 * 1024 * 1024) == 603980288); // 0x20000000
|
||||
// "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-)
|
||||
CHECK(MemBuffer::getSizeForCompression(640 * 1024 * 1024) == 754975232); // 0x28000000
|
||||
// "682 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 2023 ;-)
|
||||
CHECK(MemBuffer::getSizeForCompression(682 * 1024 * 1024) == 804520448); // 0x2aa00000
|
||||
CHECK(MemBuffer::getSizeForCompression(715827428) == UPX_RSIZE_MAX); // 0x2aaaa8e4
|
||||
CHECK_THROWS(MemBuffer::getSizeForCompression(715827428 + 1)); // 0x2aaaa8e4 + 1
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
|
|
@ -43,8 +43,7 @@
|
|||
// and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
//
|
||||
// this limits uncompressed_size to about 640 MiB which is perfectly fine:
|
||||
// "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-)
|
||||
// this limits uncompressed_size to about 682 MiB (715_128_832 bytes)
|
||||
**************************************************************************/
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX)
|
||||
|
|
Loading…
Reference in New Issue
Block a user