[FFmpeg-devel] [PATCH] avcodec/av1dec: Check tiles sizes, fix assert, don't read bytes bitwise

James Almer jamrial at gmail.com
Thu Sep 17 06:37:23 EEST 2020


On 9/17/2020 12:19 AM, Andreas Rheinhardt wrote:
> Tiles have a size field with a length from one to four bytes. As such it
> is not possible to read it all at once with a call to get_bits() as this
> only allows to read up to 25 bits; this is guarded by an av_assert2. Yet
> this is done by the AV1 decoder in get_tiles_info(). It has been done
> despite said size fields being byte-aligned. This commit fixes this by
> using the bytestream2 API instead.
> 
> Furthermore, it is now explicitly checked whether the data is
> consistent, i.e. whether the data that is supposed to be there extends
> beyond the end of the data actually present.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
> ---
>  libavcodec/av1dec.c | 40 ++++++++++++++++++++--------------------
>  1 file changed, 20 insertions(+), 20 deletions(-)
> 
> diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
> index cb46801202..0bb04a3e44 100644
> --- a/libavcodec/av1dec.c
> +++ b/libavcodec/av1dec.c
> @@ -21,7 +21,7 @@
>  #include "libavutil/pixdesc.h"
>  #include "avcodec.h"
>  #include "av1dec.h"
> -#include "get_bits.h"
> +#include "bytestream.h"
>  #include "hwconfig.h"
>  #include "internal.h"
>  #include "profiles.h"
> @@ -205,18 +205,12 @@ static int init_tile_data(AV1DecContext *s)
>  static int get_tiles_info(AVCodecContext *avctx, const AV1RawTileGroup *tile_group)
>  {
>      AV1DecContext *s = avctx->priv_data;
> -    GetBitContext gb;
> +    GetByteContext gb;
>      uint16_t tile_num, tile_row, tile_col;
> -    uint32_t size = 0, size_bytes = 0, offset = 0;
> -    int ret;
> -
> -    if ((ret = init_get_bits8(&gb,
> -                              tile_group->tile_data.data,
> -                              tile_group->tile_data.data_size)) < 0) {
> -        av_log(avctx, AV_LOG_ERROR, "Failed to initialize bitstream reader.\n");
> -        return ret;
> -    }
> +    uint32_t size = 0, size_bytes = 0;
>  
> +    bytestream2_init(&gb, tile_group->tile_data.data,
> +                     tile_group->tile_data.data_size);
>      s->tg_start = tile_group->tg_start;
>      s->tg_end = tile_group->tg_end;
>  
> @@ -225,24 +219,28 @@ static int get_tiles_info(AVCodecContext *avctx, const AV1RawTileGroup *tile_gro
>          tile_col = tile_num % s->raw_frame_header->tile_cols;
>  
>          if (tile_num == tile_group->tg_end) {
> -            s->tile_group_info[tile_num].tile_size = get_bits_left(&gb) / 8;
> -            s->tile_group_info[tile_num].tile_offset = offset;
> +            s->tile_group_info[tile_num].tile_size = bytestream2_get_bytes_left(&gb);
> +            s->tile_group_info[tile_num].tile_offset = bytestream2_tell(&gb);
>              s->tile_group_info[tile_num].tile_row = tile_row;
>              s->tile_group_info[tile_num].tile_column = tile_col;
>              return 0;
>          }
>          size_bytes = s->raw_frame_header->tile_size_bytes_minus1 + 1;
> -        size = get_bits_le(&gb, size_bytes * 8) + 1;
> -        skip_bits(&gb, size * 8);
> -
> -        offset += size_bytes;
> +        if (bytestream2_get_bytes_left(&gb) < size_bytes)
> +            return AVERROR_INVALIDDATA;
> +        size = 0;
> +        for (int i = 0; i < size_bytes; i++)
> +            size |= bytestream2_get_byteu(&gb) << 8 * i;
> +        if (bytestream2_get_bytes_left(&gb) <= size)
> +            return AVERROR_INVALIDDATA;
> +        size++;
>  
>          s->tile_group_info[tile_num].tile_size = size;
> -        s->tile_group_info[tile_num].tile_offset = offset;
> +        s->tile_group_info[tile_num].tile_offset = bytestream2_tell(&gb);
>          s->tile_group_info[tile_num].tile_row = tile_row;
>          s->tile_group_info[tile_num].tile_column = tile_col;
>  
> -        offset += size;
> +        bytestream2_skipu(&gb, size);
>      }
>  
>      return 0;
> @@ -778,7 +776,9 @@ static int av1_decode_frame(AVCodecContext *avctx, void *frame,
>              else
>                  raw_tile_group = &obu->obu.tile_group;
>  
> -            get_tiles_info(avctx, raw_tile_group);
> +            ret = get_tiles_info(avctx, raw_tile_group);
> +            if (ret < 0)
> +                goto end;
>  
>              if (avctx->hwaccel) {
>                  ret = avctx->hwaccel->decode_slice(avctx,

Should be ok.


More information about the ffmpeg-devel mailing list