mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-26 17:32:06 +00:00
avcodec/exr: Fix memleaks in decode_header()
Fixes: 4793/clusterfuzz-testcase-minimized-5707366629638144 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
parent
b1af0e23a3
commit
0a2560a977
@ -1306,6 +1306,7 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
AVDictionary *metadata = NULL;
|
AVDictionary *metadata = NULL;
|
||||||
int magic_number, version, i, flags, sar = 0;
|
int magic_number, version, i, flags, sar = 0;
|
||||||
int layer_match = 0;
|
int layer_match = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
s->current_channel_offset = 0;
|
s->current_channel_offset = 0;
|
||||||
s->xmin = ~0;
|
s->xmin = ~0;
|
||||||
@ -1364,8 +1365,10 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
if ((var_size = check_header_variable(s, "channels",
|
if ((var_size = check_header_variable(s, "channels",
|
||||||
"chlist", 38)) >= 0) {
|
"chlist", 38)) >= 0) {
|
||||||
GetByteContext ch_gb;
|
GetByteContext ch_gb;
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
bytestream2_init(&ch_gb, s->gb.buffer, var_size);
|
bytestream2_init(&ch_gb, s->gb.buffer, var_size);
|
||||||
|
|
||||||
@ -1424,14 +1427,16 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
|
|
||||||
if (bytestream2_get_bytes_left(&ch_gb) < 4) {
|
if (bytestream2_get_bytes_left(&ch_gb) < 4) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Incomplete header.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Incomplete header.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_pixel_type = bytestream2_get_le32(&ch_gb);
|
current_pixel_type = bytestream2_get_le32(&ch_gb);
|
||||||
if (current_pixel_type >= EXR_UNKNOWN) {
|
if (current_pixel_type >= EXR_UNKNOWN) {
|
||||||
avpriv_report_missing_feature(s->avctx, "Pixel type %d",
|
avpriv_report_missing_feature(s->avctx, "Pixel type %d",
|
||||||
current_pixel_type);
|
current_pixel_type);
|
||||||
return AVERROR_PATCHWELCOME;
|
ret = AVERROR_PATCHWELCOME;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytestream2_skip(&ch_gb, 4);
|
bytestream2_skip(&ch_gb, 4);
|
||||||
@ -1442,7 +1447,8 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
avpriv_report_missing_feature(s->avctx,
|
avpriv_report_missing_feature(s->avctx,
|
||||||
"Subsampling %dx%d",
|
"Subsampling %dx%d",
|
||||||
xsub, ysub);
|
xsub, ysub);
|
||||||
return AVERROR_PATCHWELCOME;
|
ret = AVERROR_PATCHWELCOME;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel_index >= 0 && s->channel_offsets[channel_index] == -1) { /* channel has not been previously assigned */
|
if (channel_index >= 0 && s->channel_offsets[channel_index] == -1) { /* channel has not been previously assigned */
|
||||||
@ -1450,7 +1456,8 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
s->pixel_type != current_pixel_type) {
|
s->pixel_type != current_pixel_type) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR,
|
av_log(s->avctx, AV_LOG_ERROR,
|
||||||
"RGB channels not of the same depth.\n");
|
"RGB channels not of the same depth.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
s->pixel_type = current_pixel_type;
|
s->pixel_type = current_pixel_type;
|
||||||
s->channel_offsets[channel_index] = s->current_channel_offset;
|
s->channel_offsets[channel_index] = s->current_channel_offset;
|
||||||
@ -1458,8 +1465,10 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
|
|
||||||
s->channels = av_realloc(s->channels,
|
s->channels = av_realloc(s->channels,
|
||||||
++s->nb_channels * sizeof(EXRChannel));
|
++s->nb_channels * sizeof(EXRChannel));
|
||||||
if (!s->channels)
|
if (!s->channels) {
|
||||||
return AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
channel = &s->channels[s->nb_channels - 1];
|
channel = &s->channels[s->nb_channels - 1];
|
||||||
channel->pixel_type = current_pixel_type;
|
channel->pixel_type = current_pixel_type;
|
||||||
channel->xsub = xsub;
|
channel->xsub = xsub;
|
||||||
@ -1484,7 +1493,8 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
av_log(s->avctx, AV_LOG_ERROR, "Missing green channel.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Missing green channel.\n");
|
||||||
if (s->channel_offsets[2] < 0)
|
if (s->channel_offsets[2] < 0)
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Missing blue channel.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Missing blue channel.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1493,8 +1503,10 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
continue;
|
continue;
|
||||||
} else if ((var_size = check_header_variable(s, "dataWindow", "box2i",
|
} else if ((var_size = check_header_variable(s, "dataWindow", "box2i",
|
||||||
31)) >= 0) {
|
31)) >= 0) {
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
s->xmin = bytestream2_get_le32(&s->gb);
|
s->xmin = bytestream2_get_le32(&s->gb);
|
||||||
s->ymin = bytestream2_get_le32(&s->gb);
|
s->ymin = bytestream2_get_le32(&s->gb);
|
||||||
@ -1506,8 +1518,10 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
continue;
|
continue;
|
||||||
} else if ((var_size = check_header_variable(s, "displayWindow",
|
} else if ((var_size = check_header_variable(s, "displayWindow",
|
||||||
"box2i", 34)) >= 0) {
|
"box2i", 34)) >= 0) {
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
bytestream2_skip(&s->gb, 8);
|
bytestream2_skip(&s->gb, 8);
|
||||||
s->w = bytestream2_get_le32(&s->gb) + 1;
|
s->w = bytestream2_get_le32(&s->gb) + 1;
|
||||||
@ -1517,29 +1531,36 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
} else if ((var_size = check_header_variable(s, "lineOrder",
|
} else if ((var_size = check_header_variable(s, "lineOrder",
|
||||||
"lineOrder", 25)) >= 0) {
|
"lineOrder", 25)) >= 0) {
|
||||||
int line_order;
|
int line_order;
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
line_order = bytestream2_get_byte(&s->gb);
|
line_order = bytestream2_get_byte(&s->gb);
|
||||||
av_log(s->avctx, AV_LOG_DEBUG, "line order: %d.\n", line_order);
|
av_log(s->avctx, AV_LOG_DEBUG, "line order: %d.\n", line_order);
|
||||||
if (line_order > 2) {
|
if (line_order > 2) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Unknown line order.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Unknown line order.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else if ((var_size = check_header_variable(s, "pixelAspectRatio",
|
} else if ((var_size = check_header_variable(s, "pixelAspectRatio",
|
||||||
"float", 31)) >= 0) {
|
"float", 31)) >= 0) {
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
sar = bytestream2_get_le32(&s->gb);
|
sar = bytestream2_get_le32(&s->gb);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else if ((var_size = check_header_variable(s, "compression",
|
} else if ((var_size = check_header_variable(s, "compression",
|
||||||
"compression", 29)) >= 0) {
|
"compression", 29)) >= 0) {
|
||||||
if (!var_size)
|
if (!var_size) {
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->compression == EXR_UNKN)
|
if (s->compression == EXR_UNKN)
|
||||||
s->compression = bytestream2_get_byte(&s->gb);
|
s->compression = bytestream2_get_byte(&s->gb);
|
||||||
@ -1566,13 +1587,15 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
if (s->tile_attr.level_mode >= EXR_TILE_LEVEL_UNKNOWN){
|
if (s->tile_attr.level_mode >= EXR_TILE_LEVEL_UNKNOWN){
|
||||||
avpriv_report_missing_feature(s->avctx, "Tile level mode %d",
|
avpriv_report_missing_feature(s->avctx, "Tile level mode %d",
|
||||||
s->tile_attr.level_mode);
|
s->tile_attr.level_mode);
|
||||||
return AVERROR_PATCHWELCOME;
|
ret = AVERROR_PATCHWELCOME;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->tile_attr.level_round >= EXR_TILE_ROUND_UNKNOWN) {
|
if (s->tile_attr.level_round >= EXR_TILE_ROUND_UNKNOWN) {
|
||||||
avpriv_report_missing_feature(s->avctx, "Tile level round %d",
|
avpriv_report_missing_feature(s->avctx, "Tile level round %d",
|
||||||
s->tile_attr.level_round);
|
s->tile_attr.level_round);
|
||||||
return AVERROR_PATCHWELCOME;
|
ret = AVERROR_PATCHWELCOME;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -1589,7 +1612,8 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
// Check if there are enough bytes for a header
|
// Check if there are enough bytes for a header
|
||||||
if (bytestream2_get_bytes_left(&s->gb) <= 9) {
|
if (bytestream2_get_bytes_left(&s->gb) <= 9) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Incomplete header\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Incomplete header\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process unknown variables
|
// Process unknown variables
|
||||||
@ -1604,19 +1628,22 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
|
|
||||||
if (s->compression == EXR_UNKN) {
|
if (s->compression == EXR_UNKN) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->is_tile) {
|
if (s->is_tile) {
|
||||||
if (s->tile_attr.xSize < 1 || s->tile_attr.ySize < 1) {
|
if (s->tile_attr.xSize < 1 || s->tile_attr.ySize < 1) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Invalid tile attribute.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Invalid tile attribute.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytestream2_get_bytes_left(&s->gb) <= 0) {
|
if (bytestream2_get_bytes_left(&s->gb) <= 0) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n");
|
av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n");
|
||||||
return AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->metadata = metadata;
|
frame->metadata = metadata;
|
||||||
@ -1624,6 +1651,9 @@ static int decode_header(EXRContext *s, AVFrame *frame)
|
|||||||
// aaand we are done
|
// aaand we are done
|
||||||
bytestream2_skip(&s->gb, 1);
|
bytestream2_skip(&s->gb, 1);
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
av_dict_free(&metadata);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_frame(AVCodecContext *avctx, void *data,
|
static int decode_frame(AVCodecContext *avctx, void *data,
|
||||||
|
Loading…
Reference in New Issue
Block a user