
WhatsApp의 미디어 선택기에서 발생하는 힙 손상
WhatsApp의 미디어 선택기에서 발생하는 힙 손상으로, Android용 WhatsApp 2.19.291 이전 버전에 영향을 미칩니다.
GIF 파일은 특정 바이트로 표시된 세그먼트로 나뉩니다:
소스 코드에 따르면, renderFrame은 GIF를 파싱하기 위해 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 이미지는 충돌을 일으킵니다: