diff --git a/libavcodec/ws-snd1.c b/libavcodec/ws-snd1.c index 959c7bb1d9..06bd18c529 100644 --- a/libavcodec/ws-snd1.c +++ b/libavcodec/ws-snd1.c @@ -61,6 +61,11 @@ static int ws_snd_decode_frame(AVCodecContext *avctx, if (!buf_size) return 0; + if (buf_size < 4) { + av_log(avctx, AV_LOG_ERROR, "packet is too small\n"); + return AVERROR(EINVAL); + } + out_size = AV_RL16(&buf[0]); in_size = AV_RL16(&buf[2]); buf += 4; @@ -74,20 +79,37 @@ static int ws_snd_decode_frame(AVCodecContext *avctx, return -1; } - *data_size = out_size; - if (in_size == out_size) { for (i = 0; i < out_size; i++) *samples++ = *buf++; + *data_size = out_size; return buf_size; } - while (out_size > 0) { - int code; + while (out_size > 0 && buf - avpkt->data < buf_size) { + int code, smp, size; uint8_t count; code = (*buf) >> 6; count = (*buf) & 0x3F; buf++; + + /* make sure we don't write more than out_size samples */ + switch (code) { + case 0: smp = 4; break; + case 1: smp = 2; break; + case 2: smp = (count & 0x20) ? 1 : count + 1; break; + default: smp = count + 1; break; + } + if (out_size < smp) { + out_size = 0; + break; + } + + /* make sure we don't read past the input buffer */ + size = ((code == 2 && (count & 0x20)) || code == 3) ? 0 : count + 1; + if ((buf - avpkt->data) + size > buf_size) + break; + switch(code) { case 0: /* ADPCM 2-bit */ for (count++; count > 0; count--) { @@ -144,6 +166,8 @@ static int ws_snd_decode_frame(AVCodecContext *avctx, } } + *data_size = samples - (uint8_t *)data; + return buf_size; }