diff --git a/source/Irrlicht/CImageLoaderBMP.cpp b/source/Irrlicht/CImageLoaderBMP.cpp index 16e862ec..358f7b80 100644 --- a/source/Irrlicht/CImageLoaderBMP.cpp +++ b/source/Irrlicht/CImageLoaderBMP.cpp @@ -45,20 +45,32 @@ bool CImageLoaderBMP::isALoadableFileFormat(io::IReadFile* file) const return headerID == 0x4d42; } +// UB-safe overflow check +static inline bool overflowCheck(const void *base, size_t offset, const void *end) +{ + auto baseI = reinterpret_cast(base), + endI = reinterpret_cast(end); + return baseI > endI || offset >= (endI - baseI); +} +// check whether &p[0] to &p[_off - 1] can be accessed +#define CHECKP(_off) if ((_off) < 0 || overflowCheck(p, _off, pEnd)) goto exit +// same for d +#define CHECKD(_off) if ((_off) < 0 || overflowCheck(d, _off, destEnd)) goto exit void CImageLoaderBMP::decompress8BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const { u8* p = bmpData; + const u8* pEnd = bmpData + size; u8* newBmp = new u8[(width+pitch)*height]; u8* d = newBmp; - u8* destEnd = newBmp + (width+pitch)*height; + const u8* destEnd = newBmp + (width+pitch)*height; s32 line = 0; - while (bmpData - p < size && d < destEnd) + while (p < pEnd && d < destEnd) { if (*p == 0) { - ++p; + ++p; CHECKP(1); switch(*p) { @@ -68,29 +80,28 @@ void CImageLoaderBMP::decompress8BitRLE(u8*& bmpData, s32 size, s32 width, s32 h d = newBmp + (line*(width+pitch)); break; case 1: // end of bmp - delete [] bmpData; - bmpData = newBmp; - return; + goto exit; case 2: - ++p; d +=(u8)*p; // delta - ++p; d += ((u8)*p)*(width+pitch); - ++p; + ++p; CHECKP(2); + d += (u8)*p; ++p; // delta + d += ((u8)*p)*(width+pitch); ++p; break; default: { // absolute mode s32 count = (u8)*p; ++p; s32 readAdditional = ((2-(count%2))%2); - s32 i; - for (i=0; i> readShift) & 0x0f; readShift -= 4; if (readShift < 0) { - ++*p; + ++*p; // <- bug? readShift = 4; } @@ -179,7 +202,8 @@ void CImageLoaderBMP::decompress4BitRLE(u8*& bmpData, s32 size, s32 width, s32 h } - for (i=0; i> 4) & 0x0f; ++p; + CHECKD(shiftedCount(count, shift)); for (s32 i=0; i