Skip to content

Commit dd70fe9

Browse files
Baojun Wangmeta-codesync[bot]
authored andcommitted
Bound decoded GIF frame storage
Summary: GIF logical-screen dimensions are expanded into full-canvas RGBA32 frames. A tiny input declaring a 24,930 by 38,911 screen therefore drives roughly 3.9 GiB of initialization before any useful decode result. Reject a single canvas or retained frame set above the existing 1 GiB decoded-frame budget, before allocating or copying it. The division-based checks add O(1) work; accepted decode complexity remains O(frame count * canvas pixels), with aggregate output storage bounded to 1 GiB. Add a synthetic regression with the exact oversized dimensions and a valid 1x1 control. Differential Revision: D114062863 fbshipit-source-id: faf9ebdeb9a0c6ec39694047eebda071adbb1224
1 parent 041112a commit dd70fe9

2 files changed

Lines changed: 42 additions & 9 deletions

File tree

impl/ocean/media/openimagelibraries/ImageGif.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,23 @@ Frames ImageGif::decodeImages(const void* buffer, const size_t size, const size_
175175

176176
const ScopedFunctionVoid scopedCloseFileFunction(std::bind(&DGifCloseFile, gifFile, &error));
177177

178+
const int maxWidth = gifFile->SWidth;
179+
const int maxHeight = gifFile->SHeight;
180+
181+
// Each output image is retained as a full-canvas RGBA32 frame. Bound the
182+
// aggregate resident frame storage before allocating or copying it.
183+
constexpr uint64_t maximalDecodedBytes = 1024ull * 1024ull * 1024ull;
184+
constexpr uint64_t bytesPerPixel = 4ull;
185+
constexpr uint64_t maximalDecodedPixels = maximalDecodedBytes / bytesPerPixel;
186+
187+
const bool hasValidDimensions = maxWidth >= 1 && maxHeight >= 1;
188+
const uint64_t framePixels = hasValidDimensions ? uint64_t(maxWidth) * uint64_t(maxHeight) : 0ull;
189+
190+
if (framePixels > maximalDecodedPixels)
191+
{
192+
return Frames();
193+
}
194+
178195
if (DGifSlurp(gifFile) != GIF_OK)
179196
{
180197
return Frames();
@@ -192,18 +209,15 @@ Frames ImageGif::decodeImages(const void* buffer, const size_t size, const size_
192209
numberImages = std::min(numberImages, maximalImages);
193210
}
194211

195-
Frames frames;
212+
if (framePixels > maximalDecodedPixels / uint64_t(numberImages))
213+
{
214+
return Frames();
215+
}
196216

197-
const int maxWidth = gifFile->SWidth;
198-
const int maxHeight = gifFile->SHeight;
217+
Frames frames;
199218

200-
if (maxWidth >= 1 && maxHeight >= 1)
219+
if (hasValidDimensions)
201220
{
202-
if (uint64_t(maxWidth) * uint64_t(maxHeight) >= uint64_t(1073741823ull)) // width * height * 4 < 2^32
203-
{
204-
return Frames();
205-
}
206-
207221
const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGBA32;
208222

209223
const FrameType frameType = FrameType((unsigned int)(maxWidth), (unsigned int)(maxHeight), pixelFormat, FrameType::ORIGIN_UPPER_LEFT);

impl/ocean/test/testmedia/TestOpenImageLibraries.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,25 @@ TEST_F(TestOpenImageLibrariesGTestInstance, TifImageRGBA32Recorder)
482482

483483
#ifdef OCEAN_MEDIA_OIL_SUPPORT_GIF
484484

485+
TEST_F(TestOpenImageLibrariesGTestInstance, DecodeImages_OversizedLogicalScreen_ReturnsEmpty)
486+
{
487+
std::vector<uint8_t> gif = {
488+
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
489+
0xFF, 0xFF, 0xFF, 0x21, 0xF9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
490+
0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3B};
491+
492+
EXPECT_EQ(Media::OpenImageLibraries::ImageGif::decodeImages(gif.data(), gif.size()).size(), 1u);
493+
494+
constexpr uint16_t oversizedWidth = 24930u;
495+
constexpr uint16_t oversizedHeight = 38911u;
496+
gif[6] = uint8_t(oversizedWidth);
497+
gif[7] = uint8_t(oversizedWidth >> 8u);
498+
gif[8] = uint8_t(oversizedHeight);
499+
gif[9] = uint8_t(oversizedHeight >> 8u);
500+
501+
EXPECT_TRUE(Media::OpenImageLibraries::ImageGif::decodeImages(gif.data(), gif.size()).empty());
502+
}
503+
485504
#ifndef OCEAN_DEBUG
486505
TEST_F(TestOpenImageLibrariesGTestInstance, GifDecodeStressTest)
487506
{

0 commit comments

Comments
 (0)