After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 775218 - Integer overflows in jpeg_parse_exif_app1
Integer overflows in jpeg_parse_exif_app1
Status: RESOLVED FIXED
Product: gdk-pixbuf
Classification: Platform
Component: loaders
git master
Other Linux
: Normal normal
: ---
Assigned To: gdk-pixbuf-maint
gdk-pixbuf-maint
Depends on:
Blocks:
 
 
Reported: 2016-11-28 10:33 UTC by Tobias Mueller
Modified: 2016-12-14 12:50 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch (2.43 KB, patch)
2016-11-28 10:49 UTC, Tobias Mueller
accepted-commit_now Details | Review
crashing file, password "crash" (1.16 KB, application/pgp-encrypted)
2016-11-28 10:50 UTC, Tobias Mueller
  Details
crashing file added to tests/ (2.42 KB, patch)
2016-12-12 15:18 UTC, Tobias Mueller
none Details | Review
jpeg: Check for integer overflows in app1 EXIF tags (2.75 KB, patch)
2016-12-12 15:49 UTC, Bastien Nocera
none Details | Review
tests: Add test case for bug 775218 (3.85 KB, patch)
2016-12-12 16:55 UTC, Bastien Nocera
none Details | Review
jpeg: Check for integer overflows in app1 EXIF tags (2.82 KB, patch)
2016-12-12 17:25 UTC, Bastien Nocera
committed Details | Review
tests: Add test case for bug 775218 (3.82 KB, patch)
2016-12-12 17:25 UTC, Bastien Nocera
committed Details | Review

Description Tobias Mueller 2016-11-28 10:33:59 UTC
security
Comment 1 Tobias Mueller 2016-11-28 10:46:38 UTC
In jpeg_parse_exif_app1 it reads an offset off a file:

    /* read out the offset pointer to IFD0 */
    offset  = de_get32(&marker->data[i] + 4, endian);
    i = i + offset;

this "i" is then used to peek into the buffer and read bytes.

	tags = de_get16(&marker->data[i], endian);
	i = i + 2;

The addition may very well overflow.


➜ gdk-pixbuf git:(master) ✗>
env ASAN_OPTIONS=abort_on_error=1 gdb -ex "set pagination 0" -ex "r" -ex "t a a bt full" --args /tmp/gdkpb/libexec/installed-tests/gdk-pixbuf/pixbuf-read /tmp/gdk-findings/compute32_fuzz19/crashes/id:000022,sig:11,src:003440+003703,op:splice,rep:16 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /tmp/gdkpb/libexec/installed-tests/gdk-pixbuf/pixbuf-read...done.
Starting program: /tmp/gdkpb/libexec/installed-tests/gdk-pixbuf/pixbuf-read /tmp/gdk-findings/compute32_fuzz19/crashes/id:000022,sig:11,src:003440+003703,op:splice,rep:16
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
/tmp/gdk-findings/compute32_fuzz19/crashes/id:000022,sig:11,src:003440+003703,op:splice,rep:16		
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff0ee3263 in de_get16 (ptr=0x60d10000b33e, endian=4321) at io-jpeg.c:294
294	       memcpy(&val, ptr, sizeof(val));

Thread 1 (Thread 0x7ffff7fc3880 (LWP 7536))

  • #0 de_get16
    at io-jpeg.c line 294
  • #1 jpeg_parse_exif_app1
    at io-jpeg.c line 454
  • #2 jpeg_parse_exif
    at io-jpeg.c line 505
  • #3 gdk_pixbuf__jpeg_image_load_increment
    at io-jpeg.c line 1026
  • #4 gdk_pixbuf_loader_write
    at gdk-pixbuf-loader.c line 521
  • #5 test_loader
    at pixbuf-read.c line 31
  • #6 main
    at pixbuf-read.c line 75
  • #1 jpeg_parse_exif_app1
    at io-jpeg.c line 454
$4 = (jpeg_saved_marker_ptr) 0x60d00000b320
(gdb) p *marker
$5 = {next = 0x60d00000b250, marker = 225 '\341', original_length = 55, data_length = 55, data = 0x60d00000b340 "Exif66P\221\366MM"}
(gdb) p i
$6 = 4294967294
(gdb) p i+2
$7 = 0
(gdb) l
449		ret = FALSE;
450			goto out;
451		}
452	
453		/* find out how many tags we have in IFD0. As per the TIFF spec, the first
454		   two bytes of the IFD contain a count of the number of tags. */
455		tags = de_get16(&marker->data[i], endian);
456		i = i + 2;
457	
458		/* check that we still have enough data for all tags to check. The tags
(gdb) 




This crashes firefox, epiphany, nautilus, probably everything that uses gdk-pixbuf to render the pathologic JPEG file that afl produced.
Comment 2 Tobias Mueller 2016-11-28 10:49:10 UTC
Created attachment 340887 [details] [review]
patch

This is one way to check for overflows. The test case passes.
Comment 3 Tobias Mueller 2016-11-28 10:50:34 UTC
Created attachment 340888 [details]
crashing file, password "crash"
Comment 4 Matthias Clasen 2016-12-12 15:12:13 UTC
I don't do gpg. Can you please attach a patch that adds the test file to the testsuite ?
Comment 5 Matthias Clasen 2016-12-12 15:13:53 UTC
Review of attachment 340887 [details] [review]:

this looks good to me
Comment 6 Tobias Mueller 2016-12-12 15:18:58 UTC
Created attachment 341821 [details] [review]
crashing file added to tests/

this is the attached gpg file after having done
gpg --decrypt /tmp/crash.jpg.gpg > bug775218.jpg
Comment 7 Bastien Nocera 2016-12-12 15:49:28 UTC
Created attachment 341826 [details] [review]
jpeg: Check for integer overflows in app1 EXIF tags

In jpeg_parse_exif_app1(), we would usually read offsets this way:

    /* read out the offset pointer to IFD0 */
    offset  = de_get32(&marker->data[i] + 4, endian);
    i = i + offset;

"i" is then used to peek into the buffer and read bytes.

	tags = de_get16(&marker->data[i], endian);
	i = i + 2;

But as the addition may overflow, we need to check whether the result of
the addition would overflow and wrap-around.
Comment 8 Bastien Nocera 2016-12-12 15:50:28 UTC
Comment on attachment 340887 [details] [review]
patch

I fixed coding style problems, and reworded the commit message in a new patch, marking this one as obsolete.
Comment 9 Bastien Nocera 2016-12-12 16:49:01 UTC
Review of attachment 341826 [details] [review]:

It regresses it seems:
ERROR:/home/hadess/Projects/jhbuild/gdk-pixbuf/tests/pixbuf-jpeg.c:74:test_type9_rotation_exif_tag: assertion failed (error == NULL): Image size is 640x428 but should be 428x640 (gdk-pixbuf-error-quark, 0)
Comment 10 Bastien Nocera 2016-12-12 16:55:21 UTC
Created attachment 341833 [details] [review]
tests: Add test case for bug 775218
Comment 11 Bastien Nocera 2016-12-12 16:57:16 UTC
(In reply to Bastien Nocera from comment #9)
> Review of attachment 341826 [details] [review] [review]:
> 
> It regresses it seems:
> ERROR:/home/hadess/Projects/jhbuild/gdk-pixbuf/tests/pixbuf-jpeg.c:74:
> test_type9_rotation_exif_tag: assertion failed (error == NULL): Image size
> is 640x428 but should be 428x640 (gdk-pixbuf-error-quark, 0)

The original patch regresses as well. At least now we have a test case hooked up, which shows the impact of the patch.
Comment 12 Bastien Nocera 2016-12-12 17:25:53 UTC
Created attachment 341836 [details] [review]
jpeg: Check for integer overflows in app1 EXIF tags

In jpeg_parse_exif_app1(), we would usually read offsets this way:

    /* read out the offset pointer to IFD0 */
    offset  = de_get32(&marker->data[i] + 4, endian);
    i = i + offset;

"i" is then used to peek into the buffer and read bytes.

	tags = de_get16(&marker->data[i], endian);
	i = i + 2;

But as the addition may overflow, we need to check whether the result of
the addition would overflow and wrap-around.
Comment 13 Bastien Nocera 2016-12-12 17:25:58 UTC
Created attachment 341837 [details] [review]
tests: Add test case for bug 775218
Comment 14 Bastien Nocera 2016-12-12 17:27:40 UTC
This last patch to io-jpeg.c corrects the checks done for integer overflow. You were doing "i = i+12" when you should just have been checking for whether "i+12" overflowed (or was too big), and weren't doing the checks at the end of each while loop.

This passes the test suite for me.
Comment 15 Tobias Mueller 2016-12-13 11:11:05 UTC
very nice work!
Looks good to me.
Comment 16 Bastien Nocera 2016-12-13 12:06:22 UTC
Attachment 341836 [details] pushed as 5daadc0 - jpeg: Check for integer overflows in app1 EXIF tags
Attachment 341837 [details] pushed as 7fc0cc2 - tests: Add test case for bug 775218