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
Showing the changes to libavcodec (4 of 4 files). Show all
Unified · Split
| @@ -35,6 +35,16 @@ · 34 unmodified lines | ||
| 35 | 35 | #include "thread.h" |
| 36 | 36 | |
| 37 | 37 | |
| 38 | +typedef struct APVDerivedTileInfo { | |
| 39 | + uint8_t tile_cols; | |
| 40 | + uint8_t tile_rows; | |
| 41 | + uint16_t num_tiles; | |
| 42 | + // The spec uses an extra element on the end of these arrays | |
| 43 | + // not corresponding to any tile. | |
| 44 | + uint16_t col_starts[APV_MAX_TILE_COLS + 1]; | |
| 45 | + uint16_t row_starts[APV_MAX_TILE_ROWS + 1]; | |
| 46 | +} APVDerivedTileInfo; | |
| 47 | + | |
| 38 | 48 | typedef struct APVDecodeContext { |
| 39 | 49 | CodedBitstreamContext *cbc; |
| 40 | 50 | APVDSPContext dsp; |
| @@ -184,7 +194,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data, · 143 unmodified lines | ||
| 184 | 194 | APVRawFrame *input = data; |
| 185 | 195 | APVDecodeContext *apv = avctx->priv_data; |
| 186 | 196 | const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; |
| 187 | − const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; | |
| 197 | + const APVDerivedTileInfo *tile_info = &apv->tile_info; | |
| 188 | 198 | |
| 189 | 199 | int tile_index = job / apv_cbc->num_comp; |
| 190 | 200 | int comp_index = job % apv_cbc->num_comp; |
| @@ -297,12 +307,38 @@ fail: · 106 unmodified lines | ||
| 297 | 307 | return err; |
| 298 | 308 | } |
| 299 | 309 | |
| 310 | +static void apv_derive_tile_info(APVDerivedTileInfo *ti, | |
| 311 | + const APVRawFrameHeader *fh) | |
| 312 | +{ | |
| 313 | + int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4; | |
| 314 | + int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4; | |
| 315 | + int start_mb, i; | |
| 316 | + | |
| 317 | + start_mb = 0; | |
| 318 | + for (i = 0; start_mb < frame_width_in_mbs; i++) { | |
| 319 | + ti->col_starts[i] = start_mb * APV_MB_WIDTH; | |
| 320 | + start_mb += fh->tile_info.tile_width_in_mbs; | |
| 321 | + } | |
| 322 | + ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH; | |
| 323 | + ti->tile_cols = i; | |
| 324 | + | |
| 325 | + start_mb = 0; | |
| 326 | + for (i = 0; start_mb < frame_height_in_mbs; i++) { | |
| 327 | + ti->row_starts[i] = start_mb * APV_MB_HEIGHT; | |
| 328 | + start_mb += fh->tile_info.tile_height_in_mbs; | |
| 329 | + } | |
| 330 | + ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; | |
| 331 | + ti->tile_rows = i; | |
| 332 | + | |
| 333 | + ti->num_tiles = ti->tile_cols * ti->tile_rows; | |
| 334 | +} | |
| 335 | + | |
| 300 | 336 | static int apv_decode(AVCodecContext *avctx, AVFrame *output, |
| 301 | 337 | APVRawFrame *input) |
| 302 | 338 | { |
| 303 | 339 | APVDecodeContext *apv = avctx->priv_data; |
| 304 | − const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; | |
| 305 | − const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; | |
| 340 | + const AVPixFmtDescriptor *desc = NULL; | |
| 341 | + APVDerivedTileInfo *tile_info = &apv->tile_info; | |
| 306 | 342 | int err, job_count; |
| 307 | 343 | |
| 308 | 344 | err = apv_decode_check_format(avctx, &input->frame_header); |
| @@ -311,6 +347,9 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, · 2 unmodified lines | ||
| 311 | 347 | return err; |
| 312 | 348 | } |
| 313 | 349 | |
| 350 | + desc = av_pix_fmt_desc_get(avctx->pix_fmt); | |
| 351 | + av_assert0(desc); | |
| 352 | + | |
| 314 | 353 | err = ff_thread_get_buffer(avctx, output, 0); |
| 315 | 354 | if (err < 0) |
| 316 | 355 | return err; |
| @@ -318,9 +357,11 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, · 1 unmodified line | ||
| 318 | 357 | apv->output_frame = output; |
| 319 | 358 | atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); |
| 320 | 359 | |
| 360 | + apv_derive_tile_info(tile_info, &input->frame_header); | |
| 361 | + | |
| 321 | 362 | // Each component within a tile is independent of every other, |
| 322 | 363 | // so we can decode all in parallel. |
| 323 | − job_count = tile_info->num_tiles * apv_cbc->num_comp; | |
| 364 | + job_count = tile_info->num_tiles * desc->nb_components; | |
| 324 | 365 | |
| 325 | 366 | avctx->execute2(avctx, apv_decode_tile_component, |
| 326 | 367 | input, NULL, job_count); |
| @@ -37,33 +37,18 @@ static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh) · 36 unmodified lines | ||
| 37 | 37 | } |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | −static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti, | |
| 40 | +static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx, | |
| 41 | 41 | const APVRawFrameHeader *fh) |
| 42 | 42 | { |
| 43 | + CodedBitstreamAPVContext *priv = ctx->priv_data; | |
| 43 | 44 | int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; |
| 44 | 45 | int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; |
| 45 | − int start_mb, i; | |
| 46 | + int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs; | |
| 47 | + int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs; | |
| 46 | 48 | |
| 47 | − start_mb = 0; | |
| 48 | − for (i = 0; start_mb < frame_width_in_mbs; i++) { | |
| 49 | − ti->col_starts[i] = start_mb * APV_MB_WIDTH; | |
| 50 | − start_mb += fh->tile_info.tile_width_in_mbs; | |
| 51 | − } | |
| 52 | − av_assert0(i <= APV_MAX_TILE_COLS); | |
| 53 | − ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH; | |
| 54 | − ti->tile_cols = i; | |
| 55 | − | |
| 56 | − start_mb = 0; | |
| 57 | − for (i = 0; start_mb < frame_height_in_mbs; i++) { | |
| 58 | − av_assert0(i < APV_MAX_TILE_ROWS); | |
| 59 | − ti->row_starts[i] = start_mb * APV_MB_HEIGHT; | |
| 60 | − start_mb += fh->tile_info.tile_height_in_mbs; | |
| 61 | − } | |
| 62 | − av_assert0(i <= APV_MAX_TILE_ROWS); | |
| 63 | − ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; | |
| 64 | − ti->tile_rows = i; | |
| 49 | + av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS); | |
| 65 | 50 | |
| 66 | − ti->num_tiles = ti->tile_cols * ti->tile_rows; | |
| 51 | + priv->num_tiles = tile_cols * tile_rows; | |
| 67 | 52 | } |
| 68 | 53 | |
| 69 | 54 | |
| @@ -187,21 +187,11 @@ typedef struct APVRawMetadata { · 186 unmodified lines | ||
| 187 | 187 | } APVRawMetadata; |
| 188 | 188 | |
| 189 | 189 | |
| 190 | −typedef struct APVDerivedTileInfo { | |
| 191 | − uint8_t tile_cols; | |
| 192 | − uint8_t tile_rows; | |
| 193 | − uint16_t num_tiles; | |
| 194 | − // The spec uses an extra element on the end of these arrays | |
| 195 | − // not corresponding to any tile. | |
| 196 | − uint16_t col_starts[APV_MAX_TILE_COLS + 1]; | |
| 197 | − uint16_t row_starts[APV_MAX_TILE_ROWS + 1]; | |
| 198 | −} APVDerivedTileInfo; | |
| 199 | − | |
| 200 | 190 | typedef struct CodedBitstreamAPVContext { |
| 201 | 191 | int bit_depth; |
| 202 | 192 | int num_comp; |
| 203 | 193 | |
| 204 | − APVDerivedTileInfo tile_info; | |
| 194 | + uint16_t num_tiles; | |
| 205 | 195 | } CodedBitstreamAPVContext; |
| 206 | 196 | |
| 207 | 197 | #endif /* AVCODEC_CBS_APV_H */ |
| @@ -128,10 +128,10 @@ static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, · 127 unmodified lines | ||
| 128 | 128 | |
| 129 | 129 | ub(1, tile_size_present_in_fh_flag); |
| 130 | 130 | |
| 131 | − cbs_apv_derive_tile_info(&priv->tile_info, fh); | |
| 131 | + cbs_apv_derive_tile_info(ctx, fh); | |
| 132 | 132 | |
| 133 | 133 | if (current->tile_size_present_in_fh_flag) { |
| 134 | − for (int t = 0; t < priv->tile_info.num_tiles; t++) { | |
| 134 | + for (int t = 0; t < priv->num_tiles; t++) { | |
| 135 | 135 | us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); |
| 136 | 136 | } |
| 137 | 137 | } |
| @@ -262,7 +262,7 @@ static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, · 124 unmodified lines | ||
| 262 | 262 | |
| 263 | 263 | CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); |
| 264 | 264 | |
| 265 | − for (int t = 0; t < priv->tile_info.num_tiles; t++) { | |
| 265 | + for (int t = 0; t < priv->num_tiles; t++) { | |
| 266 | 266 | us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); |
| 267 | 267 | |
| 268 | 268 | CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], |