[Bug 1823419] Re: jbig-kit calls abort() on invalid data, crashing many programs
Marc Deslauriers
marc.deslauriers at canonical.com
Fri Oct 18 12:09:57 UTC 2019
** Changed in: jbigkit (Ubuntu)
Status: New => Confirmed
--
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to jbigkit in Ubuntu.
https://bugs.launchpad.net/bugs/1823419
Title:
jbig-kit calls abort() on invalid data, crashing many programs
Status in jbigkit package in Ubuntu:
Confirmed
Bug description:
Hi,
Sometimes I fuzz random packages that are dependencies of lots of
other packages. Yesterday I picked up jbigkit.
I've just reported upstream a crash where invalid input can cause it
to call abort() rather than report an error up the stack.
This is a DoS in itself, but it's massively exacerbated because TIFF
files can include JBIG1-formatted streams. jbigkit is included in
libtiff, and libtiff is itself included in a bunch of other things. So
I wanted to highlight this to you because of it's widespread DoS
potential.
For example, if you process a corrupted tiff file in imagemagick, it
will crash. If view a corrupted tiff file in e.g. eog or evince, it
will crash. Worst, if you open a file picker in some apps, like chrome
or chromium-browser, it will call out to libgdk-pixbuf to generate a
preview, which will call out to libtiff, then jbigkit, then abort(),
which kills your entire browser session. This also affects the file
picker on pinta (and pinta itself), but not firefox or eog. I'm not
sure why some are affected and some are not.
Here's a trace from chromium-browser: I know it's not in main but it's
a good demonstration.
Thread 1 "chromium-browse" received signal SIGABRT, Aborted.
__GI_raise (sig=sig at entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 0x00007ffff5039077 in __GI_raise (sig=sig at entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007ffff501a535 in __GI_abort () at abort.c:79
#2 0x00007fff4e15b1a3 in checked_malloc (nmemb=<optimised out>, size=<optimised out>) at jbig.c:139
#3 0x00007fff4e160803 in jbg_dec_in (s=s at entry=0x7ffffffea8c0, data=0x555560317eb0 "", len=14761, cnt=0x7ffffffea838, cnt at entry=0x0) at jbig.c:2669
#4 0x00007fff941ccf50 in JBIGDecode (tif=0x55556022cf70, buffer=0x5555604decc0 "", size=513216, s=<optimised out>) at tif_jbig.c:80
#5 0x00007fff941e46f4 in _TIFFReadEncodedStripAndAllocBuffer
(tif=tif at entry=0x55556022cf70, strip=0, buf=buf at entry=0x7ffffffeaed0, bufsizetoalloc=bufsizetoalloc at entry=513216, size_to_read=size_to_read at entry=513216)
at tif_read.c:586
#6 0x00007fff941c93ff in gtStripContig (img=0x7ffffffeaf30, raster=0x7fff49cef010, w=1728, h=2376) at tif_getimage.c:960
#7 0x00007fff941cc958 in TIFFReadRGBAImageOriented
(tif=tif at entry=0x55556022cf70, rwidth=1728, rheight=2376, raster=raster at entry=0x7fff49cef010, orientation=orientation at entry=1, stop=stop at entry=1) at tif_getimage.c:532
#8 0x00007fffe81f668b in tiff_image_parse (tiff=tiff at entry=0x55556022cf70, context=context at entry=0x55555fbedaa0, error=error at entry=0x7ffffffeb4c0)
at ../gdk-pixbuf/io-tiff.c:282
#9 0x00007fffe81f6b3b in gdk_pixbuf__tiff_image_stop_load (data=0x55555fbedaa0, error=0x7ffffffeb4c0) at ../gdk-pixbuf/io-tiff.c:515
#10 0x00007ffff5398943 in gdk_pixbuf_loader_close (loader=loader at entry=0x55555f7f0140 [GdkPixbufLoader], error=error at entry=0x0) at ../gdk-pixbuf/gdk-pixbuf-loader.c:846
#11 0x00007ffff539601a in gdk_pixbuf_new_from_file_at_scale
(filename=0x555560072980 "/home/dja/dev/research/wip/maintest/packages/fax/crash.tiff", width=<optimised out>, height=<optimised out>, preserve_aspect_ratio=<optimised out>, error=0x0) at ../gdk-pixbuf/gdk-pixbuf-io.c:1353
#12 0x000055555af5d8bf in ()
#16 0x00007ffff68f83a4 in <emit signal ??? on instance 0x5555601263b0 [GtkFileChooserDialog]> (instance=0x5555601263b0, detailed_signal=<optimised out>)
at ../../../../gobject/gsignal.c:3487
#13 0x00007ffff68dbb6d in g_closure_invoke (closure=0x5555602ee6d0, return_value=0x0, n_param_values=1, param_values=0x7fffffffb800, invocation_hint=0x7fffffffb780)
at ../../../../gobject/gclosure.c:810
#14 0x00007ffff68ee8f3 in signal_emit_unlocked_R
(node=node at entry=0x55555ff53be0, detail=detail at entry=0, instance=instance at entry=0x5555601263b0, emission_return=emission_return at entry=0x0, instance_and_params=instance_and_params at entry=0x7fffffffb800) at ../../../../gobject/gsignal.c:3635
#15 0x00007ffff68f7882 in g_signal_emit_valist
(instance=instance at entry=0x5555601263b0, signal_id=signal_id at entry=335, detail=detail at entry=0, var_args=var_args at entry=0x7fffffffb9f8)
at ../../../../gobject/gsignal.c:3391
#20 0x00007ffff68f83a4 in <emit signal 0x7ffff58b67d8 "update-preview" on instance 0x5555600e0360 [GtkFileChooserWidget]>
(instance=instance at entry=0x5555600e0360, detailed_signal=detailed_signal at entry=0x7ffff58b67d8 "update-preview") at ../../../../gobject/gsignal.c:3487
--Type <RET> for more, q to quit, c to continue without paging--c
#17 0x00007ffff68dbb6d in g_closure_invoke (closure=0x5555600e2fe0, return_value=0x0, n_param_values=1, param_values=0x7fffffffbcf0, invocation_hint=0x7fffffffbc70) at ../../../../gobject/gclosure.c:810
#18 0x00007ffff68ee8f3 in signal_emit_unlocked_R (node=node at entry=0x55555ff53be0, detail=detail at entry=0, instance=instance at entry=0x5555600e0360, emission_return=emission_return at entry=0x0, instance_and_params=instance_and_params at entry=0x7fffffffbcf0) at ../../../../gobject/gsignal.c:3635
#19 0x00007ffff68f7882 in g_signal_emit_valist (instance=instance at entry=0x5555600e0360, signal_id=signal_id at entry=335, detail=detail at entry=0, var_args=var_args at entry=0x7fffffffbee8) at ../../../../gobject/gsignal.c:3391
#21 0x00007ffff567c015 in check_preview_change (impl=impl at entry=0x5555600e0360 [GtkFileChooserWidget]) at ../../../../gtk/gtkfilechooserwidget.c:7723
#22 0x00007ffff567fcc0 in list_selection_changed (selection=<optimised out>, impl=0x5555600e0360 [GtkFileChooserWidget]) at ../../../../gtk/gtkfilechooserwidget.c:7778
#23 0x00007ffff68dbda6 in _g_closure_invoke_va (closure=0x555560203fe0, return_value=0x0, instance=0x5555601cc2b0, args=0x7fffffffc330, n_params=0, param_types=0x0) at ../../../../gobject/gclosure.c:873
#24 0x00007ffff68f7961 in g_signal_emit_valist (instance=0x5555601cc2b0, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args at entry=0x7fffffffc330) at ../../../../gobject/gsignal.c:3300
#25 0x00007ffff68f7ecf in g_signal_emit (instance=<optimised out>, signal_id=<optimised out>, detail=<optimised out>) at ../../../../gobject/gsignal.c:3447
#26 0x00007ffff5810607 in gtk_tree_view_real_set_cursor (tree_view=tree_view at entry=0x5555601ee3c0 [GtkTreeView], path=path at entry=0x55555fce37b0, flags=flags at entry=(CLEAR_AND_SELECT | CLAMP_NODE)) at ../../../../gtk/gtktreeview.c:13323
#27 0x00007ffff581799a in gtk_tree_view_multipress_gesture_pressed (gesture=0x55556016b790 [GtkGestureMultiPress], n_press=1, x=<optimised out>, y=<optimised out>, tree_view=0x5555601ee3c0 [GtkTreeView]) at ../../../../gtk/gtktreeview.c:3379
#28 0x00007ffff49e9dae in ffi_call_unix64 () at /usr/lib/x86_64-linux-gnu/libffi.so.6
#29 0x00007ffff49e971f in ffi_call () at /usr/lib/x86_64-linux-gnu/libffi.so.6
#30 0x00007ffff68dc7e6 in g_cclosure_marshal_generic_va (closure=0x5555601f0420, return_value=0x0, instance=<optimised out>, args_list=<optimised out>, marshal_data=<optimised out>, n_params=3, param_types=0x55555f712690) at ../../../../gobject/gclosure.c:1610
#31 0x00007ffff68dbda6 in _g_closure_invoke_va (closure=0x5555601f0420, return_value=0x0, instance=0x55556016b790, args=0x7fffffffca10, n_params=3, param_types=0x55555f712690) at ../../../../gobject/gclosure.c:873
#32 0x00007ffff68f7961 in g_signal_emit_valist (instance=0x55556016b790, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args at entry=0x7fffffffca10) at ../../../../gobject/gsignal.c:3300
#33 0x00007ffff68f7ecf in g_signal_emit (instance=instance at entry=0x55556016b790, signal_id=<optimised out>, detail=detail at entry=0) at ../../../../gobject/gsignal.c:3447
#34 0x00007ffff56a1868 in gtk_gesture_multi_press_begin (gesture=0x55556016b790 [GtkGestureMultiPress], sequence=<optimised out>) at ../../../../gtk/gtkgesturemultipress.c:241
#35 0x00007ffff68deba2 in g_cclosure_marshal_VOID__BOXEDv (closure=0x55555f65c870, return_value=<optimised out>, instance=<optimised out>, args=<optimised out>, marshal_data=<optimised out>, n_params=<optimised out>, param_types=0x55555f65c8e0) at ../../../../gobject/gmarshal.c:1950
#36 0x00007ffff68dbda6 in _g_closure_invoke_va (closure=0x55555f65c870, return_value=0x0, instance=0x55556016b790, args=0x7fffffffcdc0, n_params=1, param_types=0x55555f65c8e0) at ../../../../gobject/gclosure.c:873
#37 0x00007ffff68f7961 in g_signal_emit_valist (instance=0x55556016b790, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args at entry=0x7fffffffcdc0) at ../../../../gobject/gsignal.c:3300
#38 0x00007ffff68f7ecf in g_signal_emit (instance=instance at entry=0x55556016b790, signal_id=<optimised out>, detail=detail at entry=0) at ../../../../gobject/gsignal.c:3447
#39 0x00007ffff569e6fe in _gtk_gesture_set_recognized (sequence=0x0, recognized=1, gesture=0x55556016b790 [GtkGestureMultiPress]) at ../../../../gtk/gtkgesture.c:343
#40 0x00007ffff569e6fe in _gtk_gesture_check_recognized (gesture=gesture at entry=0x55556016b790 [GtkGestureMultiPress], sequence=sequence at entry=0x0) at ../../../../gtk/gtkgesture.c:389
#41 0x00007ffff569fc33 in gtk_gesture_handle_event (controller=0x55556016b790 [GtkGestureMultiPress], event=0x5555602831f0) at ../../../../gtk/gtkgesture.c:747
#42 0x00007ffff56a2a96 in gtk_gesture_single_handle_event (controller=0x55556016b790 [GtkGestureMultiPress], event=0x5555602831f0) at ../../../../gtk/gtkgesturesingle.c:222
#43 0x00007ffff566b5f5 in gtk_event_controller_handle_event (controller=0x55556016b790 [GtkGestureMultiPress], event=event at entry=0x5555602831f0) at ../../../../gtk/gtkeventcontroller.c:230
#44 0x00007ffff58258db in _gtk_widget_run_controllers (widget=0x5555601ee3c0 [GtkTreeView], event=0x5555602831f0, phase=GTK_PHASE_BUBBLE) at ../../../../gtk/gtkwidget.c:7379
#49 0x00007ffff68f7ecf in <emit signal ??? on instance 0x5555601ee3c0 [GtkTreeView]> (instance=instance at entry=0x5555601ee3c0, signal_id=<optimised out>, detail=detail at entry=0) at ../../../../gobject/gsignal.c:3447
#45 0x00007ffff5879f9b in _gtk_marshal_BOOLEAN__BOXED (closure=0x55555f60a170, return_value=0x7fffffffd140, n_param_values=<optimised out>, param_values=0x7fffffffd1a0, invocation_hint=<optimised out>, marshal_data=<optimised out>) at ../../../../gtk/gtkmarshalers.c:83
#46 0x00007ffff68dbb6d in g_closure_invoke (closure=0x55555f60a170, return_value=0x7fffffffd140, n_param_values=2, param_values=0x7fffffffd1a0, invocation_hint=0x7fffffffd120) at ../../../../gobject/gclosure.c:810
#47 0x00007ffff68ee124 in signal_emit_unlocked_R (node=node at entry=0x55555f60a1c0, detail=detail at entry=0, instance=instance at entry=0x5555601ee3c0, emission_return=emission_return at entry=0x7fffffffd2c0, instance_and_params=instance_and_params at entry=0x7fffffffd1a0) at ../../../../gobject/gsignal.c:3673
#48 0x00007ffff68f6f43 in g_signal_emit_valist (instance=<optimised out>, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args at entry=0x7fffffffd370) at ../../../../gobject/gsignal.c:3401
#50 0x00007ffff5827b74 in gtk_widget_event_internal (widget=widget at entry=0x5555601ee3c0 [GtkTreeView], event=event at entry=0x5555602831f0) at ../../../../gtk/gtkwidget.c:7744
#51 0x00007ffff5829c8a in gtk_widget_event (widget=widget at entry=0x5555601ee3c0 [GtkTreeView], event=event at entry=0x5555602831f0) at ../../../../gtk/gtkwidget.c:7314
#52 0x00007ffff56e7c56 in propagate_event_up (topmost=<optimised out>, event=<optimised out>, widget=0x5555601ee3c0 [GtkTreeView]) at ../../../../gtk/gtkmain.c:2592
#53 0x00007ffff56e7c56 in propagate_event (widget=<optimised out>, event=0x5555602831f0, captured=<optimised out>, topmost=0x0) at ../../../../gtk/gtkmain.c:2695
#54 0x00007ffff56e9d73 in gtk_main_do_event (event=<optimised out>) at ../../../../gtk/gtkmain.c:1915
#55 0x00007ffff53e7445 in _gdk_event_emit (event=event at entry=0x5555602831f0) at ../../../../gdk/gdkevents.c:73
#56 0x00007ffff5418012 in gdk_event_source_dispatch (source=<optimised out>, callback=<optimised out>, user_data=<optimised out>) at ../../../../../gdk/x11/gdkeventsource.c:367
#57 0x00007ffff67fbc3e in g_main_dispatch (context=0x55555f581110) at ../../../../glib/gmain.c:3182
#58 0x00007ffff67fbc3e in g_main_context_dispatch (context=context at entry=0x55555f581110) at ../../../../glib/gmain.c:3847
#59 0x00007ffff67fbed8 in g_main_context_iterate (context=context at entry=0x55555f581110, block=block at entry=1, dispatch=dispatch at entry=1, self=<optimised out>) at ../../../../glib/gmain.c:3920
#60 0x00007ffff67fbf6c in g_main_context_iteration (context=0x55555f581110, may_block=1) at ../../../../glib/gmain.c:3981
#61 0x0000555558c41e92 in ()
#62 0x0000555558c5e8e9 in ()
#63 0x0000555558b6f2a7 in ()
#64 0x0000555557203274 in ()
#65 0x0000555557205962 in ()
#66 0x000055555720039b in ()
#67 0x000055555882f96a in ()
#68 0x000055555882f5e6 in ()
#69 0x0000555558865996 in ()
#70 0x000055555882d9d1 in ()
#71 0x00005555565a74f3 in ChromeMain ()
#72 0x00007ffff501c09b in __libc_start_main (main=0x5555565a7470, argc=2, argv=0x7fffffffde38, init=<optimised out>, fini=<optimised out>, rtld_fini=<optimised out>, stack_end=0x7fffffffde28) at ../csu/libc-start.c:308
#73 0x00005555565a73aa in _start ()
You could potentially mitigate this by building libtiff without jbig1 support - it's a fairly old format for faxes.
I've been doing these tests on Cosmic but jbigkit has been unchanged
for years so the bugs should apply to older distros.
My message to upstream follows.
Hi,
I decided to try fuzzing jbig-kit with afl-fuzz.
I discovered that it is easy for untrusted inputs to jbig-kit to cause
an abort() in checked_malloc by providing overly large input values.
This will immediately kill any application that links to jbig-kit,
including tools like imagemagick. I think this would be considered a
denial of service attack.
Due to libtiff's embedding of jbig-kit, anything that uses libtiff can
also be caused to abort and dump core rather than fail gracefully.
I have attached both an example jbig file and an example tiff file.
'jbgtopbm crash.jbg'' will crash, and 'convert crash.tiff crash.png'
and 'eog crash.tiff' should also crash. I've had to put the tiff file
in an archive because clicking on it to attach it to the email crashes
the Gnome file picker: it tries to generate a preview, calls out to
libtiff, calls out to jbig-kit, and abort()s.
I think the solution is to have checked_malloc return some sort of
error where it would currently abort().
While fuzzing with AddressSanitizer, I also found a minor buffer over-
read. Perhaps in very rare circumstances it could cause a crash, or
perhaps some data corruption. It can be fixed like so:
diff --git a/libjbig/jbig.c b/libjbig/jbig.c
index fe549464b859..d77990b9205d 100644
--- a/libjbig/jbig.c
+++ b/libjbig/jbig.c
@@ -3264,6 +3264,8 @@ int jbg_newlen(unsigned char *bie, size_t len)
while ((p = jbg_next_pscdms(p, len - (p - bie)))) {
if (p == bie + len)
return JBG_EOK;
+ else if (len - (p - bie) < 6)
+ return JBG_EINVAL;
else if (p[0] == MARKER_ESC)
switch (p[1]) {
case MARKER_NEWLEN:
Regards,
Daniel Axtens
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/jbigkit/+bug/1823419/+subscriptions
More information about the foundations-bugs
mailing list