shithub: jbig2

Download patch

ref: dc14b5a69be02341d84e2956131f93f962408af2
parent: 0665a13dcda6ab99dd93c1002d52e0206c7ecb0b
author: Sebastian Rasmussen <sebras@gmail.com>
date: Fri Mar 27 01:41:07 EDT 2020

jbig2dec: Adjust number of bytes consumed by MMR decoder.

The MMR decoder pre-buffers up to 32 bits of encoded input data in a word
buffer before they are consumed by the MMR decoder. Once bits are consumed, the
pre-buffer will be filled up with more input data. When filling up the buffer
the decoder would previously stay clear of reading data belonging to succeeding
segments, but still indicated that it consumed those bytes it never read. Once
finished the MMR decoder lied to the caller by propagating the incorrect number
of consumed bytes. The caller subtracted the consumed number of bytes from the
size and end up in underflow causing the next MMR decoding to first read input
data at the wrong location, later ending up attempting to read outside the MMR
encoded input buffer.

Now, the MMR decoder keeps track of how many bits it has consumed and
accurately rounds this number up to a whole number of bytes to the caller.

Fixes OSS-fuzz issue 17855.

Thanks to OSS-fuzz for reporting.

--- a/jbig2_mmr.c
+++ b/jbig2_mmr.c
@@ -45,6 +45,7 @@
     uint32_t height;
     const byte *data;
     size_t size;
+    size_t consumed_bits;
     uint32_t data_index;
     uint32_t bit_index;
     uint32_t word;
@@ -58,30 +59,34 @@
 static void
 jbig2_decode_mmr_init(Jbig2MmrCtx *mmr, int width, int height, const byte *data, size_t size)
 {
-    size_t i;
-    uint32_t word = 0;
-
     mmr->width = width;
     mmr->height = height;
     mmr->data = data;
     mmr->size = size;
     mmr->data_index = 0;
-    mmr->bit_index = 0;
+    mmr->bit_index = 32;
+    mmr->word = 0;
+    mmr->consumed_bits = 0;
 
-    for (i = 0; i < size && i < 4; i++)
-        word |= (data[i] << ((3 - i) << 3));
-    mmr->word = word;
+    while (mmr->bit_index >= 8 && mmr->data_index < mmr->size) {
+        mmr->bit_index -= 8;
+        mmr->word |= (mmr->data[mmr->data_index] << mmr->bit_index);
+        mmr->data_index++;
+    }
 }
 
 static void
 jbig2_decode_mmr_consume(Jbig2MmrCtx *mmr, int n_bits)
 {
+    mmr->consumed_bits += n_bits;
+    if (mmr->consumed_bits > mmr->size * 8)
+        mmr->consumed_bits = mmr->size * 8;
+
     mmr->word <<= n_bits;
     mmr->bit_index += n_bits;
-    while (mmr->bit_index >= 8) {
+    while (mmr->bit_index >= 8 && mmr->data_index < mmr->size) {
         mmr->bit_index -= 8;
-        if (mmr->data_index + 4 < mmr->size)
-            mmr->word |= (mmr->data[mmr->data_index + 4] << mmr->bit_index);
+        mmr->word |= (mmr->data[mmr->data_index] << mmr->bit_index);
         mmr->data_index++;
     }
 }
@@ -1259,6 +1264,6 @@
         jbig2_decode_mmr_consume(&mmr, 24);
     }
 
-    *consumed_bytes += mmr.data_index + (mmr.bit_index >> 3) + (mmr.bit_index > 0 ? 1 : 0);
+    *consumed_bytes += (mmr.consumed_bits + 7) / 8;
     return code;
 }