ref: 31e0aec4ef57166e8cbdc549e92435bc487ba9bb
parent: 861e081b86b9e4d6c8bf4ff6231025c7a950f6bf
author: Sebastian Rasmussen <sebras@gmail.com>
date: Mon Apr 23 10:02:46 EDT 2018
jbig2dec: Handle get_next_word() returning error/less than a word. This includes propagating the error handling to all callers.
--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -61,6 +61,7 @@
static void
jbig2_arith_bytein(Jbig2ArithState *as)
{
+ int new_bytes;
byte B;
/* invariant: as->next_word_bytes > 0 */
@@ -73,8 +74,10 @@
if (as->next_word_bytes == 1) {
Jbig2WordStream *ws = as->ws;
- ws->get_next_word(ws, as->offset, &as->next_word);
- as->offset += 4;
+ new_bytes = ws->get_next_word(ws, as->offset, &as->next_word);
+ as->next_word_bytes = new_bytes;
+ as->offset += new_bytes;
+
B1 = (byte)((as->next_word >> 24) & 0xFF);
if (B1 > 0x8F) {
#ifdef JBIG2_DEBUG_ARITH
@@ -84,8 +87,9 @@
as->C += 0xFF00;
#endif
as->CT = 8;
- as->next_word = (0xFF00 | B1) << 16;
- as->next_word_bytes = 2;
+ as->next_word = 0xFF000000 | (as->next_word >> 8);
+ as->next_word_bytes = 4;
+ as->offset--;
} else {
#ifdef JBIG2_DEBUG_ARITH
fprintf(stderr, "read %02x (a)\n", B);
@@ -96,7 +100,6 @@
as->C += B1 << 9;
#endif
as->CT = 7;
- as->next_word_bytes = 4;
}
} else {
B1 = (byte)((as->next_word >> 16) & 0xFF);
@@ -133,9 +136,9 @@
if (as->next_word_bytes == 0) {
Jbig2WordStream *ws = as->ws;
- ws->get_next_word(ws, as->offset, &as->next_word);
- as->offset += 4;
- as->next_word_bytes = 4;
+ new_bytes = ws->get_next_word(ws, as->offset, &as->next_word);
+ as->offset += new_bytes;
+ as->next_word_bytes = new_bytes;
}
B = (byte)((as->next_word >> 24) & 0xFF);
#ifdef SOFTWARE_CONVENTION
@@ -162,6 +165,7 @@
jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws)
{
Jbig2ArithState *result;
+ int new_bytes;
result = jbig2_new(ctx, Jbig2ArithState, 1);
if (result == NULL) {
@@ -171,9 +175,9 @@
result->ws = ws;
- ws->get_next_word(ws, 0, &result->next_word);
- result->next_word_bytes = 4;
- result->offset = 4;
+ new_bytes = ws->get_next_word(ws, 0, &result->next_word);
+ result->next_word_bytes = new_bytes;
+ result->offset = new_bytes;
/* Figure E.20 */
#ifdef SOFTWARE_CONVENTION
@@ -348,7 +352,7 @@
if (self == NULL || word == NULL)
return -1;
if (offset >= sizeof (test_stream))
- return -1;
+ return 0;
if (offset < sizeof(test_stream)) {
val |= test_stream[offset] << 24;
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -57,14 +57,14 @@
Jbig2Ctx *ctx;
};
-static uint32_t
-huff_get_next_word(Jbig2HuffmanState *hs, uint32_t offset)
+static int
+huff_get_next_word(Jbig2HuffmanState *hs, uint32_t offset, uint32_t *word)
{
- uint32_t word = 0;
Jbig2WordStream *ws = hs->ws;
- ws->get_next_word(ws, offset, &word);
- return word;
+ if (word == NULL)
+ return -1;
+ return ws->get_next_word(ws, offset, word);
}
/** Allocate and initialize a new huffman coding state
@@ -75,6 +75,7 @@
jbig2_huffman_new(Jbig2Ctx *ctx, Jbig2WordStream *ws)
{
Jbig2HuffmanState *result = NULL;
+ int code;
result = jbig2_new(ctx, Jbig2HuffmanState, 1);
@@ -84,8 +85,18 @@
result->offset_limit = 0;
result->ws = ws;
result->ctx = ctx;
- result->this_word = huff_get_next_word(result, 0);
- result->next_word = huff_get_next_word(result, 4);
+ code = huff_get_next_word(result, 0, &result->this_word);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed read first huffman word");
+ jbig2_huffman_free(ctx, result);
+ return NULL;
+ }
+ code = huff_get_next_word(result, 4, &result->next_word);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed read second huffman word");
+ jbig2_huffman_free(ctx, result);
+ return NULL;
+ }
} else {
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate new huffman coding state");
}
@@ -170,10 +181,11 @@
/** Skip bits up to the next byte boundary
*/
-void
+int
jbig2_huffman_skip(Jbig2HuffmanState *hs)
{
int bits = hs->offset_bits & 7;
+ int code;
if (bits) {
bits = 8 - bits;
@@ -184,19 +196,24 @@
if (hs->offset_bits >= 32) {
hs->this_word = hs->next_word;
hs->offset += 4;
- hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+ code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read next huffman word when skipping");
+ }
hs->offset_bits -= 32;
if (hs->offset_bits) {
hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
}
}
+ return 0;
}
/* skip ahead a specified number of bytes in the word stream
*/
-void
+int
jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset)
{
+ int code;
hs->offset += offset & ~3;
hs->offset_bits += (offset & 3) << 3;
if (hs->offset_bits >= 32) {
@@ -203,10 +220,17 @@
hs->offset += 4;
hs->offset_bits -= 32;
}
- hs->this_word = huff_get_next_word(hs, hs->offset);
- hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+ code = huff_get_next_word(hs, hs->offset, &hs->this_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get first huffman word after advancing");
+ }
+ code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get second huffman word after advancing");
+ }
if (hs->offset_bits > 0)
hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
+ return 0;
}
/* return the offset of the huffman decode pointer (in bytes)
@@ -226,6 +250,7 @@
{
uint32_t this_word = hs->this_word;
int32_t result;
+ int code;
if (hs->offset_limit && hs->offset >= hs->offset_limit) {
*err = -1;
@@ -238,7 +263,10 @@
hs->offset += 4;
hs->offset_bits -= 32;
hs->this_word = hs->next_word;
- hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+ code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+ }
if (hs->offset_bits) {
hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
} else {
@@ -271,6 +299,7 @@
for (;;) {
int log_table_size = table->log_table_size;
int PREFLEN;
+ int code;
/* SumatraPDF: shifting by the size of the operand is undefined */
entry = &table->entries[log_table_size > 0 ? this_word >> (32 - log_table_size) : 0];
@@ -287,7 +316,10 @@
if (offset_bits >= 32) {
this_word = next_word;
hs->offset += 4;
- next_word = huff_get_next_word(hs, hs->offset + 4);
+ code = huff_get_next_word(hs, hs->offset + 4, &next_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+ }
offset_bits -= 32;
hs->next_word = next_word;
PREFLEN = offset_bits;
@@ -303,6 +335,7 @@
RANGELEN = entry->RANGELEN;
if (RANGELEN > 0) {
int32_t HTOFFSET;
+ int code;
HTOFFSET = this_word >> (32 - RANGELEN);
if (flags & JBIG2_HUFFMAN_FLAGS_ISLOW)
@@ -314,7 +347,10 @@
if (offset_bits >= 32) {
this_word = next_word;
hs->offset += 4;
- next_word = huff_get_next_word(hs, hs->offset + 4);
+ code = huff_get_next_word(hs, hs->offset + 4, &next_word);
+ if (code < 0) {
+ return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+ }
offset_bits -= 32;
hs->next_word = next_word;
RANGELEN = offset_bits;
--- a/jbig2_huffman.h
+++ b/jbig2_huffman.h
@@ -60,9 +60,9 @@
void jbig2_huffman_free(Jbig2Ctx *ctx, Jbig2HuffmanState *hs);
-void jbig2_huffman_skip(Jbig2HuffmanState *hs);
+int jbig2_huffman_skip(Jbig2HuffmanState *hs);
-void jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset);
+int jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset);
uint32_t jbig2_huffman_offset(Jbig2HuffmanState *hs);
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -553,14 +553,15 @@
int code2 = 0;
int code3 = 0;
int code4 = 0;
+ int code5 = 0;
/* 6.5.8.2.2 (2, 3, 4, 5) */
if (params->SDHUFF) {
- ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code4);
- RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code1);
- RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
- BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code3);
- jbig2_huffman_skip(hs);
+ ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code1);
+ RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
+ RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code3);
+ BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code4);
+ code5 = jbig2_huffman_skip(hs);
} else {
code1 = jbig2_arith_iaid_decode(ctx, IAID, as, (int32_t *) & ID);
code2 = jbig2_arith_int_decode(ctx, IARDX, as, &RDX);
@@ -567,11 +568,11 @@
code3 = jbig2_arith_int_decode(ctx, IARDY, as, &RDY);
}
- if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0) {
+ if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
goto cleanup4;
}
- if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0) {
+ if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in single refinement/aggregate coded symbol data");
goto cleanup4;
}
@@ -615,7 +616,11 @@
if (params->SDHUFF) {
if (BMSIZE == 0)
BMSIZE = image->height * image->stride;
- jbig2_huffman_advance(hs, BMSIZE);
+ code = jbig2_huffman_advance(hs, BMSIZE);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding in refinement region");
+ goto cleanup4;
+ }
}
}
}
@@ -671,7 +676,10 @@
}
/* skip any bits before the next byte boundary */
- jbig2_huffman_skip(hs);
+ code = jbig2_huffman_skip(hs);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when decoding collective bitmap");
+ }
image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT);
if (image == NULL) {
@@ -725,7 +733,12 @@
}
/* advance past the data we've just read */
- jbig2_huffman_advance(hs, BMSIZE);
+ code = jbig2_huffman_advance(hs, BMSIZE);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding MMR bitmap image");
+ jbig2_image_release(ctx, image);
+ goto cleanup4;
+ }
/* copy the collective bitmap into the symbol dictionary */
x = 0;
--- a/jbig2_text.c
+++ b/jbig2_text.c
@@ -202,7 +202,12 @@
symcodeparams.n_lines = SBNUMSYMS;
/* skip to byte boundary */
- jbig2_huffman_skip(hs);
+ err = jbig2_huffman_skip(hs);
+ if (err < 0)
+ {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when building huffman table");
+ goto cleanup1;
+ }
/* finally, construct the symbol id huffman table itself */
SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams);
@@ -383,6 +388,7 @@
int code3 = 0;
int code4 = 0;
int code5 = 0;
+ int code6 = 0;
/* 6.4.11 (1, 2, 3, 4) */
if (!params->SBHUFF) {
@@ -396,15 +402,15 @@
RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3);
RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4);
BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5);
- jbig2_huffman_skip(hs);
+ code6 = jbig2_huffman_skip(hs);
}
- if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
+ if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0 || code6 < 0) {
jbig2_image_release(ctx, IB);
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
goto cleanup2;
}
- if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
+ if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0 || code6 > 0) {
jbig2_image_release(ctx, IB);
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance refinement data");
goto cleanup2;
@@ -447,7 +453,13 @@
/* 6.4.11 (7) */
if (params->SBHUFF) {
- jbig2_huffman_advance(hs, BMSIZE);
+ code = jbig2_huffman_advance(hs, BMSIZE);
+ if (code < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding refinement region");
+ jbig2_image_release(ctx, refimage);
+ jbig2_image_release(ctx, IBO);
+ goto cleanup2;
+ }
}
}