Stop indefinite recursion for Huffman Image.

Ensure that the lossless bit-stream doesn't allow for such cases and
safe-gaurd decoder against indefinite recursion.

Change-Id: Ia6d7f519291de8739f79a977a5800982872aae71
This commit is contained in:
Vikas Arora 2012-06-07 11:09:34 +05:30
parent 814a063925
commit 70eb2bd687
2 changed files with 41 additions and 31 deletions

View File

@ -302,7 +302,7 @@ static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
}
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits) {
int color_cache_bits, int allow_recursion) {
int i, j;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_;
@ -310,12 +310,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
HTreeGroup* htree_groups = NULL;
int num_htree_groups = 1;
if (VP8LReadBits(br, 1)) { // use meta Huffman codes
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2;
const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
const int huffman_pixs = huffman_xsize * huffman_ysize;
if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
&huffman_image)) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
@ -862,7 +862,7 @@ static int DecodeImageStream(int xsize, int ysize,
// Read the Huffman codes (may recurse).
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
color_cache_bits);
color_cache_bits, is_level0);
if (!ok) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto End;

View File

@ -33,6 +33,10 @@ extern "C" {
#define MIN_HISTO_BITS 2
#define MAX_HISTO_BITS 9
// NO_HISTO_BITS needs to be large enough so that all bits in the image
// size are thrown away by shifting.
#define NO_HISTO_BITS (VP8L_IMAGE_SIZE_BITS + 1)
// -----------------------------------------------------------------------------
// Palette
@ -442,10 +446,11 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
int cache_bits, int histogram_bits) {
int i;
int ok = 0;
int write_histogram_image;
const int use_2d_locality = 1;
const int use_color_cache = (cache_bits > 0);
const int histogram_image_xysize =
(histogram_bits == NO_HISTO_BITS) ?
1 :
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
VP8LHistogramSet* histogram_image =
@ -456,7 +461,8 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
VP8LBackwardRefs refs;
uint16_t* const histogram_symbols =
(uint16_t*)malloc(histogram_image_xysize * sizeof(*histogram_symbols));
assert((histogram_bits >= 2 && histogram_bits <= 9) ||
histogram_bits == NO_HISTO_BITS);
if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
// Calculate backward references from ARGB image.
@ -488,30 +494,31 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
}
// Huffman image + meta huffman.
write_histogram_image = (histogram_image_size > 1);
VP8LWriteBits(bw, 1, write_histogram_image);
if (write_histogram_image) {
uint32_t* const histogram_argb =
(uint32_t*)malloc(histogram_image_xysize * sizeof(*histogram_argb));
int max_index = 0;
if (histogram_argb == NULL) goto Error;
for (i = 0; i < histogram_image_xysize; ++i) {
const int index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = 0xff000000 | (index << 8);
if (index >= max_index) {
max_index = index + 1;
if (histogram_bits != NO_HISTO_BITS) {
const int write_histogram_image = (histogram_image_size > 1);
VP8LWriteBits(bw, 1, write_histogram_image);
if (write_histogram_image) {
uint32_t* const histogram_argb =
(uint32_t*)malloc(histogram_image_xysize * sizeof(*histogram_argb));
int max_index = 0;
if (histogram_argb == NULL) goto Error;
for (i = 0; i < histogram_image_xysize; ++i) {
const int index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = 0xff000000 | (index << 8);
if (index >= max_index) {
max_index = index + 1;
}
}
}
histogram_image_size = max_index;
histogram_image_size = max_index;
assert(histogram_bits >= 2);
VP8LWriteBits(bw, 3, histogram_bits - 2);
ok = EncodeImageInternal(bw, histogram_argb,
VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits),
quality, 0, 0);
free(histogram_argb);
if (!ok) goto Error;
VP8LWriteBits(bw, 3, histogram_bits - 2);
ok = EncodeImageInternal(bw, histogram_argb,
VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits),
quality, 0, NO_HISTO_BITS);
free(histogram_argb);
if (!ok) goto Error;
}
}
// Store Huffman codes.
@ -601,7 +608,8 @@ static int ApplyPredictFilter(const VP8LEncoder* const enc,
assert(pred_bits >= 2);
VP8LWriteBits(bw, 3, pred_bits - 2);
if (!EncodeImageInternal(bw, enc->transform_data_,
transform_width, transform_height, quality, 0, 0)) {
transform_width, transform_height, quality, 0,
NO_HISTO_BITS)) {
return 0;
}
return 1;
@ -622,7 +630,8 @@ static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
assert(ccolor_transform_bits >= 2);
VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
if (!EncodeImageInternal(bw, enc->transform_data_,
transform_width, transform_height, quality, 0, 0)) {
transform_width, transform_height, quality, 0,
NO_HISTO_BITS)) {
return 0;
}
return 1;
@ -786,7 +795,8 @@ static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
for (i = palette_size - 1; i >= 1; --i) {
palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
}
if (!EncodeImageInternal(bw, palette, palette_size, 1, quality, 0, 0)) {
if (!EncodeImageInternal(bw, palette, palette_size, 1, quality, 0,
NO_HISTO_BITS)) {
err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
goto Error;
}