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
Unified · Split
| @@ -35,6 +35,16 @@ · 34 unmodified lines | |||
| 35 | #include "thread.h" | 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 | typedef struct APVDecodeContext { | 48 | typedef struct APVDecodeContext { |
| 39 | CodedBitstreamContext *cbc; | 49 | CodedBitstreamContext *cbc; |
| 40 | APVDSPContext dsp; | 50 | APVDSPContext dsp; |
| @@ -184,7 +194,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data, · 143 unmodified lines | |||
| 184 | APVRawFrame *input = data; | 194 | APVRawFrame *input = data; |
| 185 | APVDecodeContext *apv = avctx->priv_data; | 195 | APVDecodeContext *apv = avctx->priv_data; |
| 186 | const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; | 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 | int tile_index = job / apv_cbc->num_comp; | 199 | int tile_index = job / apv_cbc->num_comp; |
| 190 | int comp_index = job % apv_cbc->num_comp; | 200 | int comp_index = job % apv_cbc->num_comp; |
| @@ -297,12 +307,38 @@ fail: · 106 unmodified lines | |||
| 297 | return err; | 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 | static int apv_decode(AVCodecContext *avctx, AVFrame *output, | 336 | static int apv_decode(AVCodecContext *avctx, AVFrame *output, |
| 301 | APVRawFrame *input) | 337 | APVRawFrame *input) |
| 302 | { | 338 | { |
| 303 | APVDecodeContext *apv = avctx->priv_data; | 339 | APVDecodeContext *apv = avctx->priv_data; |
| 304 | const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; | 340 | const AVPixFmtDescriptor *desc = NULL; |
| 305 | const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; | 341 | APVDerivedTileInfo *tile_info = &apv->tile_info; |
| 306 | int err, job_count; | 342 | int err, job_count; |
| 307 | 343 | ||
| 308 | err = apv_decode_check_format(avctx, &input->frame_header); | 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 | return err; | 347 | return err; |
| 312 | } | 348 | } |
| 313 | 349 | ||
| 350 | desc = av_pix_fmt_desc_get(avctx->pix_fmt); | ||
| 351 | av_assert0(desc); | ||
| 352 | |||
| 314 | err = ff_thread_get_buffer(avctx, output, 0); | 353 | err = ff_thread_get_buffer(avctx, output, 0); |
| 315 | if (err < 0) | 354 | if (err < 0) |
| 316 | return err; | 355 | return err; |
| @@ -318,9 +357,11 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, · 1 unmodified line | |||
| 318 | apv->output_frame = output; | 357 | apv->output_frame = output; |
| 319 | atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); | 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 | // Each component within a tile is independent of every other, | 362 | // Each component within a tile is independent of every other, |
| 322 | // so we can decode all in parallel. | 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 | avctx->execute2(avctx, apv_decode_tile_component, | 366 | avctx->execute2(avctx, apv_decode_tile_component, |
| 326 | input, NULL, job_count); | 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 | const APVRawFrameHeader *fh) | 41 | const APVRawFrameHeader *fh) |
| 42 | { | 42 | { |
| 43 | CodedBitstreamAPVContext *priv = ctx->priv_data; | ||
| 43 | int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; | 44 | int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; |
| 44 | int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; | 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; | 49 | av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS); |
| 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; | ||
| 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 | } APVRawMetadata; | 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 | typedef struct CodedBitstreamAPVContext { | 190 | typedef struct CodedBitstreamAPVContext { |
| 201 | int bit_depth; | 191 | int bit_depth; |
| 202 | int num_comp; | 192 | int num_comp; |
| 203 | 193 | ||
| 204 | APVDerivedTileInfo tile_info; | 194 | uint16_t num_tiles; |
| 205 | } CodedBitstreamAPVContext; | 195 | } CodedBitstreamAPVContext; |
| 206 | 196 | ||
| 207 | #endif /* AVCODEC_CBS_APV_H */ | 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 | ub(1, tile_size_present_in_fh_flag); | 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 | if (current->tile_size_present_in_fh_flag) { | 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 | us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); | 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 | CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); | 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 | us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); | 266 | us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); |
| 267 | 267 | ||
| 268 | CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], | 268 | CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], |