
Heap corruption in WhatsApp's media picker
Heap corruption in WhatsApp's media picker affecting WhatsApp for android before version 2.19.291
A GIF file is divided into segments, marked by a specific byte:
According to the source code, renderFrame calls DDGifSlurp to parse a GIF, and getBitmap to display the GIF. A rasterBits buffer is allocated by the function, and its size calculated by multiply the width by the height of the image it is currently processing. Perhaps to save memory space and time, the same rasterBits buffer will be used for all frames/images in the GIF. Therefore, it is required that the buffer is able to contain the largest image described in the file. As such, the buffer is re-allocated accordingly if another image section within the same GIF describes a larger image (requires more space).
DDGifSlurp parses the GIF file in a loop, processing each image/frame in the file, and terminates when the terminate record is encountered. When DGifGetImageDesc to return GIF_ERROR (a), it will result in early termination (in the switch case), causing the code that reallocates the rasterBits buffer to be skipped. A snippet of DDGifSlurp is shown below:
void DDGifSlurp(GifInfo *info, bool decode, bool exitAfterFrame) {
...
do {
...
switch (RecordType) {
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(gifFilePtr, isInitialPass) == GIF_ERROR) { <-- [a]
break;
}
...
if (decode) {
...
const uint_fast32_t newRasterSize = gifFilePtr->Image.Width * gifFilePtr->Image.Height;
if (newRasterSize > info->rasterSize || widthOverflow > 0 || heightOverflow > 0) {
void *tmpRasterBits = reallocarray(info->rasterBits, newRasterSize, sizeof(GifPixelType));
...
}
}while (RecordType != TERMINATE_RECORD_TYPE);
}
A GIF image that has the following format will cause a crash: