1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-10-06 05:47:18 +02:00

avcodec/cbs_apv: store derived tile information in a per frame basis

If a single fragment contains more than one frame unit, the tile information stored
in the private context will only correspond to one of them.

Fixes: crash (out of array access)
Fixes: 435489659/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_APV_fuzzer-6194885205229568

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2025-08-10 13:44:31 -03:00
parent 0469d68acb
commit 4b39d776c3
4 changed files with 55 additions and 39 deletions

View File

@@ -35,6 +35,16 @@
#include "thread.h" #include "thread.h"
typedef struct APVDerivedTileInfo {
uint8_t tile_cols;
uint8_t tile_rows;
uint16_t num_tiles;
// The spec uses an extra element on the end of these arrays
// not corresponding to any tile.
uint16_t col_starts[APV_MAX_TILE_COLS + 1];
uint16_t row_starts[APV_MAX_TILE_ROWS + 1];
} APVDerivedTileInfo;
typedef struct APVDecodeContext { typedef struct APVDecodeContext {
CodedBitstreamContext *cbc; CodedBitstreamContext *cbc;
APVDSPContext dsp; APVDSPContext dsp;
@@ -184,7 +194,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data,
APVRawFrame *input = data; APVRawFrame *input = data;
APVDecodeContext *apv = avctx->priv_data; APVDecodeContext *apv = avctx->priv_data;
const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data;
const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; const APVDerivedTileInfo *tile_info = &apv->tile_info;
int tile_index = job / apv_cbc->num_comp; int tile_index = job / apv_cbc->num_comp;
int comp_index = job % apv_cbc->num_comp; int comp_index = job % apv_cbc->num_comp;
@@ -297,12 +307,38 @@ fail:
return err; return err;
} }
static void apv_derive_tile_info(APVDerivedTileInfo *ti,
const APVRawFrameHeader *fh)
{
int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4;
int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4;
int start_mb, i;
start_mb = 0;
for (i = 0; start_mb < frame_width_in_mbs; i++) {
ti->col_starts[i] = start_mb * APV_MB_WIDTH;
start_mb += fh->tile_info.tile_width_in_mbs;
}
ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
ti->tile_cols = i;
start_mb = 0;
for (i = 0; start_mb < frame_height_in_mbs; i++) {
ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
start_mb += fh->tile_info.tile_height_in_mbs;
}
ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
ti->tile_rows = i;
ti->num_tiles = ti->tile_cols * ti->tile_rows;
}
static int apv_decode(AVCodecContext *avctx, AVFrame *output, static int apv_decode(AVCodecContext *avctx, AVFrame *output,
APVRawFrame *input) APVRawFrame *input)
{ {
APVDecodeContext *apv = avctx->priv_data; APVDecodeContext *apv = avctx->priv_data;
const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; const AVPixFmtDescriptor *desc = NULL;
const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; APVDerivedTileInfo *tile_info = &apv->tile_info;
int err, job_count; int err, job_count;
err = apv_decode_check_format(avctx, &input->frame_header); err = apv_decode_check_format(avctx, &input->frame_header);
@@ -311,6 +347,9 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output,
return err; return err;
} }
desc = av_pix_fmt_desc_get(avctx->pix_fmt);
av_assert0(desc);
err = ff_thread_get_buffer(avctx, output, 0); err = ff_thread_get_buffer(avctx, output, 0);
if (err < 0) if (err < 0)
return err; return err;
@@ -318,9 +357,11 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output,
apv->output_frame = output; apv->output_frame = output;
atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed);
apv_derive_tile_info(tile_info, &input->frame_header);
// Each component within a tile is independent of every other, // Each component within a tile is independent of every other,
// so we can decode all in parallel. // so we can decode all in parallel.
job_count = tile_info->num_tiles * apv_cbc->num_comp; job_count = tile_info->num_tiles * desc->nb_components;
avctx->execute2(avctx, apv_decode_tile_component, avctx->execute2(avctx, apv_decode_tile_component,
input, NULL, job_count); input, NULL, job_count);

View File

@@ -37,33 +37,18 @@ static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh)
} }
} }
static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti, static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx,
const APVRawFrameHeader *fh) const APVRawFrameHeader *fh)
{ {
CodedBitstreamAPVContext *priv = ctx->priv_data;
int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16;
int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16;
int start_mb, i; int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs;
int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs;
start_mb = 0; av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS);
for (i = 0; start_mb < frame_width_in_mbs; i++) {
ti->col_starts[i] = start_mb * APV_MB_WIDTH;
start_mb += fh->tile_info.tile_width_in_mbs;
}
av_assert0(i <= APV_MAX_TILE_COLS);
ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
ti->tile_cols = i;
start_mb = 0; priv->num_tiles = tile_cols * tile_rows;
for (i = 0; start_mb < frame_height_in_mbs; i++) {
av_assert0(i < APV_MAX_TILE_ROWS);
ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
start_mb += fh->tile_info.tile_height_in_mbs;
}
av_assert0(i <= APV_MAX_TILE_ROWS);
ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
ti->tile_rows = i;
ti->num_tiles = ti->tile_cols * ti->tile_rows;
} }

View File

@@ -187,21 +187,11 @@ typedef struct APVRawMetadata {
} APVRawMetadata; } APVRawMetadata;
typedef struct APVDerivedTileInfo {
uint8_t tile_cols;
uint8_t tile_rows;
uint16_t num_tiles;
// The spec uses an extra element on the end of these arrays
// not corresponding to any tile.
uint16_t col_starts[APV_MAX_TILE_COLS + 1];
uint16_t row_starts[APV_MAX_TILE_ROWS + 1];
} APVDerivedTileInfo;
typedef struct CodedBitstreamAPVContext { typedef struct CodedBitstreamAPVContext {
int bit_depth; int bit_depth;
int num_comp; int num_comp;
APVDerivedTileInfo tile_info; uint16_t num_tiles;
} CodedBitstreamAPVContext; } CodedBitstreamAPVContext;
#endif /* AVCODEC_CBS_APV_H */ #endif /* AVCODEC_CBS_APV_H */

View File

@@ -128,10 +128,10 @@ static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw,
ub(1, tile_size_present_in_fh_flag); ub(1, tile_size_present_in_fh_flag);
cbs_apv_derive_tile_info(&priv->tile_info, fh); cbs_apv_derive_tile_info(ctx, fh);
if (current->tile_size_present_in_fh_flag) { if (current->tile_size_present_in_fh_flag) {
for (int t = 0; t < priv->tile_info.num_tiles; t++) { for (int t = 0; t < priv->num_tiles; t++) {
us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t);
} }
} }
@@ -262,7 +262,7 @@ static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw,
CHECK(FUNC(frame_header)(ctx, rw, &current->frame_header)); CHECK(FUNC(frame_header)(ctx, rw, &current->frame_header));
for (int t = 0; t < priv->tile_info.num_tiles; t++) { for (int t = 0; t < priv->num_tiles; t++) {
us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t);
CHECK(FUNC(tile)(ctx, rw, &current->tile[t], CHECK(FUNC(tile)(ctx, rw, &current->tile[t],