From ed4632345ef8edd8ce07403bb4a4996d8c8f440a Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin <jmvalin@jmvalin.ca> Date: Fri, 11 Oct 2013 18:06:00 -0400 Subject: [PATCH] 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. --- src/opus_decoder.c | 19 +++++++------- src/opus_multistream_decoder.c | 46 ++++++++++++++++++++++++++++++++++ src/opus_private.h | 4 +++ 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/opus_decoder.c b/src/opus_decoder.c index 5b56ac1f6..ee0c9f560 100644 --- a/src/opus_decoder.c +++ b/src/opus_decoder.c @@ -355,7 +355,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, 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 parse_size(const unsigned char *data, opus_int32 len, opus_int16 *siz } } -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 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, 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 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, if (out_toc) *out_toc = toc; - if (payload_offset) - *payload_offset = (int)(data-data0); - return count; } @@ -777,6 +777,9 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, 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 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, 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; diff --git a/src/opus_multistream_decoder.c b/src/opus_multistream_decoder.c index f3d2311e4..d04a99f34 100644 --- a/src/opus_multistream_decoder.c +++ b/src/opus_multistream_decoder.c @@ -152,6 +152,37 @@ typedef void (*opus_copy_channel_out_func)( 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 @@ static int opus_multistream_decode_native( 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; diff --git a/src/opus_private.h b/src/opus_private.h index 0e739ebb0..aaf3cbf1d 100644 --- a/src/opus_private.h +++ b/src/opus_private.h @@ -112,6 +112,10 @@ static inline int align(int i) 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 */ -- GitLab