From: "Ronald S. Bultje" <[email protected]>

WMApro (and all wma variants) actually support 13-bits block sizes, and
thus we should support that also. Some WMA functions do not enforce the
12-bit maximum, which causes crashes when decoding such a file because
it expects bigger buffers, which aren't there, causing overreads/writes
and all kind of bad stuff.

If we get block sizes beyond what the decoder can handle (14 is possible
in wmapro, but decoder doesn't handle it, and wma1/2 only handles up to
11), error out instead of crashing.
---
 libavcodec/sinewin.h          |    3 ++-
 libavcodec/sinewin_tablegen.c |    2 +-
 libavcodec/sinewin_tablegen.h |    3 ++-
 libavcodec/wma.c              |   14 +++++++++++---
 libavcodec/wma.h              |    5 +++--
 libavcodec/wmaprodec.c        |   12 ++++++++----
 6 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/libavcodec/sinewin.h b/libavcodec/sinewin.h
index eefe5bf..8054191 100644
--- a/libavcodec/sinewin.h
+++ b/libavcodec/sinewin.h
@@ -53,7 +53,8 @@ extern SINETABLE( 512);
 extern SINETABLE(1024);
 extern SINETABLE(2048);
 extern SINETABLE(4096);
+extern SINETABLE(8192);
 
-extern SINETABLE_CONST float * const ff_sine_windows[13];
+extern SINETABLE_CONST float * const ff_sine_windows[14];
 
 #endif /* AVCODEC_SINEWIN_H */
diff --git a/libavcodec/sinewin_tablegen.c b/libavcodec/sinewin_tablegen.c
index 2f4d1aa..d5e0689 100644
--- a/libavcodec/sinewin_tablegen.c
+++ b/libavcodec/sinewin_tablegen.c
@@ -38,7 +38,7 @@ int main(void)
 
     write_fileheader();
 
-    for (i = 5; i <= 12; i++) {
+    for (i = 5; i <= 13; i++) {
         ff_init_ff_sine_windows(i);
         printf("SINETABLE(%4i) = {\n", 1 << i);
         write_float_array(ff_sine_windows[i], 1 << i);
diff --git a/libavcodec/sinewin_tablegen.h b/libavcodec/sinewin_tablegen.h
index 720f1ab..7d92026 100644
--- a/libavcodec/sinewin_tablegen.h
+++ b/libavcodec/sinewin_tablegen.h
@@ -38,6 +38,7 @@ SINETABLE( 512);
 SINETABLE(1024);
 SINETABLE(2048);
 SINETABLE(4096);
+SINETABLE(8192);
 #else
 #include "libavcodec/sinewin_tables.h"
 #endif
@@ -45,7 +46,7 @@ SINETABLE(4096);
 SINETABLE_CONST float * const ff_sine_windows[] = {
     NULL, NULL, NULL, NULL, NULL, // unused
     ff_sine_32 , ff_sine_64 ,
-    ff_sine_128, ff_sine_256, ff_sine_512, ff_sine_1024, ff_sine_2048, 
ff_sine_4096
+    ff_sine_128, ff_sine_256, ff_sine_512, ff_sine_1024, ff_sine_2048, 
ff_sine_4096, ff_sine_8192
 };
 
 // Generate a sine window.
diff --git a/libavcodec/wma.c b/libavcodec/wma.c
index 4eaf6fc..8c1186c 100644
--- a/libavcodec/wma.c
+++ b/libavcodec/wma.c
@@ -74,8 +74,9 @@ static void init_coef_vlc(VLC *vlc, uint16_t **prun_table,
  *@param decode_flags codec compression features
  *@return log2 of the number of output samples per frame
  */
-int av_cold ff_wma_get_frame_len_bits(int sample_rate, int version,
-                                      unsigned int decode_flags)
+int av_cold ff_wma_get_frame_len_bits(AVCodecContext *avctx,
+                                      int sample_rate, int version,
+                                      unsigned int decode_flags, int max)
 {
 
     int frame_len_bits;
@@ -104,6 +105,11 @@ int av_cold ff_wma_get_frame_len_bits(int sample_rate, int 
version,
         }
     }
 
+    if (frame_len_bits > max) {
+        av_log_missing_feature(avctx, "High frame len bits", 1);
+        return AVERROR_INVALIDDATA;
+    }
+
     return frame_len_bits;
 }
 
@@ -136,7 +142,9 @@ int ff_wma_init(AVCodecContext *avctx, int flags2)
     }
 
     /* compute MDCT block size */
-    s->frame_len_bits = ff_wma_get_frame_len_bits(s->sample_rate, s->version, 
0);
+    s->frame_len_bits = ff_wma_get_frame_len_bits(avctx,
+                                                  s->sample_rate, s->version,
+                                                  0, BLOCK_MAX_BITS);
     s->next_block_len_bits = s->frame_len_bits;
     s->prev_block_len_bits = s->frame_len_bits;
     s->block_len_bits      = s->frame_len_bits;
diff --git a/libavcodec/wma.h b/libavcodec/wma.h
index 4acbf04..8d6452a 100644
--- a/libavcodec/wma.h
+++ b/libavcodec/wma.h
@@ -150,8 +150,9 @@ extern const float ff_wma_lsp_codebook[NB_LSP_COEFS][16];
 extern const uint32_t ff_aac_scalefactor_code[121];
 extern const uint8_t  ff_aac_scalefactor_bits[121];
 
-int av_cold ff_wma_get_frame_len_bits(int sample_rate, int version,
-                                      unsigned int decode_flags);
+int av_cold ff_wma_get_frame_len_bits(AVCodecContext *avctx,
+                                      int sample_rate, int version,
+                                      unsigned int decode_flags, int max);
 int ff_wma_init(AVCodecContext * avctx, int flags2);
 int ff_wma_total_gain_to_bits(int total_gain);
 int ff_wma_end(AVCodecContext *avctx);
diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
index a1b82db..15162a1 100644
--- a/libavcodec/wmaprodec.c
+++ b/libavcodec/wmaprodec.c
@@ -105,7 +105,7 @@
 #define MAX_FRAMESIZE  32768                                 ///< maximum 
compressed frame size
 
 #define WMAPRO_BLOCK_MIN_BITS  6                                           
///< log2 of min block size
-#define WMAPRO_BLOCK_MAX_BITS 12                                           
///< log2 of max block size
+#define WMAPRO_BLOCK_MAX_BITS 13                                           
///< log2 of max block size
 #define WMAPRO_BLOCK_MAX_SIZE (1 << WMAPRO_BLOCK_MAX_BITS)                 
///< maximum block size
 #define WMAPRO_BLOCK_SIZES    (WMAPRO_BLOCK_MAX_BITS - WMAPRO_BLOCK_MIN_BITS + 
1) ///< possible block sizes
 
@@ -276,7 +276,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
     WMAProDecodeCtx *s = avctx->priv_data;
     uint8_t *edata_ptr = avctx->extradata;
     unsigned int channel_mask;
-    int i;
+    int i, bits;
     int log2_max_num_subframes;
     int num_possible_block_sizes;
 
@@ -310,8 +310,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
     s->len_prefix  = (s->decode_flags & 0x40);
 
     /** get frame len */
-    s->samples_per_frame = 1 << ff_wma_get_frame_len_bits(avctx->sample_rate,
-                                                          3, s->decode_flags);
+    bits = ff_wma_get_frame_len_bits(s->avctx, avctx->sample_rate,
+                                     3, s->decode_flags,
+                                     WMAPRO_BLOCK_MAX_BITS);
+    if (bits < 0)
+        return bits;
+    s->samples_per_frame = 1 << bits;
 
     /** subframe info */
     log2_max_num_subframes       = ((s->decode_flags & 0x38) >> 3);
-- 
1.7.7.4

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to