#10199: OOB memory access with AVIOContext, seeking, AVIO_FLAG_DIRECT, and ogg
files
---------------------------------------+----------------------------------
             Reporter:  Andrew Kelley  |                     Type:  defect
               Status:  new            |                 Priority:  normal
            Component:  undetermined   |                  Version:  5.1.2
             Keywords:                 |               Blocked By:
             Blocking:                 |  Reproduced by developer:  0
Analyzed by developer:  0              |
---------------------------------------+----------------------------------
 To reproduce, apply the following diff:

 {{{
 --- a/doc/examples/avio_reading.c
 +++ b/doc/examples/avio_reading.c
 @@ -37,6 +37,7 @@
  struct buffer_data {
      uint8_t *ptr;
      size_t size; ///< size left in the buffer
 +    size_t original_size;
  };

  static int read_packet(void *opaque, uint8_t *buf, int buf_size)
 @@ -56,6 +57,39 @@ static int read_packet(void *opaque, uint8_t *buf, int
 buf_size)
      return buf_size;
  }

 +static int64_t seek_packet(void *opaque, int64_t offset, int whence)
 +{
 +    struct buffer_data *bd = (struct buffer_data *)opaque;
 +
 +    if (whence & AVSEEK_FORCE) {
 +        // doesn't matter
 +        whence -= AVSEEK_FORCE;
 +    }
 +
 +    if (whence & AVSEEK_SIZE) {
 +        return bd->original_size;
 +    }
 +
 +    switch (whence) {
 +        case SEEK_SET:
 +        {
 +            uint8_t *base_ptr = (bd->ptr + bd->size) - bd->original_size;
 +            bd->ptr = base_ptr + offset;
 +            bd->size = bd->original_size - offset;
 +            return 0;
 +        }
 +        case SEEK_CUR:
 +            bd->ptr += offset;
 +            bd->size -= offset;
 +            return 0;
 +        case SEEK_END:
 +            bd->ptr += bd->size;
 +            bd->size = 0;
 +            return 0;
 +    }
 +    return -1;
 +}
 +
  int main(int argc, char *argv[])
  {
      AVFormatContext *fmt_ctx = NULL;
 @@ -82,6 +116,7 @@ int main(int argc, char *argv[])
      /* fill opaque structure used by the AVIOContext read callback */
      bd.ptr  = buffer;
      bd.size = buffer_size;
 +    bd.original_size = buffer_size;

      if (!(fmt_ctx = avformat_alloc_context())) {
          ret = AVERROR(ENOMEM);
 @@ -94,11 +129,12 @@ int main(int argc, char *argv[])
          goto end;
      }
      avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
 -                                  0, &bd, &read_packet, NULL, NULL);
 +                                  0, &bd, &read_packet, NULL,
 &seek_packet);
      if (!avio_ctx) {
          ret = AVERROR(ENOMEM);
          goto end;
      }
 +    avio_ctx->direct = AVIO_FLAG_DIRECT;
      fmt_ctx->pb = avio_ctx;

      ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
 }}}

 Next, build the example and then run it with any ogg file:

 {{{
 [nix-shell:~/Downloads/ffmpeg]$ make examples
 CC      doc/examples/avio_reading.o
 LD      doc/examples/avio_reading_g
 STRIP   doc/examples/avio_reading
 [nix-shell:~/Downloads/ffmpeg]$ ./doc/examples/avio_reading_g
 ~/tmp/danse1.ogg
 ptr:0x7fb9605df000 size:88407
 ptr:0x7fb9605df000 size:88407
 ptr:0x7fb9605df004 size:88403
 ptr:0x7fb9605df016 size:88385
 [ogg @ 0x264a040] CRC mismatch!
 ptr:0x7fb9605df000 size:88407
 ptr:0x7fb9605df004 size:88403
 ptr:0x7fb9605df008 size:88399
 Segmentation fault (core dumped)

 [nix-shell:~/Downloads/ffmpeg]$ gdb ./doc/examples/avio_reading_g
 ~/tmp/danse1.ogg  -ex 'run'
 GNU gdb (GDB) 12.1
 Copyright (C) 2022 Free Software Foundation, Inc.
 License GPLv3+: GNU GPL version 3 or later
 <http://gnu.org/licenses/gpl.html>
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
 Type "show copying" and "show warranty" for details.
 This GDB was configured as "x86_64-unknown-linux-gnu".
 Type "show configuration" for configuration details.
 For bug reporting instructions, please see:
 <https://www.gnu.org/software/gdb/bugs/>.
 Find the GDB manual and other documentation resources online at:
     <http://www.gnu.org/software/gdb/documentation/>.

 For help, type "help".
 Type "apropos word" to search for commands related to "word"...
 Reading symbols from ./doc/examples/avio_reading_g...
 "/home/andy/tmp/danse1.ogg" is not a core dump: file format not recognized
 Starting program: /home/andy/Downloads/ffmpeg/doc/examples/avio_reading_g
 [Thread debugging using libthread_db enabled]
 Using host libthread_db library "/nix/store
 /4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libthread_db.so.1".
 usage: /home/andy/Downloads/ffmpeg/doc/examples/avio_reading_g input_file
 API example program to show how to read from a custom buffer accessed
 through AVIOContext.
 [Inferior 1 (process 1486710) exited with code 01]
 (gdb)
 quit

 [nix-shell:~/Downloads/ffmpeg]$ gdb ./doc/examples/avio_reading_g -ex 'run
 ~/tmp/danse1.ogg '
 GNU gdb (GDB) 12.1
 Copyright (C) 2022 Free Software Foundation, Inc.
 License GPLv3+: GNU GPL version 3 or later
 <http://gnu.org/licenses/gpl.html>
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
 Type "show copying" and "show warranty" for details.
 This GDB was configured as "x86_64-unknown-linux-gnu".
 Type "show configuration" for configuration details.
 For bug reporting instructions, please see:
 <https://www.gnu.org/software/gdb/bugs/>.
 Find the GDB manual and other documentation resources online at:
     <http://www.gnu.org/software/gdb/documentation/>.

 For help, type "help".
 Type "apropos word" to search for commands related to "word"...
 Reading symbols from ./doc/examples/avio_reading_g...
 Starting program: /home/andy/Downloads/ffmpeg/doc/examples/avio_reading_g
 ~/tmp/danse1.ogg
 [Thread debugging using libthread_db enabled]
 Using host libthread_db library "/nix/store
 /4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libthread_db.so.1".
 ptr:0x7ffff7c9f000 size:88407
 ptr:0x7ffff7c9f000 size:88407
 ptr:0x7ffff7c9f004 size:88403
 ptr:0x7ffff7c9f016 size:88385
 [ogg @ 0x1a5e040] CRC mismatch!
 ptr:0x7ffff7c9f000 size:88407
 ptr:0x7ffff7c9f004 size:88403
 ptr:0x7ffff7c9f008 size:88399

 Program received signal SIGSEGV, Segmentation fault.
 av_crc (ctx=0x1956f40 <av_crc_table+12288>, crc=853835309,
 crc@entry=1336520799, buffer=0x1a7f000 <error: Cannot access memory at
 address 0x1a7f000>, buffer@entry=0x1a605f6 "",
 length=length@entry=4294967242) at libavutil/crc.c:403
 403                 crc ^= av_le2ne32(*(const uint32_t *) buffer); buffer
 += 4;
 (gdb) bt
 #0  av_crc (ctx=0x1956f40 <av_crc_table+12288>, crc=853835309,
 crc@entry=1336520799, buffer=0x1a7f000 <error: Cannot access memory at
 address 0x1a7f000>, buffer@entry=0x1a605f6 "",
 length=length@entry=4294967242) at libavutil/crc.c:403
 #1  0x000000000046b965 in ff_crc04C11DB7_update (checksum=1336520799,
 buf=0x1a605f6 "", len=4294967242) at libavformat/aviobuf.c:597
 #2  0x000000000046b9e4 in ffio_get_checksum (s=s@entry=0x1a5f800) at
 libavformat/aviobuf.c:614
 #3  0x00000000005614d1 in ogg_read_page (s=s@entry=0x1a5e040,
 sid=sid@entry=0x7fffffffaabc, probing=probing@entry=0) at
 libavformat/oggdec.c:375
 #4  0x0000000000561d1f in ogg_packet (s=s@entry=0x1a5e040,
 sid=sid@entry=0x0, dstart=dstart@entry=0x0, dsize=dsize@entry=0x0,
 fpos=fpos@entry=0x0) at libavformat/oggdec.c:515
 #5  0x000000000056261a in ogg_read_header (s=0x1a5e040) at
 libavformat/oggdec.c:734
 #6  0x0000000000472f19 in avformat_open_input (ps=ps@entry=0x7fffffffac00,
 filename=filename@entry=0x0, fmt=fmt@entry=0x0, options=options@entry=0x0)
 at libavformat/demux.c:310
 #7  0x0000000000466c08 in main (argc=<optimized out>, argv=<optimized
 out>) at doc/examples/avio_reading.c:140
 (gdb) up
 #1  0x000000000046b965 in ff_crc04C11DB7_update (checksum=1336520799,
 buf=0x1a605f6 "", len=4294967242) at libavformat/aviobuf.c:597
 597         return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf,
 len);
 (gdb)
 #2  0x000000000046b9e4 in ffio_get_checksum (s=s@entry=0x1a5f800) at
 libavformat/aviobuf.c:614
 614         s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
 (gdb) p s[0]
 $1 = {
   av_class = 0x0,
   buffer = 0x1a605c0 "",
   buffer_size = 4096,
   buf_ptr = 0x1a605c0 "",
   buf_end = 0x1a605c0 "",
   opaque = 0x7fffffffac20,
   read_packet = 0x466e40 <read_packet>,
   write_packet = 0x0,
   seek = 0x466eb0 <seek_packet>,
   pos = 80,
   eof_reached = 0,
   error = 0,
   write_flag = 0,
   max_packet_size = 0,
   min_packet_size = 0,
   checksum = 1336520799,
   checksum_ptr = 0x1a605f6 "",
   update_checksum = 0x46b940 <ff_crc04C11DB7_update>,
   read_pause = 0x0,
   read_seek = 0x0,
   seekable = 1,
   direct = 32768,
   protocol_whitelist = 0x0,
   protocol_blacklist = 0x0,
   write_data_type = 0x0,
   ignore_boundary_point = 0,
   written = 0,
   buf_ptr_max = 0x1a605c0 "",
   bytes_read = 18440,
   bytes_written = 0
 }
 (gdb)
 }}}

 I have included some gdb output as a clue: checksum_ptr illegally becomes
 greater than buf_ptr, causing the subtraction in ffio_get_checksum to
 overflow.
-- 
Ticket URL: <https://trac.ffmpeg.org/ticket/10199>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker
_______________________________________________
FFmpeg-trac mailing list
FFmpeg-trac@avcodec.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-trac

To unsubscribe, visit link above, or email
ffmpeg-trac-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to