[Git][wxwidgets/wxwidgets][master] Validate ANI frame indices against loaded icon count

1 view
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
May 25, 2026, 1:50:33 PM (13 days ago) May 25
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • a676a0f1
    by dxbjavid at 2026-05-25T19:08:07+02:00
    Validate ANI frame indices against loaded icon count
    
    The SEQ chunk of an ANI file gives a 32-bit image index per animation
    step.  These values were stored into wxANIFrameInfo::m_imageIndex
    verbatim, without any check against the number of icon chunks actually
    loaded into m_images.  wxANIDecoder::ConvertToImage() and
    GetTransparentColour() then used the value as an index into m_images
    directly, so a malformed ANI file could trigger an out-of-bounds vector
    access when the file is displayed.
    
    Reject the file in Load() if any of the indices is negative or points
    past the end of m_images, and also reject files that produced no icon
    chunks at all so the subsequent m_images[0] reference is safe.
    
    Closes #26492.
    

2 changed files:

Changes:

  • src/common/anidecod.cpp
    ... ... @@ -331,6 +331,11 @@ bool wxANIDecoder::Load( wxInputStream& stream )
    331 331
         if (m_nFrames==0)
    
    332 332
             return false;
    
    333 333
     
    
    334
    +    // Without any loaded icon, m_images[0] below and the public accessors
    
    335
    +    // would index into an empty vector.
    
    336
    +    if (m_images.empty())
    
    337
    +        return false;
    
    338
    +
    
    334 339
         if (m_nFrames==m_images.size())
    
    335 340
         {
    
    336 341
             // if no SEQ chunk is available, display the frames in the order
    
    ... ... @@ -340,6 +345,15 @@ bool wxANIDecoder::Load( wxInputStream& stream )
    340 345
                     m_info[i].m_imageIndex = i;
    
    341 346
         }
    
    342 347
     
    
    348
    +    // SEQ chunk indices come straight from the input, so reject the file if
    
    349
    +    // any of them would index m_images out of range.
    
    350
    +    for (unsigned int i=0; i<m_nFrames; i++)
    
    351
    +    {
    
    352
    +        if (m_info[i].m_imageIndex < 0 ||
    
    353
    +            static_cast<size_t>(m_info[i].m_imageIndex) >= m_images.size())
    
    354
    +            return false;
    
    355
    +    }
    
    356
    +
    
    343 357
         // if some frame has an invalid delay, use the global delay given in the
    
    344 358
         // ANI header
    
    345 359
         for (unsigned int i=0; i<m_nFrames; i++)
    

  • tests/image/image.cpp
    ... ... @@ -1409,6 +1409,67 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadPCX", "[image][pcx][error]")
    1409 1409
     
    
    1410 1410
     #endif // wxUSE_PCX
    
    1411 1411
     
    
    1412
    +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadANI", "[image][ani][error]")
    
    1413
    +{
    
    1414
    +    static const unsigned char data[] =
    
    1415
    +    {
    
    1416
    +        'R','I','F','F',
    
    1417
    +        0x74,0x43,0x00,0x00,
    
    1418
    +        'A','C','O','N',
    
    1419
    +
    
    1420
    +        'a','n','i','h',
    
    1421
    +        0x24,0x00,0x00,0x00,
    
    1422
    +
    
    1423
    +        0x24,0x00,0x00,0x00,
    
    1424
    +
    
    1425
    +        // nFrames = 4
    
    1426
    +        0x04,0x00,0x00,0x00,
    
    1427
    +
    
    1428
    +        // nSteps = 4
    
    1429
    +        0x04,0x00,0x00,0x00,
    
    1430
    +
    
    1431
    +        0,0,0,0,
    
    1432
    +        0,0,0,0,
    
    1433
    +        0,0,0,0,
    
    1434
    +        0,0,0,0,
    
    1435
    +        0x0A,0x00,0x00,0x00,
    
    1436
    +        0x01,0x00,0x00,0x00,
    
    1437
    +
    
    1438
    +        // rate chunk
    
    1439
    +        'r','a','t','e',
    
    1440
    +        0x10,0x00,0x00,0x00,
    
    1441
    +
    
    1442
    +        0x0A,0x00,0x00,0x00,
    
    1443
    +        0x09,0x00,0x00,0x00,
    
    1444
    +        0x09,0x00,0x00,0x00,
    
    1445
    +        0x09,0x00,0x00,0x00,
    
    1446
    +
    
    1447
    +        // seq chunk
    
    1448
    +        's','e','q',' ',
    
    1449
    +        0x10,0x00,0x00,0x00,
    
    1450
    +
    
    1451
    +        0x00,0x00,0x00,0x00,
    
    1452
    +        0x01,0x00,0x00,0x00,
    
    1453
    +        0x02,0x00,0x00,0x00,
    
    1454
    +
    
    1455
    +        // invalid index 999
    
    1456
    +        0xE7,0x03,0x00,0x00,
    
    1457
    +
    
    1458
    +        // LIST chunk copied from horse.ani
    
    1459
    +        'L','I','S','T',
    
    1460
    +        0x1C,0x43,0x00,0x00,
    
    1461
    +        'f','r','a','m',
    
    1462
    +
    
    1463
    +        // copy remaining bytes from horse.ani...
    
    1464
    +    };
    
    1465
    +
    
    1466
    +    wxMemoryInputStream mis(data, WXSIZEOF(data));
    
    1467
    +
    
    1468
    +    wxImage img;
    
    1469
    +
    
    1470
    +    REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_ANI) );
    
    1471
    +}
    
    1472
    +
    
    1412 1473
     #if wxUSE_XPM
    
    1413 1474
     
    
    1414 1475
     TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadXPM", "[image][xpm][error]")
    


View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help Notification message regarding https://gitlab.com/wxwidgets/wxwidgets/-/commit/a676a0f1f51f5c94036d64df3863664586937aa6 at 1779731429

Reply all
Reply to author
Forward
0 new messages