New Security Issue
Original reporter: Sam Ezeh
Area: Platform component
Message
Denial of Service in gdk-pixbuf
The attached file when processed by gdk-pixbuf-thumbnailer
causes excess CPU usage to occur and ultimately causes gdk-pixbuf to hang.
The issue comes about as a result of the EOI correction code leading to an infinite loop in the libjpeg library when decoding MCUs. In arith_decode
, e->a
is 0 and its value is never changed successfully since `e->a skip_next] = (JOCTET) 0xFF;
src->buffer[src->skip_next + 1] = (JOCTET) JPEG_EOI;
src->pub.next_input_byte = src->buffer + src->skip_next;
-
src->pub.bytes_in_buffer = 2; gdk_pixbuf__jpeg_image_load_lines (context, NULL); }
# Backtrace
```c
#0 0x00007ffff787f78c in arith_decode (cinfo=cinfo@entry=0x55555559d6c0, st=st@entry=0x55555559f880 "")
at /usr/src/debug/libjpeg-turbo-2.1.3/jdarith.c:154
#1 0x00007ffff788244a in decode_mcu (cinfo=0x55555559d6c0, MCU_data=0x55555559f018)
at /usr/src/debug/libjpeg-turbo-2.1.3/jdarith.c:538
#2 0x00007ffff786c7d7 in decompress_onepass (cinfo=0x55555559d6c0, output_buf=0x55555559f200)
at /usr/src/debug/libjpeg-turbo-2.1.3/jdcoefct.c:107
#3 0x00007ffff78722c2 in process_data_context_main
(cinfo=0x55555559d6c0, output_buf=0x7ffffffedb60, out_row_ctr=0x7ffffffedb34, out_rows_avail=1)
at /usr/src/debug/libjpeg-turbo-2.1.3/jdmainct.c:339
#4 0x00007ffff7869bb5 in jpeg_read_scanlines
(cinfo=cinfo@entry=0x55555559d6c0, scanlines=scanlines@entry=0x7ffffffedb60, max_lines=1)
at /usr/src/debug/libjpeg-turbo-2.1.3/jdapistd.c:293
#5 0x00007ffff7faea5d in gdk_pixbuf__jpeg_image_load_lines
(context=context@entry=0x55555559d680, error=error@entry=0x0) at ../gdk-pixbuf/io-jpeg.c:937
#6 0x00007ffff7faec32 in gdk_pixbuf__jpeg_image_stop_load (data=0x55555559d680, error=0x7ffffffedc00)
at ../gdk-pixbuf/io-jpeg.c:884
#7 0x00007ffff7fa14e3 in gdk_pixbuf_loader_close
(loader=loader@entry=0x555555596b40, error=error@entry=0x7fffffffdcf0) at ../gdk-pixbuf/gdk-pixbuf-loader.c:859
#8 0x00007ffff7f9ea0e in gdk_pixbuf_new_from_file_at_scale
(filename=filename@entry=0x55555559ba70 "/home/sam/Documents/Security/Samples/hang.jpg", width=, height=, preserve_aspect_ratio=preserve_aspect_ratio@entry=1, error=error@entry=0x7fffffffdcf0)
at ../gdk-pixbuf/gdk-pixbuf-io.c:1442
#9 0x00007ffff7f9ebdd in gdk_pixbuf_new_from_file_at_size
(filename=filename@entry=0x55555559ba70 "/home/sam/Documents/Security/Samples/hang.jpg", width=, height=, error=error@entry=0x7fffffffdcf0) at ../gdk-pixbuf/gdk-pixbuf-io.c:1248
#10 0x0000555555556741 in file_to_pixbuf
(path=path@entry=0x55555559ba70 "/home/sam/Documents/Security/Samples/hang.jpg", destination_size=, error=error@entry=0x7fffffffdcf0) at ../thumbnailer/gdk-pixbuf-thumbnailer.c:35
#11 0x00005555555563a1 in main (argc=, argv=)
at ../thumbnailer/gnome-thumbnailer-skeleton.c:284
Relevant libjpeg code
LOCAL(int)
arith_decode(j_decompress_ptr cinfo, unsigned char *st)
{
register arith_entropy_ptr e = (arith_entropy_ptr)cinfo->entropy;
register unsigned char nl, nm;
register JLONG qe, temp;
register int sv, data;
/* Renormalization & data input per section D.2.6 */
while (e->a ct unread_marker)
data = 0; /* stuff zero data */
else {
data = get_byte(cinfo); /* read next input byte */
if (data == 0xFF) { /* zero stuff or marker code */
do data = get_byte(cinfo);
while (data == 0xFF); /* swallow extra 0xFF bytes */
if (data == 0)
data = 0xFF; /* discard stuffed zero byte */
else {
/* Note: Different from the Huffman decoder, hitting
* a marker while processing the compressed data
* segment is legal in arithmetic coding.
* The convention is to supply zero data
* then until decoding is complete.
*/
cinfo->unread_marker = data;
data = 0;
}
}
}
e->c = (e->c re-init A and exit loop */
e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
}
e->a <<= 1;
}
...
}