aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Aimar <fenrir@videolan.org>2011-09-24 23:52:23 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-10-01 20:24:52 +0200
commitf40b04e9178c0a5246271c857437c6745276479c (patch)
tree54c3405db2af754d314f162078ec316f95af0cc9
parentd92bfc98f9f64fa891ee4a3640ba6c55e90540ef (diff)
downloadffmpeg-f40b04e9178c0a5246271c857437c6745276479c.tar.gz
Prevent out of bound read in lz_unpack in vmd video decoder.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at> (cherry picked from commit 5127f465bd3e2cf9cbf66dea3cf7b481b522d266)
-rw-r--r--libavcodec/vmdav.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/libavcodec/vmdav.c b/libavcodec/vmdav.c
index f5f8598919..d7cf18d62b 100644
--- a/libavcodec/vmdav.c
+++ b/libavcodec/vmdav.c
@@ -72,9 +72,11 @@ typedef struct VmdVideoContext {
#define QUEUE_SIZE 0x1000
#define QUEUE_MASK 0x0FFF
-static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_len)
+static void lz_unpack(const unsigned char *src, int src_len,
+ unsigned char *dest, int dest_len)
{
const unsigned char *s;
+ const unsigned char *s_end;
unsigned char *d;
unsigned char *d_end;
unsigned char queue[QUEUE_SIZE];
@@ -87,8 +89,12 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le
unsigned int i, j;
s = src;
+ s_end = src + src_len;
d = dest;
d_end = d + dest_len;
+
+ if (s_end - s < 8)
+ return;
dataleft = AV_RL32(s);
s += 4;
memset(queue, 0x20, QUEUE_SIZE);
@@ -101,10 +107,10 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le
speclen = 100; /* no speclen */
}
- while (dataleft > 0) {
+ while (s_end - s > 0 && dataleft > 0) {
tag = *s++;
if ((tag == 0xFF) && (dataleft > 8)) {
- if (d + 8 > d_end)
+ if (d + 8 > d_end || s_end - s < 8)
return;
for (i = 0; i < 8; i++) {
queue[qpos++] = *d++ = *s++;
@@ -116,17 +122,22 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le
if (dataleft == 0)
break;
if (tag & 0x01) {
- if (d + 1 > d_end)
+ if (d + 1 > d_end || s_end - s < 1)
return;
queue[qpos++] = *d++ = *s++;
qpos &= QUEUE_MASK;
dataleft--;
} else {
+ if (s_end - s < 2)
+ return;
chainofs = *s++;
chainofs |= ((*s & 0xF0) << 4);
chainlen = (*s++ & 0x0F) + 3;
- if (chainlen == speclen)
+ if (chainlen == speclen) {
+ if (s_end - s < 1)
+ return;
chainlen = *s++ + 0xF + 3;
+ }
if (d + chainlen > d_end)
return;
for (j = 0; j < chainlen; j++) {
@@ -189,6 +200,7 @@ static void vmd_decode(VmdVideoContext *s)
/* point to the start of the encoded data */
const unsigned char *p = s->buf + 16;
+ const unsigned char *p_end = s->buf + s->size;
const unsigned char *pb;
unsigned char meth;
@@ -251,7 +263,7 @@ static void vmd_decode(VmdVideoContext *s)
pb = p;
meth = *pb++;
if (meth & 0x80) {
- lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size);
+ lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
meth &= 0x7F;
pb = s->unpack_buffer;
}