[FFmpeg-cvslog] binkaudio: add some buffer overread checks.

Justin Ruggles git at videolan.org
Fri Nov 4 20:49:30 CET 2011


ffmpeg | branch: release/0.7 | Justin Ruggles <justin.ruggles at gmail.com> | Tue Oct 25 13:47:50 2011 -0400| [8491677ab632f89f31bb26e48c8d1c429be07928] | committer: Michael Niedermayer

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 at gmx.at>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=8491677ab632f89f31bb26e48c8d1c429be07928
---

 libavcodec/binkaudio.c |   47 +++++++++++++++++++++++++++++++++++++----------
 1 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c
index ff36458..3b65a19 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);
     }



More information about the ffmpeg-cvslog mailing list