Large amount of uninitialized values in svg parsing and processing
Submitted by gus..@..mag.fr
Assigned to Emmanuel Pacaud
Description
This is a copy of a security report, please make this bug private as soon as possible reproduced here since it affects cairo. After that, i will submit the test cases to reproduce it.
Hello,
We detected a large amount of uninitialized values in the parsing and processing of svg files using librsvg and related libraries (e.g, libcairo) causing undefined behaviors. Some of these issues are originated in librsvg, some in libcairo and others (libpixman maybe). I haven't found a way to privately report these issues to the cairo developers but anyway i think you should be aware of this, since it affects almost every program using gdk-pixbuf (yes, including Firefox and Chromium when you try to attach a svg in Linux). These issues were tested in a fully updated Ubuntu 14.04 (with librsvg-2.40.2 and its dependencies). Other configurations/versions are likely affected.
Please find attached some small svg files to trigger the creation and use of initialized values. Valgrind reports are also attached. You can reproduce these issues using a gdk-pixbuf minimum example (available here: https://github.com/CIFASIS/QuickFuzz/blob/master/bins/gdk-pixbuf.c). These svg are taking forever to be rendered (possible infinite loop).
DoS is not the only possible attack: we also found that it is possible to use a state-of-the-art fuzzer, american fuzzy lop, to discover interesting crashes. In the instrumented mode, afl will look for new "transitions" in the control flow graph of a program. If you collect many different test cases, you can find some interesting ways of exploit uninitialized values (specially, in the stack). We used rsvg-convert process the test cases with the undefined behavior and after fuzzing for a few hours, afl detected this heap overflow:
Program received signal SIGSEGV, Segmentation fault.
rsvg_filter_primitive_erode_render (self=0x8115880, ctx=0x8162d10) at rsvg-filter.c:2495
2495 output_pixels[y * rowstride + x * 4 + ch] = extreme;
(gdb) bt
#0 rsvg_filter_primitive_erode_render (self=0x8115880, ctx=0x8162d10) at rsvg-filter.c:2495
#1 0x080c0575 in rsvg_filter_primitive_render (ctx=0x8162d10, self=<optimized out>) at rsvg-filter.c:86
#2 rsvg_filter_render (self=0x81152e0, source=source@entry=0x8167608, context=context@entry=0x80fb330, bounds=bounds@entry=0x8124d34,
channelmap=channelmap@entry=0x80ea460 "2103") at rsvg-filter.c:530
#3 0x080d78c9 in rsvg_cairo_pop_render_stack (ctx=0x80fb330) at rsvg-cairo-draw.c:806
#4 rsvg_cairo_pop_discrete_layer (ctx=0x80fb330) at rsvg-cairo-draw.c:853
#5 0x080ce488 in rsvg_node_use_draw (self=0x811fda0, ctx=0x80fb330, dominate=0) at rsvg-structure.c:228
#6 0x080ccef0 in rsvg_node_draw (dominate=0, ctx=0x80fb330, self=0x811fda0) at rsvg-structure.c:69
#7 _rsvg_node_draw_children (self=0x811f800, ctx=0x80fb330, dominate=0) at rsvg-structure.c:87
#8 0x080ccef0 in rsvg_node_draw (dominate=0, ctx=0x80fb330, self=0x811f800) at rsvg-structure.c:69
#9 _rsvg_node_draw_children (self=0x811b4b8, ctx=0x80fb330, dominate=0) at rsvg-structure.c:87
#10 0x080ccef0 in rsvg_node_draw (dominate=0, ctx=0x80fb330, self=0x811b4b8) at rsvg-structure.c:69
#11 _rsvg_node_draw_children (self=0x8113378, ctx=0x80fb330, dominate=0) at rsvg-structure.c:87
#12 0x080ccef0 in rsvg_node_draw (dominate=0, ctx=0x80fb330, self=0x8113378) at rsvg-structure.c:69
#13 _rsvg_node_draw_children (self=0x8111ea0, ctx=0x80fb330, dominate=0) at rsvg-structure.c:87
#14 0x080cd5d0 in rsvg_node_draw (dominate=0, ctx=0x80fb330, self=0x8111ea0) at rsvg-structure.c:69
#15 rsvg_node_svg_draw (self=0x81086e0, ctx=0x80fb330, dominate=0) at rsvg-structure.c:323
#16 0x080ceb60 in rsvg_node_draw (self=0x81086e0, ctx=0x80fb330, dominate=0) at rsvg-structure.c:69
#17 0x0808af0a in rsvg_handle_render_cairo_sub (id=0x0, cr=0x80fb900, handle=0x80ff8f0) at rsvg-cairo-render.c:225
#18 rsvg_handle_render_cairo (handle=handle@entry=0x80ff8f0, cr=cr@entry=0x80fb900) at rsvg-cairo-render.c:247
#19 0x0804ec8c in main (argc=1, argv=0xbffff6c4) at rsvg-convert.c:360
Unfortunately, such crash is difficult to reproduce in the original rsvg-convert binary (remember that afl needs to recompile to instrumenting binaries) but the uninitialized values are easy to spot using valgrind (such report is also attached). Nevertheless, the possibility of finding vulnerabilities is real and therefore these bugs should be fixed.
These test cases were found using QuickFuzz and afl.
Regards, Gustavo.