diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2011-10-25 13:47:50 -0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-11-04 13:31:15 +0100 |
commit | 8491677ab632f89f31bb26e48c8d1c429be07928 (patch) | |
tree | 4b91f046f64321efe78f8dd0544948c7cfc9af16 | |
parent | f98bb0d3ec73b047121bcdf172cc809ac3c47013 (diff) | |
download | ffmpeg-8491677ab632f89f31bb26e48c8d1c429be07928.tar.gz |
binkaudio: add some buffer overread checks.
This stops decoding before overreads instead of after.
(cherry picked from commit 101ef19ef4dc9f5c3d536aee8fcc10fff2af4d9e)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavcodec/binkaudio.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c index ff36458c7e..3b65a19261 100644 --- a/libavcodec/binkaudio.c +++ b/libavcodec/binkaudio.c @@ -153,11 +153,18 @@ static const uint8_t rle_length_tab[16] = { 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64 }; +#define GET_BITS_SAFE(out, nbits) do { \ + if (get_bits_left(gb) < nbits) \ + return AVERROR_INVALIDDATA; \ + out = get_bits(gb, nbits); \ +} while (0) + /** * Decode Bink Audio block * @param[out] out Output buffer (must contain s->block_size elements) + * @return 0 on success, negative error code on failure */ -static void decode_block(BinkAudioContext *s, short *out, int use_dct) +static int decode_block(BinkAudioContext *s, short *out, int use_dct) { int ch, i, j, k; float q, quant[25]; @@ -170,13 +177,19 @@ static void decode_block(BinkAudioContext *s, short *out, int use_dct) for (ch = 0; ch < s->channels; ch++) { FFTSample *coeffs = s->coeffs_ptr[ch]; if (s->version_b) { + if (get_bits_left(gb) < 64) + return AVERROR_INVALIDDATA; coeffs[0] = av_int2flt(get_bits(gb, 32)) * s->root; coeffs[1] = av_int2flt(get_bits(gb, 32)) * s->root; } else { + if (get_bits_left(gb) < 58) + return AVERROR_INVALIDDATA; coeffs[0] = get_float(gb) * s->root; coeffs[1] = get_float(gb) * s->root; } + if (get_bits_left(gb) < s->num_bands * 8) + return AVERROR_INVALIDDATA; for (i = 0; i < s->num_bands; i++) { /* constant is result of 0.066399999/log10(M_E) */ int value = get_bits(gb, 8); @@ -191,15 +204,20 @@ static void decode_block(BinkAudioContext *s, short *out, int use_dct) while (i < s->frame_len) { if (s->version_b) { j = i + 16; - } else if (get_bits1(gb)) { - j = i + rle_length_tab[get_bits(gb, 4)] * 8; } else { - j = i + 8; + int v; + GET_BITS_SAFE(v, 1); + if (v) { + GET_BITS_SAFE(v, 4); + j = i + rle_length_tab[v] * 8; + } else { + j = i + 8; + } } j = FFMIN(j, s->frame_len); - width = get_bits(gb, 4); + GET_BITS_SAFE(width, 4); if (width == 0) { memset(coeffs + i, 0, (j - i) * sizeof(*coeffs)); i = j; @@ -209,9 +227,11 @@ static void decode_block(BinkAudioContext *s, short *out, int use_dct) while (i < j) { if (s->bands[k] == i) q = quant[k++]; - coeff = get_bits(gb, width); + GET_BITS_SAFE(coeff, width); if (coeff) { - if (get_bits1(gb)) + int v; + GET_BITS_SAFE(v, 1); + if (v) coeffs[i] = -q * coeff; else coeffs[i] = q * coeff; @@ -247,6 +267,8 @@ static void decode_block(BinkAudioContext *s, short *out, int use_dct) s->overlap_len * s->channels * sizeof(*out)); s->first = 0; + + return 0; } static av_cold int decode_end(AVCodecContext *avctx) @@ -278,12 +300,17 @@ static int decode_frame(AVCodecContext *avctx, int reported_size; GetBitContext *gb = &s->gb; + if (buf_size < 4) { + av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); + return AVERROR_INVALIDDATA; + } + init_get_bits(gb, buf, buf_size * 8); reported_size = get_bits_long(gb, 32); - while (get_bits_count(gb) / 8 < buf_size && - samples + s->block_size <= samples_end) { - decode_block(s, samples, avctx->codec->id == CODEC_ID_BINKAUDIO_DCT); + while (samples + s->block_size <= samples_end) { + if (decode_block(s, samples, avctx->codec->id == CODEC_ID_BINKAUDIO_DCT)) + break; samples += s->block_size; get_bits_align32(gb); } |