Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2022-35166: Infinite loop in JPEG::ReadInternal · Issue #76 · thorfdbg/libjpeg

libjpeg commit 842c7ba was discovered to contain an infinite loop via the component JPEG::ReadInternal.

CVE
#ios

version: latest commit 842c7ba
poc: poc
command: ./jpeg poc /dev/null

Here is the backtrace in GDB:

pwndbg> backtrace
#0  0x000055555558fa8a in Image::StartParseFrame (this=0x5555557433a0, io=0x555555741ad0) at image.cpp:658
#1  0x0000555555584739 in JPEG::ReadInternal (this=0x5555557414b8, tags=0x7fffffffdcf0) at jpeg.cpp:286
#2  0x00005555555843de in JPEG::Read (this=0x5555557414b8, tags=0x7fffffffdcf0) at jpeg.cpp:210
#3  0x000055555557a23e in Reconstruct (infile=0x7fffffffe6cf "../../script/test-libjpeg/modify8", outfile=0x7fffffffe6f1 "/dev/null", colortrafo=1, alpha=0x0, upsample=true) at reconstruct.cpp:121
#4  0x00005555555715be in main (argc=3, argv=0x7fffffffe448) at main.cpp:747
#5  0x00007ffff7abf0b3 in __libc_start_main (main=0x55555556fac1 <main(int, char**)>, argc=3, argv=0x7fffffffe448, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe438) at ../csu/libc-start.c:308
#6  0x000055555556f5ee in _start ()

When marker==0xffd9, ParseFrameHeader will return NULL (line 627, image.cpp), which initializes m_pCurrent with NULL (line 667, image.cpp).

marker = io->GetWord();

switch(marker) {

case ByteStream::EOF:

JPG_THROW(MALFORMED_STREAM,"Image::ParseFrameHeader","unexpected EOF while parsing the image");

break;

case 0xffd9: // EOI

return NULL;

class Frame *Image::StartParseFrame(class ByteStream *io)

{

//

// This should only be called from the main image.

assert(m_pParent == NULL && m_pMaster == NULL);

//

// Check whether we have the frame header. Residual and alpha

// already parse that off as part of ParseTrailer().

if (m_bReceivedFrameHeader == false) {

assert(m_pTables);

m_pCurrent = ParseFrameHeader(io);

// Create the checksum if it is needed.

CreateChecksumWhenNeeded(m_pChecksum);

//

// Is now there.

m_bReceivedFrameHeader = true;

}

//

// Otherwise, the frame header has already been parsed off and need not to be

// looked at here again.

return m_pCurrent;

}

Since m_bReceivedFrameHeadere is set to true after that (lne 672, image.cpp), further calls to StartParseFrame will keep returning m_pCurreent=NULL.

while(m_bDecoding) {

if (m_pFrame == NULL) {

m_pFrame = m_pImage->StartParseFrame(m_pIOStream);

if (m_pFrame) {

m_pDecoder->ParseTags(tags);

if (stopflags & JPGFLAG_DECODER_STOP_FRAME)

return;

}

}

if (m_pFrame) {

while (m_pScan == NULL) {

m_pScan = m_pFrame->StartParseScan(m_pImage->InputStreamOf(m_pIOStream),m_pImage->ChecksumOf());

//

if (m_pScan == NULL) {

// This is not yet the start of the scan, but might

// either be a frame trailer, or part of the frame header.

if (m_pFrame->isEndOfFrame()) {

if (!m_pFrame->ParseTrailer(m_pImage->InputStreamOf(m_pIOStream))) {

// Frame done, advance to the next frame.

m_pFrame = NULL;

if (!m_pImage->ParseTrailer(m_pIOStream)) {

// Image done, stop decoding, image is now loaded.

StopDecoding();

return;

}

}

} else {

if (stopflags & JPGFLAG_DECODER_STOP_FRAME)

return;

}

// else continue looking for the start of scan.

} else {

if (stopflags & JPGFLAG_DECODER_STOP_SCAN)

return;

}

}

if (m_pScan) {

if (m_bRow == false) {

m_bRow = m_pScan->StartMCURow();

if (m_bRow) {

if (stopflags & JPGFLAG_DECODER_STOP_ROW)

return;

} else {

// Scan done, advance to the next scan.

m_pFrame->EndParseScan();

m_pScan = NULL;

if (!m_pFrame->ParseTrailer(m_pImage->InputStreamOf(m_pIOStream))) {

// Frame done, advance to the next frame.

m_pFrame = NULL;

if (!m_pImage->ParseTrailer(m_pIOStream)) {

// Image done, stop decoding, image is now loaded.

StopDecoding();

return;

}

}

}

}

if (m_bRow) {

while (m_pScan->ParseMCU()) {

if (stopflags & JPGFLAG_DECODER_STOP_MCU)

return;

}

m_bRow = false;

}

}

}

}

Such behavior leads to an infinite loop in JPEG::ReadInternal. When m_pFrame==NULL (line 285, jpeg.cpp), it will invoke m_pImage->StartParseFrame to initialize it (line 286, jpeg.cpp). Since StartParseFrame keeps returning NULL in this case, the while loop from line 284-353 cannot terminate.

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda