
Heap corruption in WhatsApp's media picker
Коррупция кучи в медиа-браузере WhatsApp, затрагивающая WhatsApp для Android до версии 2.19.291
GIF-файл делится на сегменты, помеченные определённым байтом:
Согласно исходному коду, renderFrame вызывает DDGifSlurp для разбора GIF и getBitmap для его отображения. Буфер rasterBits выделяется функцией, а его размер вычисляется умножением ширины на высоту обрабатываемого изображения. Возможно, для экономии памяти и времени, один и тот же буфер rasterBits используется для всех кадров/изображений в GIF. Поэтому требуется, чтобы буфер мог вместить самое большое изображение, описанное в файле. Соответственно, буфер перераспределяется, если другая секция изображения в том же GIF описывает большее изображение (требуется больше места).
DDGifSlurp разбирает GIF-файл в цикле, обрабатывая каждое изображение/кадр в файле, и завершается при обнаружении записи завершения. Когда DGifGetImageDesc возвращает GIF_ERROR (a), это приводит к преждевременному завершению (в операторе switch), в результате чего код, перераспределяющий буфер rasterBits, пропускается. Фрагмент DDGifSlurp показан ниже:
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);
}
GIF-изображение, имеющее следующий формат, приведёт к сбою: