diff --git a/license.txt b/license.txt index 9aa2d475a..97c732b8f 100644 --- a/license.txt +++ b/license.txt @@ -111,7 +111,7 @@ This distribution contains code from the following projects (full license text b - simplewebp Website: https://github.com/MikuAuahDark/simplewebp - Source download: https://github.com/MikuAuahDark/simplewebp/blob/85157b0e5e115a76db87d5484570e44cf5c34e87/simplewebp.h + Source download: https://github.com/MikuAuahDark/simplewebp/blob/d1a728a1f8ec7348ca2a5039b6dd813b83986fbb/simplewebp.h License: 3-Clause BSD Copyright (c) 2010 Google Inc., 2023 Miku AuahDark diff --git a/src/libraries/simplewebp/simplewebp.h b/src/libraries/simplewebp/simplewebp.h index 65d2083ee..f8a34271c 100644 --- a/src/libraries/simplewebp/simplewebp.h +++ b/src/libraries/simplewebp/simplewebp.h @@ -4395,6 +4395,24 @@ static simplewebp_error swebp__vp8l_canonical_code( } } + if (symbol_count == 0) + return SIMPLEWEBP_CORRUPT_ERROR; + else if (symbol_count > 1) + { + int open_slots = 1; + + /* Max allowed code length is 15 */ + for (i = 0; i < 15; i++) + { + open_slots = (open_slots << 1) - base[i]; + if (open_slots < 0) + return SIMPLEWEBP_CORRUPT_ERROR; + } + + if (open_slots != 0) + return SIMPLEWEBP_CORRUPT_ERROR; + } + for (i = 0; i < 16; i++) { simplewebp_u16 c = base[i]; @@ -4480,6 +4498,8 @@ static simplewebp_error swebp__vp8l_decode_code_complex( if (br->eos) return SIMPLEWEBP_IO_ERROR; + if (limit > size) + return SIMPLEWEBP_CORRUPT_ERROR; err = swebp__vp8l_canonical_code(simplewebp, lencode_lengths, 19, &lc, lencode_treemem); if (err != SIMPLEWEBP_NO_ERROR) @@ -4496,10 +4516,7 @@ static simplewebp_error swebp__vp8l_decode_code_complex( c = 0; if (br->eos) - { - swebp__dealloc(simplewebp, lc.tree); return SIMPLEWEBP_IO_ERROR; - } switch (s) { @@ -4540,10 +4557,9 @@ static simplewebp_error swebp__vp8l_decode_code_complex( } if (br->eos) - { - swebp__dealloc(simplewebp, lc.tree); return SIMPLEWEBP_IO_ERROR; - } + if (s > (size - count)) + return SIMPLEWEBP_CORRUPT_ERROR; while (s--) lengths[count++] = (simplewebp_u8) c; @@ -4562,11 +4578,36 @@ static simplewebp_error swebp__vp8l_decode_code( { if (swebp__vp8l_bitread_read(br, 1)) { + simplewebp_u8 symbol[2]; simplewebp_bool two_symbols = (simplewebp_bool) swebp__vp8l_bitread_read(br, 1); + symbol[0] = (simplewebp_u8) swebp__vp8l_bitread_read(br, 1 + swebp__vp8l_bitread_read(br, 1) * 7); + symbol[1] = two_symbols ? ((simplewebp_u8) swebp__vp8l_bitread_read(br, 8)) : 0; + + if (br->eos) + return SIMPLEWEBP_IO_ERROR; + if (symbol[0] >= size || (two_symbols && symbol[1] >= size)) + return SIMPLEWEBP_CORRUPT_ERROR; + + if (two_symbols) + { + /* Reorder symbol if needed */ + if (symbol[0] > symbol[1]) + { + simplewebp_u8 tempsym = symbol[0]; + symbol[0] = symbol[1]; + symbol[1] = tempsym; + } + else if (symbol[0] == symbol[1]) + { + two_symbols = 0; + symbol[1] = 0; + } + } + code->tree = NULL; - code->size = two_symbols + 1; - code->symbol[0] = swebp__vp8l_bitread_read(br, 1 + swebp__vp8l_bitread_read(br, 1) * 7); - code->symbol[1] = two_symbols ? swebp__vp8l_bitread_read(br, 8) : 0; + code->size = (simplewebp_u16) two_symbols + 1; + code->symbol[0] = symbol[0]; + code->symbol[1] = symbol[1]; return br->eos ? SIMPLEWEBP_IO_ERROR : SIMPLEWEBP_NO_ERROR; } else @@ -4613,8 +4654,13 @@ static simplewebp_error swebp__vp8l_decode_group( static size_t swebp__hash_color(simplewebp_u8 bits, struct swebp__pixel c) { - size_t value = (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b; - return ((0x1e35a7bd * value) & 0xFFFFFFFF) >> (32 - bits); + simplewebp_u32 r, g, b, a, value; + r = c.r; + g = c.g; + b = c.b; + a = c.a; + value = (a << 24) | (r << 16) | (g << 8) | b; + return ((0x1e35a7bdU * value) & 0xFFFFFFFFU) >> (32 - bits); } static void swebp__vp8l_put_cache(simplewebp_u8 bits, struct swebp__pixel *ccache, struct swebp__pixel color) @@ -4643,13 +4689,16 @@ static simplewebp_error swebp__decode_vp8l_image( struct swebp__pixel **dest ) { + simplewebp_bool has_ccache; simplewebp_u8 ccache_bits, entropy_bits; struct swebp__pixel *color_cache, *entropy, *image; struct swebp__vp8l_group *groups; - size_t group_count, entropy_stride, i; + size_t group_count, entropy_stride, i, dimensions; simplewebp_error err; + dimensions = width * height; color_cache = NULL; + ccache_bits = 0; group_count = 1; entropy_bits = 0; entropy_stride = 0; @@ -4664,14 +4713,25 @@ static simplewebp_error swebp__decode_vp8l_image( } image = *dest; - ccache_bits = swebp__vp8l_bitread_read(br, 1) ? swebp__vp8l_bitread_read(br, 4) : 0; + has_ccache = (simplewebp_bool) swebp__vp8l_bitread_read(br, 1); if (br->eos) return SIMPLEWEBP_IO_ERROR; - if (ccache_bits) + + if (has_ccache) { - color_cache = (struct swebp__pixel*) swebp__alloc(simplewebp, (1 << ccache_bits) * 4); + size_t ccache_bits_size; + ccache_bits = (simplewebp_u8) swebp__vp8l_bitread_read(br, 4); + if (br->eos) + return SIMPLEWEBP_IO_ERROR; + if (ccache_bits < 1 || ccache_bits > 11) + return SIMPLEWEBP_CORRUPT_ERROR; + + ccache_bits_size = (1 << ccache_bits) * 4; + color_cache = (struct swebp__pixel*) swebp__alloc(simplewebp, ccache_bits_size); if (!color_cache) return SIMPLEWEBP_ALLOC_ERROR; + + memset(color_cache, 0, ccache_bits_size); } if (is_main) @@ -4733,7 +4793,7 @@ static simplewebp_error swebp__decode_vp8l_image( if (err == SIMPLEWEBP_NO_ERROR) { /* Main image decoding routines. */ - for (i = 0; i < width * height;) + for (i = 0; i < dimensions;) { struct swebp__pixel *pixel; struct swebp__vp8l_group *g = groups; @@ -4754,6 +4814,11 @@ static simplewebp_error swebp__decode_vp8l_image( } codeword = swebp__vp8l_read_code(br, &g->code[0]); + if (br->eos) + { + err = SIMPLEWEBP_IO_ERROR; + break; + } if (codeword < swebp__vp8l_literals_count) { @@ -4762,6 +4827,12 @@ static simplewebp_error swebp__decode_vp8l_image( color.g = (simplewebp_u8) codeword; color.b = (simplewebp_u8) swebp__vp8l_read_code(br, &g->code[2]); color.a = (simplewebp_u8) swebp__vp8l_read_code(br, &g->code[3]); + if (br->eos) + { + err = SIMPLEWEBP_IO_ERROR; + break; + } + *pixel = color; i++; @@ -4777,12 +4848,26 @@ static simplewebp_error swebp__decode_vp8l_image( distcode = swebp__vp8l_read_code(br, &g->code[4]); distance = swebp__vp8l_lendst(br, distcode); + if (br->eos) + { + err = SIMPLEWEBP_IO_ERROR; + break; + } + if (distance < swebp__vp8l_offset_count) - offset = swebp__vp8l_offsets[distance][0] + swebp__vp8l_offsets[distance][1] * width; + offset = (ptrdiff_t) swebp__vp8l_offsets[distance][0] + + (ptrdiff_t) swebp__vp8l_offsets[distance][1] + * (ptrdiff_t) width; else - offset = distance - swebp__vp8l_offset_count + 1; + offset = (ptrdiff_t) (distance - swebp__vp8l_offset_count + 1); offset = offset < 1 ? 1 : offset; + if ((size_t) offset > i || (length + 1) > (dimensions - i)) + { + err = SIMPLEWEBP_CORRUPT_ERROR; + break; + } + for (j = 0; j <= length; j++) { *pixel = pixel[-offset]; @@ -4796,6 +4881,12 @@ static simplewebp_error swebp__decode_vp8l_image( *pixel = color_cache[codeword - swebp__vp8l_litlen_count]; i++; } + + if (br->eos) + { + err = SIMPLEWEBP_IO_ERROR; + break; + } } } @@ -4943,10 +5034,10 @@ static struct swebp__pixel swebp__clamp_add_subtract_half(struct swebp__pixel a, static struct swebp__pixel swebp__apply_predictor( simplewebp_u8 type, - struct swebp__pixel *l, - struct swebp__pixel *tl, - struct swebp__pixel *t, - struct swebp__pixel *tr + const struct swebp__pixel *l, + const struct swebp__pixel *tl, + const struct swebp__pixel *t, + const struct swebp__pixel *tr ) { const struct swebp__pixel black = {0, 0, 0, 255}; @@ -5000,30 +5091,48 @@ static void swebp__apply_predictor_transform( { size_t x, y; size_t tiles_per_row = swebp__subsample_size(width, bits); + const struct swebp__pixel black = {0, 0, 0, 255}; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { + const struct swebp__pixel *l, *tl, *t, *tr; struct swebp__pixel result; simplewebp_u8 type = 0; + l = tl = t = tr = &black; + if (x > 0) { + l = rgba - 1; + if (y > 0) { size_t tile_x = x >> bits; size_t tile_y = y >> bits; size_t tile_index = tile_y * tiles_per_row + tile_x; type = predictor_data[tile_index].g; + tl = rgba - width - 1; + t = rgba - width; + tr = rgba - width + 1; } else type = 1; } else - type = y > 0 ? 2 : 0; + { + if (y > 0) + { + type = 2; + t = rgba - width; + tr = rgba - width + 1; + } + else + type = 0; + } - result = swebp__apply_predictor(type, rgba - 1, rgba - (width + 1), rgba - width, rgba - (width - 1)); + result = swebp__apply_predictor(type, l, tl, t, tr); rgba->r += result.r; rgba->g += result.g; rgba->b += result.b; @@ -5177,7 +5286,10 @@ static simplewebp_error swebp__decode_lossless_bitstream_main( ttype = swebp__vp8l_bitread_read(br, 2); if (br->eos) + { + swebp__batch_free(simplewebp, (void **) filter_data, 4); return SIMPLEWEBP_CORRUPT_ERROR; + } switch (ttype) { @@ -5214,6 +5326,8 @@ static simplewebp_error swebp__decode_lossless_bitstream_main( if (err != SIMPLEWEBP_NO_ERROR) { /* Error occured. Rollback. */ + if (filter_out) + swebp__dealloc(simplewebp, filter_out); swebp__batch_free(simplewebp, (void **) filter_data, 4); return err; } @@ -5457,6 +5571,7 @@ simplewebp_error simplewebp_load_from_file(FILE *file, const simplewebp_allocato simplewebp_input input; simplewebp_error err; + *out = NULL; err = simplewebp_input_from_file(file, &input); if (err != SIMPLEWEBP_NO_ERROR) return err; @@ -5473,6 +5588,7 @@ simplewebp_error simplewebp_load_from_filename(const char *filename, const simpl simplewebp_input input; simplewebp_error err; + *out = NULL; err = simplewebp_input_from_filename(filename, &input); if (err != SIMPLEWEBP_NO_ERROR) return err;