CUPS.org User: thoger
Petr Sklenar created a fuzzed gif image which triggers a heap corruption in the GIF reading code in CUPS.
The file triggers stack buffer overflow in gif_read_lzw() in filter/image-gif.c. Relevant code part is (line numbers are for 1.4.6):
661 while (code >= clear_code)
663 *sp++ = table[code];
664 if (code == table[code])
665 return (255);
667 code = table[code];
This ensures that table[code] != code, but it's possible to create loop between multiple table entries, if table[code] > code. I believe that's an incorrect case that should be detected in this part of the code:
655 if (code >= max_code)
657 *sp++ = firstcode;
658 code = oldcode;
That's the code for the LZW decoding special case. code == max_code seems to be the correct check to be used there, with code > max_code being invalid and should be rejected.
I've actually had a look at couple of other code bases that seem to have GIF reader derived from the same implementation as the one used by CUPS. Some of them reject code > max_code:
while other check for stack overflow in the while() loop:
This should not have any bad security implications for CUPS beyond filter crash, as this keeps looping until some unmapped memory is hit, without trying to use corrupted memory. I'm tagging this as security so you can review and decide how you want to handle this. Please let me know if you prefer to handle this as embargoed, as there are few other projects that seem to have this problem.
CUPS.org User: mike
We won't treat this as a security issue - as you say we'll just overflow and SIGBUS pretty quickly in imageto*.
Patch coming up...
Patch attached which also addresses STR #3868 and STR #3869. Please let me know if you think we need any further changes.
CUPS.org User: thoger
The fix looks reasonable to me, thank you!
Fixed in Subversion repository.
One thing I realized later, the crash as described above depends on stack being located above the table. If memory allocator places it below, stack overflow can result in table modification, which can break the infinite loop, and the program may continue executing with corrupted heap.
--- filter/image-gif.c (revision 9839)
+++ filter/image-gif.c (working copy)
@@ -353,7 +353,7 @@
* Read in another buffer...
Wipe the decompressor table (already mostly 0 due to the calloc above...)
fresh = 1;
table[i] = 0;
sp = stack;
@@ -605,30 +599,31 @@
fresh = 0;
if (sp > stack)
for (i = 0; i < clear_code; i ++)
\* Clear/reset the compression table...
memset(table, 0, 2 \* sizeof(gif_table_t));
for (i = 1; i < clear_code; i ++)
for (; i < 4096; i ++)
code_size = set_code_size + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
@@ -637,13 +632,12 @@
firstcode = oldcode = gif_get_code(fp, code_size, 0);
return (firstcode & 255);
unsigned char buf;
unsigned char buf; /\* Block buffer */
while (gif_get_block(fp, buf) > 0);
@@ -652,7 +646,7 @@
incode = code;
return ((*--sp) & 255);
return (code & 255);