tiffdec: fix out of bound reads/writes
Signed-off-by: Janne Grunau <janne-libav@jannau.net>
(cherry picked from commit 04a845caa7)
Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
committed by
Reinhard Tartler
parent
d75c80e942
commit
4eb51d96dd
@@ -172,6 +172,8 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t* dst, int stride, const uin
|
|||||||
}
|
}
|
||||||
switch(s->compr){
|
switch(s->compr){
|
||||||
case TIFF_RAW:
|
case TIFF_RAW:
|
||||||
|
if (ssrc + size - src < width)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
if (!s->fill_order) {
|
if (!s->fill_order) {
|
||||||
memcpy(dst, src, width);
|
memcpy(dst, src, width);
|
||||||
} else {
|
} else {
|
||||||
@@ -279,6 +281,8 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
|
|||||||
uint32_t *pal;
|
uint32_t *pal;
|
||||||
const uint8_t *rp, *gp, *bp;
|
const uint8_t *rp, *gp, *bp;
|
||||||
|
|
||||||
|
if (end_buf - buf < 12)
|
||||||
|
return -1;
|
||||||
tag = tget_short(&buf, s->le);
|
tag = tget_short(&buf, s->le);
|
||||||
type = tget_short(&buf, s->le);
|
type = tget_short(&buf, s->le);
|
||||||
count = tget_long(&buf, s->le);
|
count = tget_long(&buf, s->le);
|
||||||
@@ -338,7 +342,7 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
|
|||||||
case TIFF_SHORT:
|
case TIFF_SHORT:
|
||||||
case TIFF_LONG:
|
case TIFF_LONG:
|
||||||
s->bpp = 0;
|
s->bpp = 0;
|
||||||
for(i = 0; i < count; i++) s->bpp += tget(&buf, type, s->le);
|
for(i = 0; i < count && buf < end_buf; i++) s->bpp += tget(&buf, type, s->le);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
s->bpp = -1;
|
s->bpp = -1;
|
||||||
@@ -452,6 +456,8 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start, const uint8_t *
|
|||||||
case TIFF_PAL:
|
case TIFF_PAL:
|
||||||
pal = (uint32_t *) s->palette;
|
pal = (uint32_t *) s->palette;
|
||||||
off = type_sizes[type];
|
off = type_sizes[type];
|
||||||
|
if (count / 3 > 256 || end_buf - buf < count / 3 * off * 3)
|
||||||
|
return -1;
|
||||||
rp = buf;
|
rp = buf;
|
||||||
gp = buf + count / 3 * off;
|
gp = buf + count / 3 * off;
|
||||||
bp = buf + count / 3 * off * 2;
|
bp = buf + count / 3 * off * 2;
|
||||||
@@ -494,12 +500,16 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
AVFrame *picture = data;
|
AVFrame *picture = data;
|
||||||
AVFrame * const p= (AVFrame*)&s->picture;
|
AVFrame * const p= (AVFrame*)&s->picture;
|
||||||
const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
|
const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
|
||||||
int id, le, off, ret;
|
unsigned off;
|
||||||
|
int id, le, ret;
|
||||||
int i, j, entries;
|
int i, j, entries;
|
||||||
int stride, soff, ssize;
|
int stride;
|
||||||
|
unsigned soff, ssize;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
|
|
||||||
//parse image header
|
//parse image header
|
||||||
|
if (end_buf - buf < 8)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
id = AV_RL16(buf); buf += 2;
|
id = AV_RL16(buf); buf += 2;
|
||||||
if(id == 0x4949) le = 1;
|
if(id == 0x4949) le = 1;
|
||||||
else if(id == 0x4D4D) le = 0;
|
else if(id == 0x4D4D) le = 0;
|
||||||
@@ -519,9 +529,9 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
}
|
}
|
||||||
/* parse image file directory */
|
/* parse image file directory */
|
||||||
off = tget_long(&buf, le);
|
off = tget_long(&buf, le);
|
||||||
if(orig_buf + off + 14 >= end_buf){
|
if (off >= UINT_MAX - 14 || end_buf - orig_buf < off + 14) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
|
av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
|
||||||
return -1;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
buf = orig_buf + off;
|
buf = orig_buf + off;
|
||||||
entries = tget_short(&buf, le);
|
entries = tget_short(&buf, le);
|
||||||
@@ -545,23 +555,23 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
stride = p->linesize[0];
|
stride = p->linesize[0];
|
||||||
dst = p->data[0];
|
dst = p->data[0];
|
||||||
for(i = 0; i < s->height; i += s->rps){
|
for(i = 0; i < s->height; i += s->rps){
|
||||||
if(s->stripsizes)
|
if(s->stripsizes) {
|
||||||
|
if (s->stripsizes >= end_buf)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
ssize = tget(&s->stripsizes, s->sstype, s->le);
|
ssize = tget(&s->stripsizes, s->sstype, s->le);
|
||||||
else
|
} else
|
||||||
ssize = s->stripsize;
|
ssize = s->stripsize;
|
||||||
|
|
||||||
if (ssize > buf_size) {
|
|
||||||
av_log(avctx, AV_LOG_ERROR, "Buffer size is smaller than strip size\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s->stripdata){
|
if(s->stripdata){
|
||||||
|
if (s->stripdata >= end_buf)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
soff = tget(&s->stripdata, s->sot, s->le);
|
soff = tget(&s->stripdata, s->sot, s->le);
|
||||||
}else
|
}else
|
||||||
soff = s->stripoff;
|
soff = s->stripoff;
|
||||||
if (soff < 0) {
|
|
||||||
av_log(avctx, AV_LOG_ERROR, "Invalid stripoff: %d\n", soff);
|
if (soff > buf_size || ssize > buf_size - soff) {
|
||||||
return AVERROR(EINVAL);
|
av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
if(tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize, FFMIN(s->rps, s->height - i)) < 0)
|
if(tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize, FFMIN(s->rps, s->height - i)) < 0)
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user