Fix wxURI::IsReference() description The documentation described the inverse of the name of the function and what it actually did, fix it to describe the actual function behaviour. Closes #26520.
Fix one-byte over-read in IFF decomprle replicate packet The replicate-run branch reads the packet's data byte after only checking that one source byte remains, but it consumes two (the control byte plus the data byte). A BODY ending in a lone replicate control byte then reads one byte past the input buffer. Require two bytes left, matching the literal-run check above. Closes #26518.
Fix buffer overflow when loading invalid message catalogs Avoid integer overflow in message catalog StringAtOfs() bounds check: StringAtOfs() read ofsString and nLen from the .mo file and checked ofsString + nLen against the data length, but both are 32-bit so the sum wraps and a translated entry declaring nLen 0xffffffff passes the check; FillHash() then scans past the end of the catalog. Compute the offset as a 64-bit value so the addition can't overflow and result in an invalid index into the buffer. Add a test feeding such a catalog through wxMsgCatalog::CreateFromData(). Closes #26513.
Fix buffer overflow on invalid width in wxXPMDecoder Fix integer overflow in wxXPMDecoder::ReadData() when computing width*chars_per_pixel: a header with a (very) large width could result in wrapping around and result in reasonable but yet invalid value, which could let the key-reading loop run off the end of the buffer. Compute the product in 64-bits to avoid the overflow. Closes #26519.
Fix data-size bound check past LIST chunk in wxSound::LoadWAV() The check compared ul against length minus the fixed offset FMT_INDEX + uiSize + 16, which equals data_offset + 8 only when no LIST chunk is present. When a LIST chunk is present data_offset has already been advanced past it, so a crafted WAV can pass this check with ul larger than the bytes that actually follow the data-chunk header, and the OSS/SDL playback paths then read past m_dataWithHeader. Use data_offset directly so the same constraint holds either way. Closes #26525.
| ... | ... | @@ -259,8 +259,8 @@ public: |
| 259 | 259 | bool IsEmpty() const;
|
| 260 | 260 | |
| 261 | 261 | /**
|
| 262 | - Returns @true if a valid [absolute] URI, otherwise this URI is a URI
|
|
| 263 | - reference and not a full URI, and this function returns @false.
|
|
| 262 | + Returns @false if a valid [absolute] URI, otherwise this URI is a URI
|
|
| 263 | + reference and not a full URI, and this function returns @true.
|
|
| 264 | 264 | */
|
| 265 | 265 | bool IsReference() const;
|
| 266 | 266 |
| ... | ... | @@ -276,7 +276,7 @@ static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen) |
| 276 | 276 | |
| 277 | 277 | else if (codeByte > 0x80) {
|
| 278 | 278 | codeByte = 0x81 - (codeByte & 0x7f);
|
| 279 | - if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
|
|
| 279 | + if ((slen > (long) 1) && (dlen >= (long) codeByte)) {
|
|
| 280 | 280 | dataByte = *sptr++;
|
| 281 | 281 | slen -= 2;
|
| 282 | 282 | dlen -= codeByte;
|
| ... | ... | @@ -873,7 +873,7 @@ private: |
| 873 | 873 | const wxMsgTableEntry * const ent = pTable + n;
|
| 874 | 874 | |
| 875 | 875 | // this check could fail for a corrupt message catalog
|
| 876 | - size_t32 ofsString = Swap(ent->ofsString);
|
|
| 876 | + wxULongLong_t ofsString = Swap(ent->ofsString);
|
|
| 877 | 877 | if ( ofsString + Swap(ent->nLen) > m_data.length())
|
| 878 | 878 | {
|
| 879 | 879 | return nullptr;
|
| ... | ... | @@ -787,7 +787,8 @@ wxImage wxXPMDecoder::ReadData(const char* const* xpm_data) |
| 787 | 787 | for (i = 0; i < width; i++, img_data += 3)
|
| 788 | 788 | {
|
| 789 | 789 | const char *xpmImgLine = xpm_data[1 + colors_cnt + j];
|
| 790 | - if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel )
|
|
| 790 | + if ( !xpmImgLine ||
|
|
| 791 | + strlen(xpmImgLine) < (unsigned long long)width*chars_per_pixel )
|
|
| 791 | 792 | {
|
| 792 | 793 | wxLogError(_("XPM: truncated image data at line %d!"),
|
| 793 | 794 | (int)(1 + colors_cnt + j));
|
| ... | ... | @@ -714,8 +714,10 @@ bool wxSound::LoadWAV(const void* data_, size_t length, bool copyData) |
| 714 | 714 | memcpy(&ul, &data[data_offset + 4u], 4);
|
| 715 | 715 | ul = wxUINT32_SWAP_ON_BE(ul);
|
| 716 | 716 | |
| 717 | - // ensure we actually have at least that much data in the input
|
|
| 718 | - if (ul > length - FMT_INDEX - waveformat.uiSize - 16)
|
|
| 717 | + // ensure we actually have at least that much data in the input; use
|
|
| 718 | + // data_offset rather than the fixed FMT_INDEX + uiSize + 16 expression
|
|
| 719 | + // so that an optional LIST chunk is accounted for here as well.
|
|
| 720 | + if (ul > length - data_offset - 8u)
|
|
| 719 | 721 | return false;
|
| 720 | 722 | |
| 721 | 723 | m_data = new wxSoundData;
|
| ... | ... | @@ -1542,6 +1542,27 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadXPMUnterminatedQuote", |
| 1542 | 1542 | REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_XPM) );
|
| 1543 | 1543 | }
|
| 1544 | 1544 | |
| 1545 | +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadXPMWidthOverflow",
|
|
| 1546 | + "[image][xpm][error]")
|
|
| 1547 | +{
|
|
| 1548 | + // width * chars_per_pixel was computed in 32-bit unsigned in
|
|
| 1549 | + // wxXPMDecoder::ReadData() and used to check that each image line is long
|
|
| 1550 | + // enough, but the per-pixel index uses size_t arithmetic. With width =
|
|
| 1551 | + // 68174085 and chars_per_pixel = 63 the product is 4 294 967 355, which
|
|
| 1552 | + // wraps to 59, so a one-pixel image line passes the length check and the
|
|
| 1553 | + // key-reading loop then runs off the end of the buffer. Loading such a
|
|
| 1554 | + // file must be rejected.
|
|
| 1555 | + const std::string key(63, 'a');
|
|
| 1556 | + const std::string xpm =
|
|
| 1557 | + "/* XPM */\n"
|
|
| 1558 | + "\"68174085 1 1 63\"\n"
|
|
| 1559 | + "\"" + key + " c #ffffff\"\n"
|
|
| 1560 | + "\"" + key + "\"\n";
|
|
| 1561 | + wxMemoryInputStream mis(xpm.data(), xpm.size());
|
|
| 1562 | + wxImage img;
|
|
| 1563 | + REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_XPM) );
|
|
| 1564 | +}
|
|
| 1565 | + |
|
| 1545 | 1566 | #endif // wxUSE_XPM
|
| 1546 | 1567 | |
| 1547 | 1568 | #if wxUSE_IFF
|
| ... | ... | @@ -1649,6 +1670,43 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadIFFBodyTruncated", |
| 1649 | 1670 | REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_IFF) );
|
| 1650 | 1671 | }
|
| 1651 | 1672 | |
| 1673 | +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadIFFRLEBody",
|
|
| 1674 | + "[image][iff][error]")
|
|
| 1675 | +{
|
|
| 1676 | + // A run-length encoded (compression == 1) BODY whose data is a single
|
|
| 1677 | + // replicate control byte (0xFF) with no following data byte. decomprle()
|
|
| 1678 | + // only checked that one source byte remained before reading the replicate
|
|
| 1679 | + // packet's data byte, so it read bodyptr[1], one byte past the end of the
|
|
| 1680 | + // heap-allocated input buffer. transparentColor = 0x4000 makes
|
|
| 1681 | + // ConvertToImage() reject the result so the load fails with the fix.
|
|
| 1682 | + wxImage::AddHandler(new wxIFFHandler);
|
|
| 1683 | + |
|
| 1684 | + static const unsigned char data[] =
|
|
| 1685 | + {
|
|
| 1686 | + 0x46,0x4f,0x52,0x4d, // "FORM"
|
|
| 1687 | + 0x00,0x00,0x00,0x29, // FORM length (not validated)
|
|
| 1688 | + 0x49,0x4c,0x42,0x4d, // "ILBM"
|
|
| 1689 | + 0x42,0x4d,0x48,0x44, // "BMHD"
|
|
| 1690 | + 0x00,0x00,0x00,0x14, // BMHD chunk length = 20
|
|
| 1691 | + 0x00,0x08, // width = 8
|
|
| 1692 | + 0x00,0x01, // height = 1
|
|
| 1693 | + 0x00,0x00,0x00,0x00, // x, y
|
|
| 1694 | + 0x01, // nPlanes
|
|
| 1695 | + 0x00, // masking
|
|
| 1696 | + 0x01, // compression = 1 (RLE)
|
|
| 1697 | + 0x00, // pad
|
|
| 1698 | + 0x40,0x00, // transparentColor = 0x4000
|
|
| 1699 | + 0x00,0x00, // x/y aspect
|
|
| 1700 | + 0x00,0x00,0x00,0x00, // page width / height
|
|
| 1701 | + 0x42,0x4f,0x44,0x59, // "BODY"
|
|
| 1702 | + 0x00,0x00,0x00,0x64, // BODY chunk length = 100 (lie)
|
|
| 1703 | + 0xff, // lone replicate control byte
|
|
| 1704 | + };
|
|
| 1705 | + wxMemoryInputStream mis(data, WXSIZEOF(data));
|
|
| 1706 | + wxImage img;
|
|
| 1707 | + REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_IFF) );
|
|
| 1708 | +}
|
|
| 1709 | + |
|
| 1652 | 1710 | #endif // wxUSE_IFF
|
| 1653 | 1711 | |
| 1654 | 1712 | TEST_CASE_METHOD(ImageHandlersInit, "wxImage::DibPadding", "[image]")
|
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | #endif // WX_PRECOMP
|
| 19 | 19 | |
| 20 | 20 | #include "wx/intl.h"
|
| 21 | +#include "wx/translation.h"
|
|
| 21 | 22 | #include "wx/uilocale.h"
|
| 22 | 23 | #include "wx/scopeguard.h"
|
| 23 | 24 | |
| ... | ... | @@ -291,6 +292,46 @@ TEST_CASE("wxTranslations::AddCatalog", "[translations]") |
| 291 | 292 | }
|
| 292 | 293 | }
|
| 293 | 294 | |
| 295 | +TEST_CASE("wxTranslations::CorruptCatalog", "[translations]")
|
|
| 296 | +{
|
|
| 297 | + // Build a minimal MO catalog with two strings whose second translated
|
|
| 298 | + // entry declares a length of 0xffffffff. Adding this to the (valid) string
|
|
| 299 | + // offset wraps around in 32-bit arithmetic and used to defeat the bounds
|
|
| 300 | + // check in StringAtOfs(), letting FillHash() read past the end of the data.
|
|
| 301 | + //
|
|
| 302 | + // The catalog is 64 bytes; the backing array has one extra byte because
|
|
| 303 | + // wxCharTypeBuffer copies len+1 bytes (it assumes a trailing NUL).
|
|
| 304 | + const size_t moLen = 64;
|
|
| 305 | + unsigned char mo[moLen + 1];
|
|
| 306 | + memset(mo, 0, sizeof(mo));
|
|
| 307 | + |
|
| 308 | + auto put32 = [](unsigned char* p, wxUint32 v)
|
|
| 309 | + {
|
|
| 310 | + p[0] = (unsigned char)(v & 0xff);
|
|
| 311 | + p[1] = (unsigned char)((v >> 8) & 0xff);
|
|
| 312 | + p[2] = (unsigned char)((v >> 16) & 0xff);
|
|
| 313 | + p[3] = (unsigned char)((v >> 24) & 0xff);
|
|
| 314 | + };
|
|
| 315 | + |
|
| 316 | + put32(mo + 0, 0x950412de); // magic
|
|
| 317 | + put32(mo + 8, 2); // number of strings
|
|
| 318 | + put32(mo + 12, 28); // offset of original strings table
|
|
| 319 | + put32(mo + 16, 44); // offset of translated strings table
|
|
| 320 | + // original strings table
|
|
| 321 | + put32(mo + 28, 0); put32(mo + 32, 60); // ""
|
|
| 322 | + put32(mo + 36, 1); put32(mo + 40, 61); // "x"
|
|
| 323 | + // translated strings table
|
|
| 324 | + put32(mo + 44, 0); put32(mo + 48, 60); // ""
|
|
| 325 | + put32(mo + 52, 0xffffffff); put32(mo + 56, 63); // bogus length
|
|
| 326 | + mo[61] = 'x';
|
|
| 327 | + mo[63] = 'A'; // unterminated string at the very end of the buffer
|
|
| 328 | + |
|
| 329 | + wxCharTypeBuffer<char> data(reinterpret_cast<const char*>(mo), moLen);
|
|
| 330 | + wxMsgCatalog* const cat = wxMsgCatalog::CreateFromData(data, "corrupt");
|
|
| 331 | + CHECK( cat == nullptr );
|
|
| 332 | + delete cat;
|
|
| 333 | +}
|
|
| 334 | + |
|
| 294 | 335 | TEST_CASE("wxTranslations::GetBestTranslation", "[translations]")
|
| 295 | 336 | {
|
| 296 | 337 | wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
|
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help