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 778584 - gif: Prevent access to negative array indexes
gif: Prevent access to negative array indexes
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: 2017-02-14 03:40 UTC by Tobias Mueller
Modified: 2017-12-04 16:32 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
file exposing the issue (519 bytes, image/gif)
2017-02-14 03:44 UTC, Tobias Mueller
  Details
patch (1.92 KB, patch)
2017-02-14 03:45 UTC, Tobias Mueller
needs-work Details | Review
left shift patch (1.37 KB, patch)
2017-02-14 03:45 UTC, Tobias Mueller
none Details | Review
patch changing the initialisation to 2 (1.48 KB, patch)
2017-11-11 10:33 UTC, Tobias Mueller
needs-work Details | Review
gif: Initialise code_last_byte to not cause undefined behaviour (1.52 KB, patch)
2017-12-04 07:39 UTC, Tobias Mueller
none Details | Review
gif: Prevent access to negative array indexes (1.17 KB, patch)
2017-12-04 16:28 UTC, Bastien Nocera
committed Details | Review
tests: Add test for bug 778584 (1.04 KB, patch)
2017-12-04 16:28 UTC, Bastien Nocera
committed Details | Review
gif: Preventing undefined behaviour by making left shift unsigned (1.37 KB, patch)
2017-12-04 16:28 UTC, Bastien Nocera
committed Details | Review
gif: Initialise code_last_byte to not cause undefined behaviour (1.52 KB, patch)
2017-12-04 16:28 UTC, Bastien Nocera
committed Details | Review

Description Tobias Mueller 2017-02-14 03:40:46 UTC
It seems that a pathological gif file can cause a negative array index
to be read.  UBSAN reported this:
io-gif.c:509:44: runtime error: index -2 out of bounds for type 'guchar [280]'
io-gif.c:510:44: runtime error: index -1 out of bounds for type 'guchar [280]'
Comment 1 Tobias Mueller 2017-02-14 03:44:44 UTC
Created attachment 345696 [details]
file exposing the issue
Comment 2 Tobias Mueller 2017-02-14 03:45:11 UTC
Created attachment 345697 [details] [review]
patch
Comment 3 Tobias Mueller 2017-02-14 03:45:32 UTC
Created attachment 345698 [details] [review]
left shift patch
Comment 4 Tobias Mueller 2017-11-11 10:33:35 UTC
Created attachment 363390 [details] [review]
patch changing the initialisation to 2

The Gif patch breaks existing tests:

./tests/pixbuf-short-gif-write 
/animation/short_gif_write: **
ERROR:pixbuf-short-gif-write.c:32:loader_write_from_channel: assertion failed (error == NULL): Expected last byte to be >= 2, but is 0 (gdk-pixbuf-error-quark, 5)
fish: “./tests/pixbuf-short-gif-write” terminated by signal SIGABRT (Abort)


But the unpatched behaviour might as well be broken, given that UBSan complains with the messages I put in comment 0.

I cooked up a patch that seems to avoid the unintended array access.
Comment 5 Tobias Mueller 2017-11-11 15:33:06 UTC
The GIMP initialises that value to "2" also.  Thanks to Federico for finding that.

https://git.gnome.org/browse/gimp/tree/plug-ins/common/file-gif-load.c?id=fe3339e2156c3edf540bf548e8b149abe0f0a369#n693
Comment 6 Federico Mena Quintero 2017-11-11 16:01:16 UTC
Yes, please initialize it to 2; I think it's OK to also have the check as in your comment #2.

Specifically, the GIMP uses a buffer of the same size as gdk-pixbuf's.  To avoid a special case during the first read, it initializes the offset to 2; the buffer is zeroed out in the beginning, so the code in question just copies two zeros to the beginning of the buffer.
Comment 7 Bastien Nocera 2017-11-29 16:51:57 UTC
Review of attachment 363390 [details] [review]:

::: gdk-pixbuf/io-gif.c
@@ +1167,3 @@
 	context->code_curbit = 0;
 	context->code_lastbit = 0;
+	/* We later substract 2 from this value to peek into a buffer.

> later

Please be more precise as to where we do that. Please also add a note pointing to this comment where the "-2" is done.

@@ +1168,3 @@
 	context->code_lastbit = 0;
+	/* We later substract 2 from this value to peek into a buffer.
+	   In order to not get negative array index later, we set the value

Missing "*" at the start of the line.

@@ +1170,3 @@
+	   In order to not get negative array index later, we set the value
+	   to that magic 2 now.
+	 */

You can finish the comment on the same line as the last bits of text.
Comment 8 Bastien Nocera 2017-11-29 17:00:30 UTC
Are those 2 early patches also to review? Could you please attach the test file as a patch as well?
Comment 9 Tobias Mueller 2017-12-04 07:39:04 UTC
Created attachment 364884 [details] [review]
gif: Initialise code_last_byte to not cause undefined behaviour

Currently, code_last_byte is set only after it has been used, i.e.

    context->block_buf[0] = context->block_buf[context->code_last_byte - 2];

comes before anything has touched context->code_last_byte yet.
Except for the initialisation.
context->code_last_byte is set a few lines later, though.
And nowhere else, except for the initialisation which sets it
to 0.  That will inevitably lead to context->block_buf[-2] which is
undefined behaviour.

We hence set the code_last_byte to 2 in order to not make that
array index invalid.
Comment 10 Tobias Mueller 2017-12-04 07:41:12 UTC
(In reply to Bastien Nocera from comment #8)
> Are those 2 early patches also to review?
yes.
> Could you please attach the test file as a patch as well?
It's in https://bugzilla.gnome.org/attachment.cgi?id=34569
Comment 11 Bastien Nocera 2017-12-04 16:03:46 UTC
(In reply to Tobias Mueller from comment #10)
> (In reply to Bastien Nocera from comment #8)
> > Are those 2 early patches also to review?
> yes.
> > Could you please attach the test file as a patch as well?
> It's in https://bugzilla.gnome.org/attachment.cgi?id=34569

I'm guessing you ate the last digit and meant 345697. Thanks.
Comment 12 Bastien Nocera 2017-12-04 16:23:28 UTC
Review of attachment 345697 [details] [review]:

I've split up the test image in a separate patch as well.

::: gdk-pixbuf/io-gif.c
@@ +510,3 @@
 
+	if (context->code_last_byte < 2)
+	  {

The coding style is different in this file.

@@ +514,3 @@
+	                 GDK_PIXBUF_ERROR,
+	                 GDK_PIXBUF_ERROR_FAILED,
+	                 _("Expected last byte to be >= 2, but is %d"),

This is far too technical, this error message would appear in user interfaces. I'll try to find a more generic error message that doesn't add new translatable strings.
Comment 13 Bastien Nocera 2017-12-04 16:28:17 UTC
Created attachment 364925 [details] [review]
gif: Prevent access to negative array indexes

It seems that a pathological gif file can cause a negative array index
to be read.  UBSAN reported this:
io-gif.c:509:44: runtime error: index -2 out of bounds for type 'guchar [280]'
io-gif.c:510:44: runtime error: index -1 out of bounds for type 'guchar [280]'
Comment 14 Bastien Nocera 2017-12-04 16:28:31 UTC
Created attachment 364926 [details] [review]
tests: Add test for bug 778584
Comment 15 Bastien Nocera 2017-12-04 16:28:40 UTC
Created attachment 364927 [details] [review]
gif: Preventing undefined behaviour by making left shift unsigned

io-gif.c:509:44: runtime error: index -2 out of bounds for type 'guchar [280]'
io-gif.c:510:44: runtime error: index -1 out of bounds for type 'guchar [280]'
io-gif-animation.c:422:68: runtime error: left shift of 249 by 24 places cannot be represented in type 'int'
Comment 16 Bastien Nocera 2017-12-04 16:28:45 UTC
Created attachment 364928 [details] [review]
gif: Initialise code_last_byte to not cause undefined behaviour

Currently, code_last_byte is set only after it has been used, i.e.

    context->block_buf[0] = context->block_buf[context->code_last_byte - 2];

comes before anything has touched context->code_last_byte yet.
Except for the initialisation.
context->code_last_byte is set a few lines later, though.
And nowhere else, except for the initialisation which sets it
to 0.  That will inevitably lead to context->block_buf[-2] which is
undefined behaviour.

We hence set the code_last_byte to 2 in order to not make that
array index invalid.
Comment 17 Bastien Nocera 2017-12-04 16:32:10 UTC
Attachment 364925 [details] pushed as 23e2a7c - gif: Prevent access to negative array indexes
Attachment 364926 [details] pushed as af94eab - tests: Add test for bug 778584
Attachment 364927 [details] pushed as ced897e - gif: Preventing undefined behaviour by making left shift unsigned
Attachment 364928 [details] pushed as c1fd9f5 - gif: Initialise code_last_byte to not cause undefined behaviour