shithub: opus

Download patch

ref: ed4632345ef8edd8ce07403bb4a4996d8c8f440a
parent: aee4d8057632ea0cfc1d55d88acf8466b47b7b4b
author: Jean-Marc Valin <[email protected]>
date: Fri Oct 11 14:06:00 EDT 2013

Do up-front validation of multistream packets

Prevents the decoder from being out-of-sync on an invalid packet. Also
returns OPUS_INVALID_PACKET on a corrupted FEC packet.

--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -355,7 +355,7 @@
                  pcm_ptr[i] = 0;
            } else {
              RESTORE_STACK;
-             return OPUS_INVALID_PACKET;
+             return OPUS_INTERNAL_ERROR;
            }
         }
         pcm_ptr += silk_frame_size * st->channels;
@@ -581,7 +581,7 @@
    }
 }
 
-static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
       int self_delimited, unsigned char *out_toc,
       const unsigned char *frames[48], opus_int16 size[48], int *payload_offset)
 {
@@ -710,6 +710,9 @@
       size[count-1] = (opus_int16)last_size;
    }
 
+   if (payload_offset)
+      *payload_offset = (int)(data-data0);
+
    if (frames)
    {
       for (i=0;i<count;i++)
@@ -722,9 +725,6 @@
    if (out_toc)
       *out_toc = toc;
 
-   if (payload_offset)
-      *payload_offset = (int)(data-data0);
-
    return count;
 }
 
@@ -777,6 +777,9 @@
 
    count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
 
+   if (count<0)
+      return count;
+
    data += offset;
 
    if (decode_fec)
@@ -814,11 +817,7 @@
          return frame_size;
       }
    }
-   tot_offset = 0;
-   if (count < 0)
-      return count;
-
-   tot_offset += offset;
+   tot_offset = offset;
 
    if (count*packet_frame_size > frame_size)
       return OPUS_BUFFER_TOO_SMALL;
--- a/src/opus_multistream_decoder.c
+++ b/src/opus_multistream_decoder.c
@@ -152,6 +152,37 @@
   int frame_size
 );
 
+static int opus_multistream_packet_validate(const unsigned char *data,
+      opus_int32 len, int nb_streams)
+{
+   int s;
+   int i;
+   int count;
+   unsigned char toc;
+   opus_int16 size[48];
+   int offset;
+   int samples=0;
+
+   for (s=0;s<nb_streams;s++)
+   {
+      int tmp_samples;
+      if (len<=0)
+         return OPUS_INVALID_PACKET;
+      count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, size, &offset);
+      if (count<0)
+         return count;
+      for (i=0;i<count;i++)
+         offset += size[i];
+      tmp_samples = opus_packet_get_nb_samples(data, offset, 48000);
+      if (s!=0 && samples != tmp_samples)
+         return OPUS_INVALID_PACKET;
+      samples = tmp_samples;
+      data += offset;
+      len -= offset;
+   }
+   return OPUS_OK;
+}
+
 static int opus_multistream_decode_native(
       OpusMSDecoder *st,
       const unsigned char *data,
@@ -183,9 +214,24 @@
    if (len==0)
       do_plc = 1;
    if (len < 0)
+   {
+      RESTORE_STACK;
       return OPUS_BAD_ARG;
+   }
    if (!do_plc && len < 2*st->layout.nb_streams-1)
+   {
+      RESTORE_STACK;
       return OPUS_INVALID_PACKET;
+   }
+   if (!do_plc)
+   {
+      int ret = opus_multistream_packet_validate(data, len, st->layout.nb_coupled_streams);
+      if (ret < 0)
+      {
+         RESTORE_STACK;
+         return ret;
+      }
+   }
    for (s=0;s<st->layout.nb_streams;s++)
    {
       OpusDecoder *dec;
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -112,6 +112,10 @@
     return (i+(int)sizeof(void *)-1)&-(int)sizeof(void *);
 }
 
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+      int self_delimited, unsigned char *out_toc,
+      const unsigned char *frames[48], opus_int16 size[48], int *payload_offset);
+
 opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen, int self_delimited);
 
 #endif /* OPUS_PRIVATE_H */