tiff: add smarter checks if there is enough data left

Signed-off-by: Paul B Mahol <onemda@gmail.com>
pull/59/head
Paul B Mahol 13 years ago
parent 1ec83d9a9e
commit 292850b634
  1. 42
      libavcodec/tiff.c

@ -65,26 +65,26 @@ typedef struct TiffContext {
static unsigned tget_short(GetByteContext *gb, int le) static unsigned tget_short(GetByteContext *gb, int le)
{ {
unsigned v = le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb); unsigned v = le ? bytestream2_get_le16u(gb) : bytestream2_get_be16u(gb);
return v; return v;
} }
static unsigned tget_long(GetByteContext *gb, int le) static unsigned tget_long(GetByteContext *gb, int le)
{ {
unsigned v = le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb); unsigned v = le ? bytestream2_get_le32u(gb) : bytestream2_get_be32u(gb);
return v; return v;
} }
static double tget_double(GetByteContext *gb, int le) static double tget_double(GetByteContext *gb, int le)
{ {
av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)}; av_alias64 i = { .u64 = le ? bytestream2_get_le64u(gb) : bytestream2_get_be64u(gb)};
return i.f64; return i.f64;
} }
static unsigned tget(GetByteContext *gb, int type, int le) static unsigned tget(GetByteContext *gb, int type, int le)
{ {
switch (type) { switch (type) {
case TIFF_BYTE : return bytestream2_get_byte(gb); case TIFF_BYTE : return bytestream2_get_byteu(gb);
case TIFF_SHORT: return tget_short(gb, le); case TIFF_SHORT: return tget_short(gb, le);
case TIFF_LONG : return tget_long(gb, le); case TIFF_LONG : return tget_long(gb, le);
default : return UINT_MAX; default : return UINT_MAX;
@ -246,8 +246,10 @@ static int add_doubles_metadata(int count,
int i; int i;
double *dp; double *dp;
if (count >= INT_MAX / sizeof(int64_t))
return AVERROR_INVALIDDATA;
if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t)) if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t))
return -1; return AVERROR_INVALIDDATA;
dp = av_malloc(count * sizeof(double)); dp = av_malloc(count * sizeof(double));
if (!dp) if (!dp)
@ -270,8 +272,10 @@ static int add_shorts_metadata(int count, const char *name,
int i; int i;
int16_t *sp; int16_t *sp;
if (count >= INT_MAX / sizeof(int16_t))
return AVERROR_INVALIDDATA;
if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t)) if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int16_t))
return -1; return AVERROR_INVALIDDATA;
sp = av_malloc(count * sizeof(int16_t)); sp = av_malloc(count * sizeof(int16_t));
if (!sp) if (!sp)
@ -590,8 +594,6 @@ static int tiff_decode_tag(TiffContext *s)
uint32_t *pal; uint32_t *pal;
double *dp; double *dp;
if (bytestream2_get_bytes_left(&s->gb) < 12)
return -1;
tag = tget_short(&s->gb, s->le); tag = tget_short(&s->gb, s->le);
type = tget_short(&s->gb, s->le); type = tget_short(&s->gb, s->le);
count = tget_long(&s->gb, s->le); count = tget_long(&s->gb, s->le);
@ -657,7 +659,9 @@ static int tiff_decode_tag(TiffContext *s)
case TIFF_SHORT: case TIFF_SHORT:
case TIFF_LONG: case TIFF_LONG:
s->bpp = 0; s->bpp = 0;
for (i = 0; i < count && bytestream2_get_bytes_left(&s->gb) > 0; i++) if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count)
return -1;
for (i = 0; i < count; i++)
s->bpp += tget(&s->gb, type, s->le); s->bpp += tget(&s->gb, type, s->le);
break; break;
default: default:
@ -836,6 +840,8 @@ static int tiff_decode_tag(TiffContext *s)
s->geotag_count = count / 4 - 1; s->geotag_count = count / 4 - 1;
av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n"); av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n");
} }
if (bytestream2_get_bytes_left(&s->gb) < s->geotag_count * sizeof(int16_t) * 4)
return -1;
s->geotags = av_mallocz(sizeof(TiffGeoTag) * s->geotag_count); s->geotags = av_mallocz(sizeof(TiffGeoTag) * s->geotag_count);
if (!s->geotags) { if (!s->geotags) {
av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
@ -853,6 +859,10 @@ static int tiff_decode_tag(TiffContext *s)
} }
break; break;
case TIFF_GEO_DOUBLE_PARAMS: case TIFF_GEO_DOUBLE_PARAMS:
if (count >= INT_MAX / sizeof(int64_t))
return AVERROR_INVALIDDATA;
if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t))
return AVERROR_INVALIDDATA;
dp = av_malloc(count * sizeof(double)); dp = av_malloc(count * sizeof(double));
if (!dp) { if (!dp) {
av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
@ -886,13 +896,17 @@ static int tiff_decode_tag(TiffContext *s)
|| s->geotags[i].offset + s->geotags[i].count > count) { || s->geotags[i].offset + s->geotags[i].count > count) {
av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key); av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key);
} else { } else {
char *ap = av_malloc(s->geotags[i].count); char *ap;
bytestream2_seek(&s->gb, pos + s->geotags[i].offset, SEEK_SET);
if (bytestream2_get_bytes_left(&s->gb) < s->geotags[i].count)
return -1;
ap = av_malloc(s->geotags[i].count);
if (!ap) { if (!ap) {
av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n"); av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
bytestream2_seek(&s->gb, pos + s->geotags[i].offset, SEEK_SET); bytestream2_get_bufferu(&s->gb, ap, s->geotags[i].count);
bytestream2_get_buffer(&s->gb, ap, s->geotags[i].count);
ap[s->geotags[i].count - 1] = '\0'; //replace the "|" delimiter with a 0 byte ap[s->geotags[i].count - 1] = '\0'; //replace the "|" delimiter with a 0 byte
s->geotags[i].val = ap; s->geotags[i].val = ap;
} }
@ -927,7 +941,7 @@ static int decode_frame(AVCodecContext *avctx,
//parse image header //parse image header
if (avpkt->size < 8) if (avpkt->size < 8)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
id = bytestream2_get_le16(&s->gb); id = bytestream2_get_le16u(&s->gb);
if (id == 0x4949) if (id == 0x4949)
le = 1; le = 1;
else if (id == 0x4D4D) else if (id == 0x4D4D)
@ -961,6 +975,8 @@ static int decode_frame(AVCodecContext *avctx,
} }
bytestream2_seek(&s->gb, off, SEEK_SET); bytestream2_seek(&s->gb, off, SEEK_SET);
entries = tget_short(&s->gb, le); entries = tget_short(&s->gb, le);
if (bytestream2_get_bytes_left(&s->gb) < entries * 12)
return AVERROR_INVALIDDATA;
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
if (tiff_decode_tag(s) < 0) if (tiff_decode_tag(s) < 0)
return -1; return -1;

Loading…
Cancel
Save