CVE-2017-11399 FFmpeg-3.3.2 Heap-Out-of-Bound-RW due to an integer overflow in APE decoder


Overview

A vulnerability in FFmpeg lastest version was found with the help of AFL. This is an heap-out-of-bound-write/read vulnerability due to an integer overflow in APE decoder. The same root cause can lead to many different crash points. It can cause Denial-of-Service and probably cause Remote-Code-Execution.

Software & Environments

Software

FFmpeg-3.3.2 https://github.com/FFmpeg/FFmpeg

Download link https://github.com/FFmpeg/FFmpeg/archive/n3.3.2.tar.gz

Operating System

lsb_release -a

    Distributor ID:	Ubuntu 
    Description:	Ubuntu 16.04.1 LTS
    Release:	16.04
    Codename:	xenial

uname -a

    Linux ubuntu 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:25 UTC 2017 i686 i686 i686 GNU/Linux

Compilers & Debuggers

gcc –version

    gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 __clang --version__

    clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
    Target: i686-pc-linux-gnu
    Thread model: posix
    InstalledDir: /usr/bin __rr --version__

    rr version 4.4.0 # Reproduction __gcc debug__

cd /path of FFmpeg master source code/

mkdir build-gcc-debug && cd build-gcc-debug

../configure –enable-debug

make

./ffmpeg_g -y -i /PoC file/ -f “avi” /dev/null

clang asan debug

cd /* path of FFmpeg master source code*/

mkdir build-clang-debug-asan && cd build-clang-debug-asan

../configure –cc=clang –extra-cflags=” -fsanitize=address -g “ –extra-ldflags=” -fsanitize=address -g “ –enable-debug

make

export ASAN_SYMBOLIZER_PATH=/path/to/llvm_build/bin/llvm-symbolizer

./ffmpeg_g -y -i /* PoC file*/ -f “avi” /dev/null

Exception

The exception caught by AddressSanitizer is shown as the following:

    The exception caught by AddressSanitizer is shown as the following:
    ffmpeg version 3.3.git Copyright (c) 2000-2017 the FFmpeg developers
    built with clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
    configuration: --cc=clang --extra-cflags=' -fsanitize=address -g ' --extra-ldflags=' -fsanitize=address -g ' --enable-debug
    libavutil      55. 67.100 / 55. 67.100
    libavcodec     57.100.103 / 57.100.103
    libavformat    57. 75.100 / 57. 75.100
    libavdevice    57.  7.100 / 57.  7.100
    libavfilter     6. 94.100 /  6. 94.100
    libswscale      4.  7.101 /  4.  7.101
    libswresample   2.  8.100 /  2.  8.100
    Ignoring attempt to set invalid timebase 1/0 for st:0
    =================================================================
    ==21024==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb37fe928 at pc 0x08bf326c bp 0xbff99ee8 sp 0xbff99edc
    WRITE of size 4 at 0xb37fe928 thread T0
    #0 0x8bf326b in entropy_decode_mono_3900 /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/apedec.c:671:21
    #1 0x8befbb1 in ape_unpack_mono /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/apedec.c:1366:5
    #2 0x8befbb1 in ape_decode_frame /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/apedec.c:1512
    #3 0x8d0e3f4 in decode_simple_internal /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/decode.c:417:15
    #4 0x8d0e3f4 in decode_simple_receive_frame /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/decode.c:620
    #5 0x8d0e3f4 in decode_receive_frame_internal /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/decode.c:638
    #6 0x8d0cf1b in avcodec_send_packet /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/decode.c:678:15
    #7 0x8ae2b9a in try_decode_frame /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavformat/utils.c:3005:19
    #8 0x8ad4f4d in avformat_find_stream_info /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavformat/utils.c:3822:9
    #9 0x8184009 in open_input_file /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/ffmpeg_opt.c:1064:11
    #10 0x8181f31 in open_files /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/ffmpeg_opt.c:3258:15
    #11 0x818193b in ffmpeg_parse_options /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/ffmpeg_opt.c:3298:11
    #12 0x81bc70e in main /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/ffmpeg.c:4803:11
    #13 0xb73f8636 in __libc_start_main /build/glibc-KM3i_a/glibc-2.23/csu/../csu/libc-start.c:291
    #14 0x809e947 in _start (/home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/ffmpeg_g+0x809e947)

    0xb37fe928 is located 0 bytes to the right of 1499432-byte region [0xb3690800,0xb37fe928)
    allocated by thread T0 here:
    #0 0x8143534 in posix_memalign (/home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/ffmpeg_g+0x8143534)
    #1 0xad88455 in av_malloc /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavutil/mem.c:87:9
    #2 0xad88455 in ff_fast_malloc /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavutil/mem_internal.h:38
    #3 0xad88455 in av_fast_malloc /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavutil/mem.c:471
    #4 0x8bef6cd in ape_decode_frame /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/apedec.c:1496:5

    SUMMARY: AddressSanitizer: heap-buffer-overflow /home/fire/bing/afl/libraries/ffmpegs/0704/FFmpeg-master/build-clang-asan-debug-hash/src/libavcodec/apedec.c:671:21 in entropy_decode_mono_3900
    Shadow bytes around the buggy address:
    0x366ffcd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x366ffce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x366ffcf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x366ffd00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x366ffd10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x366ffd20: 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa fa
    0x366ffd30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x366ffd40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x366ffd50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x366ffd60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x366ffd70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow byte legend (one shadow byte represents 8 application bytes):
    Addressable:           00
    Partially addressable: 01 02 03 04 05 06 07 
    Heap left redzone:       fa
    Heap right redzone:      fb
    Freed heap region:       fd
    Stack left redzone:      f1
    Stack mid redzone:       f2
    Stack right redzone:     f3
    Stack partial redzone:   f4
    Stack after return:      f5
    Stack use after scope:   f8
    Global redzone:          f9
    Global init order:       f6
    Poisoned by user:        f7
    Container overflow:      fc
    Array cookie:            ac
    Intra object redzone:    bb
    ASan internal:           fe
    Left alloca redzone:     ca
    Right alloca redzone:    cb
    ==21024==ABORTING

Analysis

Root Cause

The crash point is:

    @src/libavcodec/apedec.c

    668 int32_t *decoded0 = ctx->decoded[0];
    669 
    670 while (blockstodecode--)
    671        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY); The out-of-bound-write happens when writing the ape decoded values (i.e. return values of __ape_decode_value_3900__) into buffer __ctx->decoded[0]__, which means that the intended access length is larger than the actual length of buffer __ctx->decoded[0]__. From above code snippet, The intended lenth is: > blockstodecode * sizeof(int32_t) = blockstodecode * 4

Now, what is the actual (allocated) length of buffer ctx->decoded[0]?

With several reverse-debugging steps, the allocate-related code snippnet can be found:

    @src/libavcodec/apedec.c:

    1495 /* reallocate decoded sample buffer if needed */
    1496 av_fast_malloc(&s->decoded_buffer, &s->decoded_size,
    1497           2 * FFALIGN(blockstodecode, 8) * sizeof(*s->decoded_buffer));
    1498 if (!s->decoded_buffer)
    1499        return AVERROR(ENOMEM);
    1450 memset(s->decoded_buffer, 0, s->decoded_size);
    1451 s->decoded[0] = s->decoded_buffer;
    1452 s->decoded[1] = s->decoded_buffer + FFALIGN(blockstodecode, 8);
    1453 
    1454 /* get output buffer */
    1455 frame->nb_samples = blockstodecode;
    1456 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
    1457         return ret;
    1458
    1459 s->error=0;
    1460 
    1461 if ((s->channels == 1) || (s->frameflags & APE_FRAMECODE_PSEUDO_STEREO))
    1462         ape_unpack_mono(s, blockstodecode);
    1463 else
    1464         ape_unpack_stereo(s, blockstodecode);

From this code snippet, ctx->decoded[0] comes from s->decoded[0] and s->decoded[0] comes from s->decoded_buffer (Here, s->decoded[0] points to the first half of s->decoded_buffer and s->decoded[1] points to the second half). The allocated length of buffer s->decoded_buffer is:

2FFALIGN(blockstodecode, 8) * sizeof(s->decoded_buffer)

= 2 * ((blockstodecode+8-1)&~(8-1)) * sizeof(int32_t)

= 2 * 0x2002b110 * 4

= 0x100158880 = (oveflow to) 0x00158880

So, there exists an integer overflow when computing the allocated buffer size of s->decoded_buffer; this results in the intended access length is larger than the actual allocated length of buffer s->decode[0].

the intended access size = blockstodecode * 4 = 0x2002b110 * 4 = 0x800ac440

the allocated buffer size = (2 * FFALIGN(blockstodecode, 8) * 4 ) / 2 = 2 * 0x2002b110 * 4 / 2 = 0x00158880 / 2 = 0x000ac440 (INTEGER OVERFLOW!)

So, the root cause of this vulnerability is an integer overflow when computing the allocated size of buffer. i.e.

@src/libavcodec/apedec.c:

1496 av_fast_malloc(&s->decoded_buffer, &s->decoded_size, 2 * FFALIGN(blockstodecode, 8) * sizeof(*s->decoded_buffer));

Debugging

The crash point and corresponding call stack is:

    Program received signal SIGSEGV, Segmentation fault.
    0x083a84ae in entropy_decode_mono_3900 (ctx=0xa672340, blockstodecode=<optimized out>) at               src/libavcodec/apedec.c:671
    671	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    (rr) bt
    #0  0x083a84ae in entropy_decode_mono_3900 (ctx=0xa672340, blockstodecode=<optimized out>) at   src/libavcodec/apedec.c:671
    #1  0x083aa3aa in ape_unpack_mono (count=537047312, ctx=0xa672340) at src/libavcodec/apedec.c:1366
    #2  ape_decode_frame (avctx=0xa671420, data=0xa671fe0, got_frame_ptr=0xbfb15800, avpkt=0xbfb15808) at src/libavcodec/apedec.c:1512
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0xa671420, frame=frame@entry=0xa671fe0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0xa671fe0, avctx=0xa671420) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0xa671420, avpkt=0xbfb158f8) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0xa670200, st=st@entry=0xa670bc0, avpkt=avpkt@entry=0xbfb15a90, options=0xa671960)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0xa670200, options=0xa671960) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfb15dbc, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0xa67002c, l=0xa67002c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbfb17fc4) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbfb17fc4) at src/ffmpeg.c:4803

The around code is:

    (rr) l
    666	static void entropy_decode_mono_3900(APEContext *ctx, int blockstodecode)
    667	{
    668	    int32_t *decoded0 = ctx->decoded[0];
    669	
    670	    while (blockstodecode--)
    671	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    672	}
    673	
    674	static void entropy_decode_stereo_3900(APEContext *ctx, int blockstodecode)
    675	{
    (rr)

Set a watch point for ctx->decoded[0] and reverse-contine:

    (rr) watch -l ctx->decoded[0]
    Hardware watchpoint 1: -location ctx->decoded[0]
    (rr) reverse-continue
    Continuing.

    Program received signal SIGSEGV, Segmentation fault.
    0x083a84ae in entropy_decode_mono_3900 (ctx=0xa672340, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:671
    671	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = (int32_t *) 0xb709a020
    New value = (int32_t *) 0x0
    ape_decode_frame (avctx=0xa671420, data=0xa671fe0, got_frame_ptr=0xbfb15800, avpkt=0xbfb15808) at src/libavcodec/apedec.c:1501
    1501	    s->decoded[0] = s->decoded_buffer;

Find that ctx->decoded[0] comes from s->decoded_buffer. Analyze the around code:

    (rr) l
    1496	    av_fast_malloc(&s->decoded_buffer, &s->decoded_size,
    1497	                   2 * FFALIGN(blockstodecode, 8) * sizeof(*s->decoded_buffer));
    1498	    if (!s->decoded_buffer)
    1499	        return AVERROR(ENOMEM);
    1500	    memset(s->decoded_buffer, 0, s->decoded_size);
    1501	    s->decoded[0] = s->decoded_buffer;
    1502	    s->decoded[1] = s->decoded_buffer + FFALIGN(blockstodecode, 8);
    1503	
    1504	    /* get output buffer */
    1505	    frame->nb_samples = blockstodecode;

Find that s->decoded_buffer is allocated by function av_fast_malloc at line 1496. The implement code of function av_fast_malloc is:

    @src/libavcodec/mem.c:
    469 void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
    470 {
    471         ff_fast_malloc(ptr, size, min_size, 0);
    472 }

    @src/libavcodec/mem_internal.c:
    27 static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
    28 {
    29        void *val;
    30 
    31        memcpy(&val, ptr, sizeof(val));
    32        if (min_size <= *size) {
    33                av_assert0(val || !min_size);
    34                return 0;
    35        }
    36        min_size = FFMAX(min_size + min_size / 16 + 32, min_size);
    37        av_freep(ptr);
    38        val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
    39        memcpy(ptr, &val, sizeof(val));
    40        if (!val)
    41                min_size = 0;
    42        *size = min_size;
    43        return 1;
    44 }

Set a break point at src/libavcodec/apedec.c:1496 and reverse-continue:

    (rr) break src/libavcodec/apedec.c:1496
    Breakpoint 4 at 0x83aa305: file src/libavcodec/apedec.c, line 1496.
    (rr) reverse-continue
    Continuing.

    Breakpoint 4, ape_decode_frame (avctx=0xa671420, data=0xa671fe0, got_frame_ptr=0xbfb15800, avpkt=0xbfb15808) at src/libavcodec/apedec.c:1496
    1496	    av_fast_malloc(&s->decoded_buffer, &s->decoded_size,
    (rr) s
    1497	                   2 * FFALIGN(blockstodecode, 8) * sizeof(*s->decoded_buffer));
    (rr) s
    1496	    av_fast_malloc(&s->decoded_buffer, &s->decoded_size,
    (rr) p s->decoded_size
    value has been optimized out
    (rr) p &s->decoded_size
    value has been optimized out
    (rr) s
    av_fast_malloc (ptr=0xa672cac, size=0xa672cb0, min_size=1411200) at src/libavutil/mem.c:470
    470	{
    (rr) p/x min_size
    $2 = 0x158880
    (rr) p/x *size
    $3 = 0x0

From above debugging info, find that

*size = 0x0

min_size = 0x00158880 (Identical to what we compute out in section “Root Cause”)

min_size > *size

So the allocated size is

FFMAX(min_size + min_size / 16 + 32, min_size) = max(min_size + min_size / 16 + 32, min_size) = min_size + min_size / 16 + 32 = 0x16e128

In general, the allocated size is X + X/16 + 32

X = 2 * FFALIGN(blockstodecode, 8) * 4

Until now, we have confirmed the integer overflow happened and known the allocated size value of buffer s->decoded_buffer.

Also, we can know the condition where the integer overflow is trigged, like the following:

2 * FFALIGN(blockstodecode, 8) * 4 > 0x100000000

=> FFALIGN(blockstodecode, 8) > 0x20000000

=> (blockstodecode+8-1)&~(8-1) > 0x20000000

=> 0x1FFFFFF9 < blockstodecode

In addition to the above condition, we must make sure there are enough memory to be allocated, i.e.:

free memory size > X + X/16 + 32

X = overflowed value of 2 * ((blockstodecode+8-1)&~(8-1)) * 4

Next, where does blockstodecode’s value come from? If we can control it or not?

We can not set a watch point for variable blockstodecode because of optimization. So set a break point at the entry of function ape_decode_frame.

(rr) break ape_decode_frame
Breakpoint 6 at 0x83a9da0: file src/libavcodec/apedec.c, line 1406.
(rr) reverse-continue
Continuing.

Breakpoint 6, ape_decode_frame (avctx=0xa671420, data=0xa671fe0, got_frame_ptr=0xbfb15800, avpkt=0xbfb15808) at src/libavcodec/apedec.c:1406
1406
(rr) n
1409	    APEContext *s = avctx->priv_data;
(rr) p s
$11 = <optimized out>
(rr) n
1418	    av_assert0(s->samples >= 0);
(rr) p s
$12 = (APEContext *) 0xa672340
(rr) n
1420	    if(!s->samples){
(rr) p buf
$14 = <optimized out>
(rr) p avpkt->data
$15 = (uint8_t *) 0xa672db0 "\020\261\002 "
(rr) p/x avpkt->data
$16 = 0xa672db0
(rr) x/32bx avpkt->data
0xa672db0:	0x10	0xb1	0x02	0x20	0x00	0x00	0x00	0x00
0xa672db8:	0x7f	0x66	0x21	0x21	0xae	0x0c	0x0c	0x0c
0xa672dc0:	0x0c	0x0c	0x22	0x0c	0x0c	0x0c	0x0c	0x0c
0xa672dc8:	0x0c	0x0c	0x0c	0x0c	0x0c	0x0c	0x0c	0x0c
(rr)

After several debugging steps, find that value of variable blockstodecode comes from s->samples which comes from variable nblocks which comes from &s->ptr[0:4] which comes from avpkt->data[0:4] whose value here is 0x2002b110. The related code is:

    @src/libavcodec/apedec.c:
    1408 const uint8_t *buf = avpkt->data;
    1409 APEContext *s = avctx->priv_data;
    ...
    1442        s->bdsp.bswap_buf((uint32_t *) s->data, (const uint32_t *) buf,
    1443                  buf_size >> 2);
    1444        memset(s->data + (buf_size & ~3), 0, buf_size & 3);
    1445        s->ptr = s->data;
    1446        s->data_end = s->data + buf_size;
    1447
    1448        nblocks = bytestream_get_be32(&s->ptr)
    ...
    1449        s->samples = nblocks;
    ...
    1489 blockstodecode = FFMIN(s->blocks_per_loop, s->samples);
    1490 // for old files coefficients were not interleaved,
    1491 // so we need to decode all of them at once
    1492 if (s->fileversion < 3930)
    1493        blockstodecode = s->samples;

Besides, in order to make avpkt->data[0:4] flow to blockstodecode, the following condition must be satisfied:

s->fileversion < 3905 <=> ctx->priv_data->fileversion < 3905

Continue to track the source of avpkt->data[0:4]:

    (rr) watch -l avpkt->data[1]
    Hardware watchpoint 7: -location avpkt->data[1]
    (rr) disable 6
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 7: -location avpkt->data[1]

    Old value = 177 '\261'
    New value = 43 '+'
    ape_read_packet (s=0xa670200, pkt=0xbfb15848) at src/libavformat/ape.c:415
    415	    AV_WL32(pkt->data    , nblocks);
    (rr) p/x nblocks
    $18 = 0x2002b110
    (rr) watch -l nblocks
    Hardware watchpoint 8: -location nblocks
    (rr) disable 7
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 8: -location nblocks

    Old value = 537047312
    New value = 16417
    0x08216893 in ape_read_packet (s=0xa670200, pkt=0xbfb15848) at src/libavformat/ape.c:404
    404	    if (ape->frames[ape->currentframe].size <= 0 ||
    (rr) break ape_read_packet
    Breakpoint 9 at 0x8216810: file src/libavformat/ape.c, line 384.
    (rr) l
    399	    if (ape->currentframe == (ape->totalframes - 1))
    400	        nblocks = ape->finalframeblocks;
    401	    else
    402	        nblocks = ape->blocksperframe;
    403	
    404	    if (ape->frames[ape->currentframe].size <= 0 ||
    405	        ape->frames[ape->currentframe].size > INT_MAX - extra_size) {
    406	        av_log(s, AV_LOG_ERROR, "invalid packet size: %d\n",
    407	               ape->frames[ape->currentframe].size);
    408	        ape->currentframe++;
    (rr) reverse-continue
    Continuing.

    Breakpoint 9, ape_read_packet (s=0xa670200, pkt=0xbfb15848) at src/libavformat/ape.c:384
    384	{
    (rr) n
    387	    APEContext *ape = s->priv_data;
    (rr) n
    390	    if (avio_feof(s->pb))
    (rr) p ape
    $19 = (APEContext *) 0xa670aa0
    (rr) p/x *ape
    $20 = {junklength = 0x0, firstframe = 0x50, totalsamples = 0x2002b110, currentframe = 0x0, frames = 0xa670b40, fileversion = 0xf40, 
    padding1 = 0x0, descriptorlength = 0x0, headerlength = 0x20, seektablelength = 0x4, wavheaderlength = 0x2c, audiodatalength = 0x0, 
    audiodatalength_high = 0x0, wavtaillength = 0x0, md5 = {0x0 <repeats 16 times>}, compressiontype = 0x3e8, formatflags = 0x0, 
    blocksperframe = 0x12000, finalframeblocks = 0x2002b110, totalframes = 0x1, bps = 0x10, channels = 0x1, samplerate = 0x0, 
    seektable = 0xa670ba0, bittable = 0x0}
    (rr) n
    392	    if (ape->currentframe >= ape->totalframes)
    (rr) n
    395	    if (avio_seek(s->pb, ape->frames[ape->currentframe].pos, SEEK_SET) < 0)
    (rr) n
    399	    if (ape->currentframe == (ape->totalframes - 1))
    (rr) n
    400	        nblocks = ape->finalframeblocks;
    (rr) p/x ape->finalframeblocks
    $21 = 0x2002b110
    (rr) n
    404	    if (ape->frames[ape->currentframe].size <= 0 ||
    (rr) watch -l ape->finalframeblocks
    Hardware watchpoint 10: -location ape->finalframeblocks
    (rr) disable 8 9
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 10: -location ape->finalframeblocks

    Old value = 537047312
    New value = 0
    0x08216b9b in ape_read_header (s=0xa670200) at src/libavformat/ape.c:221
    221	        ape->finalframeblocks     = avio_rl32(pb);
    (rr) x/16b pb-4
    0xa678830:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa678838:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    (rr) p pb
    $22 = (AVIOContext *) 0xa678ae0
    (rr) p *pb
    $23 = {av_class = 0x8cd73e0 <ff_avio_class>, buffer = 0xa678b90 "MAC @\017\350\003", buffer_size = 32768, buf_ptr = 0xa678bb0 "\004", 
    buf_end = 0xa678ea7 "", opaque = 0xa6709c0, read_packet = 0x8231ca0 <io_read_packet>, write_packet = 0x8231c90 <io_write_packet>, 
    seek = 0x8231c80 <io_seek>, pos = 791, must_flush = 0, eof_reached = 0, write_flag = 0, max_packet_size = 0, checksum = 0, 
    checksum_ptr = 0x0, update_checksum = 0x0, error = 0, read_pause = 0x8231b80 <io_read_pause>, read_seek = 0x8231bb0 <io_read_seek>, 
    seekable = 1, maxsize = 0, direct = 0, bytes_read = 791, seek_count = 0, writeout_count = 0, orig_buffer_size = 32768, 
    short_seek_threshold = 4096, protocol_whitelist = 0xa678ad0 "file,crypto", protocol_blacklist = 0x0, write_data_type = 0x0, 
    ignore_boundary_point = 0, current_type = AVIO_DATA_MARKER_UNKNOWN, last_time = -9223372036854775808, 
    short_seek_get = 0x8231c70 <io_short_seek>, written = 0, buf_ptr_max = 0xa678b9a "\001", min_packet_size = 0}
    (rr) l avio_rl32
    file: "src/libavformat/aviobuf.c", line number: 623
    file: "src/libavformat/aviobuf.c", line number: 753
    (rr) x/16bx pb->buf_ptr-4
    0xa678bac:	0x10	0xb1	0x02	0x20	0x04	0x00	0x10	0xff
    0xa678bb4:	0x00	0x61	0xff	0xff	0xff	0xc0	0xfe	0x0a
    (rr) p/x pb->buf_ptr[-3]
    $24 = 0xb1
    (rr) watch -l pb->buf_ptr[-3]
    Hardware watchpoint 11: -location pb->buf_ptr[-3]
    (rr) disable 10
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 11: -location pb->buf_ptr[-3]

    Old value = 177 '\261'
    New value = 0 '\000'
    __memcpy_sse2_unaligned () at ../sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S:492
    492	../sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S: No such file or directory.
    (rr) bt
    #0  __memcpy_sse2_unaligned () at ../sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S:492
    #1  0x08235ffe in memcpy (__len=791, __src=<optimized out>, __dest=0xa678b90) at /usr/include/i386-linux-gnu/bits/string3.h:53
    #2  avio_read (s=0xa678ae0, buf=0xa678b90 "MAC @\017\350\003", size=2048) at src/libavformat/aviobuf.c:666
    #3  0x0825ee6a in av_probe_input_buffer2 (pb=0xa678ae0, fmt=0xa670204, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", logctx=0xa670200, offset=0, max_probe_size=1048576) at src/libavformat/format.c:314
    #4  0x08360650 in init_input (options=0xbfb15c10, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", s=0xa670200) at src/libavformat/utils.c:421
    #5  avformat_open_input (ps=0xbfb15ca8, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", fmt=0x0, options=0xa6700ac) at src/libavformat/utils.c:537
    #6  0x080d2e17 in open_input_file (o=o@entry=0xbfb15dbc, filename=<optimized out>) at src/ffmpeg_opt.c:1042
    #7  0x080d44ed in open_files (l=0xa67002c, l=0xa67002c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #8  ffmpeg_parse_options (argc=7, argv=0xbfb17fc4) at src/ffmpeg_opt.c:3298
    #9  0x080c2fc9 in main (argc=7, argv=0xbfb17fc4) at src/ffmpeg.c:4803
    (rr) break src/libavformat/aviobuf.c:666
    Breakpoint 12 at 0x8236001: src/libavformat/aviobuf.c:666. (3 locations)
    (rr) disable 11
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = (int32_t *) 0x0
    New value = <unreadable>
    __brk (addr=0xa691000) at ../sysdeps/unix/sysv/linux/i386/brk.c:35
    35	../sysdeps/unix/sysv/linux/i386/brk.c: No such file or directory.
    (rr) enable 11
    (rr) c
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = <unreadable>
    New value = (int32_t *) 0x0
    0xb7710c2a in __kernel_vsyscall ()
    (rr) disable 12
    (rr) break avio_read
    Breakpoint 13 at 0x8235e60: avio_read. (3 locations)
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = (int32_t *) 0x0
    New value = <unreadable>
    __brk (addr=0xa691000) at ../sysdeps/unix/sysv/linux/i386/brk.c:35
    35	in ../sysdeps/unix/sysv/linux/i386/brk.c
    (rr) c
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = <unreadable>
    New value = (int32_t *) 0x0
    0xb7710c2a in __kernel_vsyscall ()
    (rr) disable 13
    (rr) break av_probe_input_buffer2
    Breakpoint 14 at 0x825ed40: file src/libavformat/format.c, line 269.
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = (int32_t *) 0x0
    New value = <unreadable>
    __brk (addr=0xa691000) at ../sysdeps/unix/sysv/linux/i386/brk.c:35
    35	in ../sysdeps/unix/sysv/linux/i386/brk.c
    (rr) c
    Continuing.

    Hardware watchpoint 1: -location ctx->decoded[0]

    Old value = <unreadable>
    New value = (int32_t *) 0x0
    0xb7710c2a in __kernel_vsyscall ()
    (rr) c
    Continuing.
    ffmpeg version 3.3.git Copyright (c) 2000-2017 the FFmpeg developers
    built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 20160609
    configuration: --enable-debug
    libavutil      55. 67.100 / 55. 67.100
    libavcodec     57.100.103 / 57.100.103
    libavformat    57. 75.100 / 57. 75.100
    libavdevice    57.  7.100 / 57.  7.100
    libavfilter     6. 94.100 /  6. 94.100
    libswscale      4.  7.101 /  4.  7.101
    libswresample   2.  8.100 /  2.  8.100

    Breakpoint 14, av_probe_input_buffer2 (pb=0xa678ae0, fmt=0xa670204, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", logctx=0xa670200, offset=0, max_probe_size=1048576) at src/libavformat/format.c:269
    269	{
    (rr) brea src/libavformat/format.c:314
    Breakpoint 15 at 0x825ee52: file src/libavformat/format.c, line 314.
    (rr) c
    Continuing.

    Breakpoint 15, av_probe_input_buffer2 (pb=0xa678ae0, fmt=0xa670204, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", logctx=0xa670200, offset=0, max_probe_size=1048576) at src/libavformat/format.c:314
    314	        if ((ret = avio_read(pb, buf + buf_offset,
    (rr) s
    avio_read (s=0xa678ae0, buf=0xa678b90 "\310\tg\n", size=2048) at src/libavformat/aviobuf.c:631
    631	{
    (rr) l
    626	        return *s->buf_ptr++;
    627	    return 0;
    628	}
    629	
    630	int avio_read(AVIOContext *s, unsigned char *buf, int size)
    631	{
    632	    int len, size1;
    633	
    634	    size1 = size;
    635	    while (size > 0) {
    (rr) n
    635	    while (size > 0) {
    (rr) n
    631	{
    (rr) n
    635	    while (size > 0) {
    (rr) n
    636	        len = FFMIN(s->buf_end - s->buf_ptr, size);
    (rr) p *s
    $25 = {av_class = 0x8cd73e0 <ff_avio_class>, buffer = 0xa670aa0 "", buffer_size = 32768, buf_ptr = 0xa670aa0 "", buf_end = 0xa670aa0 "", 
    opaque = 0xa6709c0, read_packet = 0x8231ca0 <io_read_packet>, write_packet = 0x8231c90 <io_write_packet>, seek = 0x8231c80 <io_seek>, 
    pos = 0, must_flush = 0, eof_reached = 0, write_flag = 0, max_packet_size = 0, checksum = 0, checksum_ptr = 0x0, update_checksum = 0x0, 
    error = 0, read_pause = 0x8231b80 <io_read_pause>, read_seek = 0x8231bb0 <io_read_seek>, seekable = 1, maxsize = 0, direct = 0, 
    bytes_read = 0, seek_count = 0, writeout_count = 0, orig_buffer_size = 32768, short_seek_threshold = 4096, 
    protocol_whitelist = 0xa678ad0 "file,crypto", protocol_blacklist = 0x0, write_data_type = 0x0, ignore_boundary_point = 0, 
    current_type = AVIO_DATA_MARKER_UNKNOWN, last_time = -9223372036854775808, short_seek_get = 0x8231c70 <io_short_seek>, written = 0, 
    buf_ptr_max = 0xa670aa0 "", min_packet_size = 0}
    (rr) n
    637	        if (len == 0 || s->write_flag) {
    (rr) p len
    $26 = 0
    (rr) x/16b s->buffer
    0xa670aa0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670aa8:	0x00	0x00	0x00	0x00	0x59	0x05	0x02	0x00
    (rr) x/32b s->buffer
    0xa670aa0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670aa8:	0x00	0x00	0x00	0x00	0x59	0x05	0x02	0x00
    0xa670ab0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670ab8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    (rr) n
    638	            if((s->direct || size > s->buffer_size) && !s->update_checksum) {
    (rr) n
    660	                fill_buffer(s);
    (rr) n
    662	                if (len == 0)
    (rr) n
    636	        len = FFMIN(s->buf_end - s->buf_ptr, size);
    (rr) n
    637	        if (len == 0 || s->write_flag) {
    (rr) n
    666	            memcpy(buf, s->buf_ptr, len);
    (rr) x/32b s->buf_ptr
    0xa670aa0:	0x4d	0x41	0x43	0x20	0x40	0x0f	0xe8	0x03
    0xa670aa8:	0x00	0x00	0x01	0x00	0x00	0x00	0x00	0x00
    0xa670ab0:	0x2c	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670ab8:	0x01	0x00	0x00	0x00	0x10	0xb1	0x02	0x20
    (rr) watch -l s->buf_ptr[29]
    Hardware watchpoint 16: -location s->buf_ptr[29]
    (rr) disable 14 15
    (rr) reverse-continue
    Continuing.

    Hardware watchpoint 16: -location s->buf_ptr[29]

    Old value = 177 '\261'
    New value = 0 '\000'
    0xb76e3af4 in ?? () from /usr/bin/../lib/librrpreload.so
    (rr) bt
    #0  0xb76e3af4 in ?? () from /usr/bin/../lib/librrpreload.so
    #1  0xb76e4b48 in ?? () from /usr/bin/../lib/librrpreload.so
    #2  0xb74e5053 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
    #3  0x08381a33 in read (__nbytes=<optimized out>, __buf=0xa670aa0, __fd=<optimized out>) at /usr/include/i386-linux-gnu/bits/unistd.h:44
    #4  file_read (h=0xa6708e0, buf=0xa670aa0 "MAC @\017\350\003", size=<optimized out>) at src/libavformat/file.c:112
    #5  0x0822fab0 in retry_transfer_wrapper (transfer_func=0x8381a10 <file_read>, size_min=1, size=32768, buf=0xa670aa0 "MAC @\017\350\003", 
    h=0xa6708e0) at src/libavformat/avio.c:378
    #6  ffurl_read (h=0xa6708e0, buf=0xa670aa0 "MAC @\017\350\003", size=32768) at src/libavformat/avio.c:411
    #7  0x08235fa4 in fill_buffer (s=0xa678ae0) at src/libavformat/aviobuf.c:566
    #8  avio_read (s=0xa678ae0, buf=0xa678b90 "\310\tg\n", size=2048) at src/libavformat/aviobuf.c:660
    #9  0x0825ee6a in av_probe_input_buffer2 (pb=0xa678ae0, fmt=0xa670204, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", logctx=0xa670200, offset=0, max_probe_size=1048576) at src/libavformat/format.c:314
    #10 0x08360650 in init_input (options=0xbfb15c10, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", s=0xa670200) at src/libavformat/utils.c:421
    #11 avformat_open_input (ps=0xbfb15ca8, 
    filename=0xbfb1a18e "../build-clang-asan-debug-hash/samples/50baca3f8895a3fa0f51e553373be6b0-varas_ra-crash.zip/id_000106,sig_06,src_051941,op_havoc,rep_16.mp4", fmt=0x0, options=0xa6700ac) at src/libavformat/utils.c:537
    #12 0x080d2e17 in open_input_file (o=o@entry=0xbfb15dbc, filename=<optimized out>) at src/ffmpeg_opt.c:1042
    #13 0x080d44ed in open_files (l=0xa67002c, l=0xa67002c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #14 ffmpeg_parse_options (argc=7, argv=0xbfb17fc4) at src/ffmpeg_opt.c:3298
    #15 0x080c2fc9 in main (argc=7, argv=0xbfb17fc4) at src/ffmpeg.c:4803
    (rr) break file_read
    Breakpoint 17 at 0x8381a10: file src/libavformat/file.c, line 108.
    (rr) disable 16
    (rr) reverse-continue
    Continuing.

    Breakpoint 17, file_read (h=0xa6708e0, buf=0xa670aa0 "", size=32768) at src/libavformat/file.c:108
    108	{
    (rr) l
    103	    .option     = pipe_options,
    104	    .version    = LIBAVUTIL_VERSION_INT,
    105	};
    106	
    107	static int file_read(URLContext *h, unsigned char *buf, int size)
    108	{
    109	    FileContext *c = h->priv_data;
    110	    int ret;
    111	    size = FFMIN(size, c->blocksize);
    112	    ret = read(c->fd, buf, size);
    (rr) x/32b buf
    0xa670aa0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670aa8:	0x00	0x00	0x00	0x00	0x59	0x05	0x02	0x00
    0xa670ab0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670ab8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    (rr) n
    109	    FileContext *c = h->priv_data;
    (rr) n
    108	{
    (rr) n
    109	    FileContext *c = h->priv_data;
    (rr) n
    112	    ret = read(c->fd, buf, size);
    (rr) n
    113	    if (ret == 0 && c->follow)
    (rr) x/32b buf
    0xa670aa0:	0x4d	0x41	0x43	0x20	0x40	0x0f	0xe8	0x03
    0xa670aa8:	0x00	0x00	0x01	0x00	0x00	0x00	0x00	0x00
    0xa670ab0:	0x2c	0x00	0x00	0x00	0x00	0x00	0x00	0x00
    0xa670ab8:	0x01	0x00	0x00	0x00	0x10	0xb1	0x02	0x20
    (rr) x/4dx buf+28
    0xa670abc:	0x10	0xb1	0x02	0x20
    (rr) 

Finally, find avpkt->data[0:4] comes from the input file with offset 0x1c to 0x1f. The header of PoC file is like the following:

    @ HEADER OF POC FILE
    4D 41 43 20 40 0F E8 03 00 00 01 00 00 00 00 00
    2C 00 00 00 00 00 00 00 01 00 00 00 10 B1 02 20

So, we can control value of variable blockstodecode_ by modifying value at file offset 0x1c to 0x1f. So the related formula:

allocated size of ctx->decode[0] = X + X/16 +32

X = 2 * FFMIN(POC[0x1c:0x1f], 8) * 4 = 8 * ((POC[0x1c:0x1f]+8-1)&~(8-1))

the integer overflow condition is: POC[0x1c:0x1f] > 0x1ffffff9

Besides, file version (i.e. s->fileversion) comes from POC[0x04:0x05]

Now, we can control the size of buffer ctx->decoded[0] where out-of-bound-write happens. Next, what value can be out-of-bound writen into?

    Program received signal SIGSEGV, Segmentation fault.
    0x083a84ae in entropy_decode_mono_3900 (ctx=0xa672340, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:671
    671	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    (rr) l 
    666	static void entropy_decode_mono_3900(APEContext *ctx, int blockstodecode)
    667	{
    668	    int32_t *decoded0 = ctx->decoded[0];
    669	
    670	    while (blockstodecode--)
    671	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    672	}
    673	
    674	static void entropy_decode_stereo_3900(APEContext *ctx, int blockstodecode)
    675	{
    (rr)

The values writen into buffer ctx->decoded[0] are the return values of function ape_decode_value_3900. ape_decode_value_3900 is used to decode the ape audio data, which means we can somewhat control the return value by controlling the APE raw data; i.e. we can somewhat control the values which are out-of-bound writen in. Here, I will not analyze this to exploit it.

Further Analysis

From the code defined in function ape_read_header at src/libavformat/ape.c:160, structure of ape file header can be inferenced as the following:

if fileversion < 3980:

    4D 41 43 20 40 0F E8 03 00 00 01 00 00 00 00 00
    2C 00 00 00 00 00 00 00 01 00 00 00 10 B1 02 20
0-3 4-5 6-7 8-9 10-11 12-15
Tag (4 bytes) FileVersion (2 bytes) CompressionType (2 bytes) FormatFlags (2 bytes) Channels (2 bytes) SampleRate (4 bytes)
WavHeaderLength (4 bytes) WavTailLength (4 bytes)   TotalFrames (4 bytes)   FinalFrameBlocks (4 bytes)

else:

    4D 41 43 20 8C 0F E8 03 00 00 01 00 00 00 00 00
    2C 00 00 00 00 00 00 00 01 00 00 00 10 B1 02 20
0-3 4-5 6-7 8-11 12-15
Tag (4 bytes) FileVersion (2 bytes) Padding1 (2 bytes) DescriptorLength (4 bytes) HeaderLength (4 bytes)
SeektableLength (4 bytes) WavHeaderLength (4 bytes)   AudioDataLength (4 bytes) AudioDataLength_High (4 bytes)

From code snippet in function ape_decode_frame:,

    @src/libavcodec/apedec.c:
    1511 if ((s->channels == 1) || (s->frameflags & APE_FRAMECODE_PSEUDO_STEREO))
    1512         ape_unpack_mono(s, blockstodecode);
    1513 else
    1514         ape_unpack_stereo(s, blockstodecode);

we know it may be possible to make crash happen in ape_unpack_stereo_XXXX serials function. In fact, it is. Even more, we can further control which mono_XXXX serial function or ape_unpack_stereo_YYYY serial function the similar crash happen in. The following are serveral similar crash call stack due to the same root cause:

crash in stereo_XXXX/mono_XXXX serial functions

PoC: out-of-bound-write-stereo-3900.ape

    Program received signal SIGSEGV, Segmentation fault.
    0x083a9476 in entropy_decode_stereo_3900 (ctx=0xa2ba320, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:681
    681	        *decoded0++ = ape_decode_value_3900(ctx, &ctx->riceY);
    (rr) bt
    #0  0x083a9476 in entropy_decode_stereo_3900 (ctx=0xa2ba320, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:681
    #1  0x083aa4f6 in ape_unpack_stereo (count=537033221, ctx=0xa2ba320) at src/libavcodec/apedec.c:1389
    #2  ape_decode_frame (avctx=0xa2b9400, data=0xa2b9fc0, got_frame_ptr=0xbfd03730, avpkt=0xbfd03738) at src/libavcodec/apedec.c:1514
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0xa2b9400, frame=frame@entry=0xa2b9fc0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0xa2b9fc0, avctx=0xa2b9400) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0xa2b9400, avpkt=0xbfd03828) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0xa2b8200, st=st@entry=0xa2b8ba0, avpkt=avpkt@entry=0xbfd039c0, options=0xa2b9940)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0xa2b8200, options=0xa2b9940) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfd03cec, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0xa2b802c, l=0xa2b802c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbfd05ef4) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbfd05ef4) at src/ffmpeg.c:4803
    (rr)

PoC: out-of-bound-write-mono-0000.ape:

    Program received signal SIGSEGV, Segmentation fault.
    0x083a80df in decode_array_0000 (ctx=0xb169320, out=0xac684020, rice=<optimized out>, blockstodecode=1094993478, gb=<optimized out>)
    at src/libavcodec/apedec.c:612
    612	        out[i] = get_rice_ook(&ctx->gb, rice->k);
    (rr) bt
    #0  0x083a80df in decode_array_0000 (ctx=0xb169320, out=0xac684020, rice=<optimized out>, blockstodecode=1094993478, gb=<optimized out>)
    at src/libavcodec/apedec.c:612
    #1  0x083aa3aa in ape_unpack_mono (count=1094993478, ctx=0xb169320) at src/libavcodec/apedec.c:1366
    #2  ape_decode_frame (avctx=0xb168400, data=0xb168fc0, got_frame_ptr=0xbfb466e0, avpkt=0xbfb466e8) at src/libavcodec/apedec.c:1512
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0xb168400, frame=frame@entry=0xb168fc0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0xb168fc0, avctx=0xb168400) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0xb168400, avpkt=0xbfb467d8) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0xb167200, st=st@entry=0xb167ba0, avpkt=avpkt@entry=0xbfb46970, options=0xb168940)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0xb167200, options=0xb168940) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfb46c9c, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0xb16702c, l=0xb16702c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbfb48ea4) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbfb48ea4) at src/ffmpeg.c:4803
    (rr)

PoC: out-of-bound-write-mono-3860.ape

    Program received signal SIGSEGV, Segmentation fault.
    0x083a6358 in entropy_decode_mono_3860 (ctx=0x9a2c320, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:651
    651	        *decoded0++ = ape_decode_value_3860(ctx, &ctx->gb, &ctx->riceY);
    (gdb) bt
    #0  0x083a6358 in entropy_decode_mono_3860 (ctx=0x9a2c320, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:651
    #1  0x083aa3aa in ape_unpack_mono (count=1090681536, ctx=0x9a2c320) at src/libavcodec/apedec.c:1366
    #2  ape_decode_frame (avctx=0x9a2b440, data=0x9a2bfe0, got_frame_ptr=0xbfffc850, avpkt=0xbfffc858) at src/libavcodec/apedec.c:1512
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0x9a2b440, frame=frame@entry=0x9a2bfe0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0x9a2bfe0, avctx=0x9a2b440) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0x9a2b440, avpkt=0xbfffc948) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0x9a2a200, st=st@entry=0x9a2ac00, avpkt=avpkt@entry=0xbfffcae0, options=0x9a2b980)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0x9a2a200, options=0x9a2b980) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfffce0c, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0x9a2a02c, l=0x9a2a02c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbffff014) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbffff014) at src/ffmpeg.c:4803

PoC: out-of-bound-stereo-3860.ape:

    Program received signal SIGSEGV, Segmentation fault.
    0x083a654c in entropy_decode_stereo_3860 (ctx=0x9a2c300, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:661
    661	        *decoded0++ = ape_decode_value_3860(ctx, &ctx->gb, &ctx->riceY);
    (gdb) bt
    #0  0x083a654c in entropy_decode_stereo_3860 (ctx=0x9a2c300, blockstodecode=<optimized out>) at src/libavcodec/apedec.c:661
    #1  0x083aa4f6 in ape_unpack_stereo (count=536870928, ctx=0x9a2c300) at src/libavcodec/apedec.c:1389
    #2  ape_decode_frame (avctx=0x9a2b420, data=0x9a2bfc0, got_frame_ptr=0xbfffc850, avpkt=0xbfffc858) at src/libavcodec/apedec.c:1514
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0x9a2b420, frame=frame@entry=0x9a2bfc0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0x9a2bfc0, avctx=0x9a2b420) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0x9a2b420, avpkt=0xbfffc948) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0x9a2a200, st=st@entry=0x9a2abe0, avpkt=avpkt@entry=0xbfffcae0, options=0x9a2b960)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0x9a2a200, options=0x9a2b960) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfffce0c, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0x9a2a02c, l=0x9a2a02c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbffff014) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbffff014) at src/ffmpeg.c:4803

out-of-bound-read

In addition to out-of-bound-write, out-of-bound-read can also be triggered in some condition just like the following:

PoC: out-of-bound-read-mono-3800.ape:

    Program received signal SIGSEGV, Segmentation fault.
    predictor_decode_mono_3800 (ctx=<optimized out>, count=1073556167) at src/libavcodec/apedec.c:1017
    1017	            *decoded0 = filter_3800(p, *decoded0, 0, YDELAYA, YDELAYB,
    (gdb) bt
    #0  predictor_decode_mono_3800 (ctx=<optimized out>, count=1073556167) at src/libavcodec/apedec.c:1017
    #1  0x083aa3b4 in ape_unpack_mono (count=1073904320, ctx=0x9a2c300) at src/libavcodec/apedec.c:1369
    #2  ape_decode_frame (avctx=0x9a2b420, data=0x9a2bfc0, got_frame_ptr=0xbfffc860, avpkt=0xbfffc868) at src/libavcodec/apedec.c:1512
    #3  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0x9a2b420, frame=frame@entry=0x9a2bfc0) at src/libavcodec/decode.c:417
    #4  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #5  decode_receive_frame_internal (frame=0x9a2bfc0, avctx=0x9a2b420) at src/libavcodec/decode.c:638
    #6  avcodec_send_packet (avctx=0x9a2b420, avpkt=0xbfffc958) at src/libavcodec/decode.c:678
    #7  0x083525ae in try_decode_frame (s=s@entry=0x9a2a200, st=st@entry=0x9a2abe0, avpkt=avpkt@entry=0xbfffcaf0, options=0x9a2b960)
    at src/libavformat/utils.c:3005
    #8  0x0835cbca in avformat_find_stream_info (ic=0x9a2a200, options=0x9a2b960) at src/libavformat/utils.c:3822
    #9  0x080d1907 in open_input_file (o=o@entry=0xbfffce1c, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #10 0x080d44ed in open_files (l=0x9a2a02c, l=0x9a2a02c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #11 ffmpeg_parse_options (argc=7, argv=0xbffff024) at src/ffmpeg_opt.c:3298
    #12 0x080c2fc9 in main (argc=7, argv=0xbffff024) at src/ffmpeg.c:4803
    (gdb)

PoC: out-of-bound-read-ape-decode-frame.ape:

    Program received signal SIGSEGV, Segmentation fault.
    ape_decode_frame (avctx=0x9a2b420, data=0x9a2bfc0, got_frame_ptr=0xbfffc860, avpkt=0xbfffc868) at src/libavcodec/apedec.c:1535
    1535	                *sample16++ = s->decoded[ch][i];
    (gdb) bt
    #0  ape_decode_frame (avctx=0x9a2b420, data=0x9a2bfc0, got_frame_ptr=0xbfffc860, avpkt=0xbfffc868) at src/libavcodec/apedec.c:1535
    #1  0x083e8f16 in decode_simple_internal (avctx=avctx@entry=0x9a2b420, frame=frame@entry=0x9a2bfc0) at src/libavcodec/decode.c:417
    #2  0x083e9a11 in decode_simple_receive_frame (frame=<optimized out>, avctx=<optimized out>) at src/libavcodec/decode.c:620
    #3  decode_receive_frame_internal (frame=0x9a2bfc0, avctx=0x9a2b420) at src/libavcodec/decode.c:638
    #4  avcodec_send_packet (avctx=0x9a2b420, avpkt=0xbfffc958) at src/libavcodec/decode.c:678
    #5  0x083525ae in try_decode_frame (s=s@entry=0x9a2a200, st=st@entry=0x9a2abe0, avpkt=avpkt@entry=0xbfffcaf0, options=0x9a2b960)
    at src/libavformat/utils.c:3005
    #6  0x0835cbca in avformat_find_stream_info (ic=0x9a2a200, options=0x9a2b960) at src/libavformat/utils.c:3822
    #7  0x080d1907 in open_input_file (o=o@entry=0xbfffce1c, filename=<optimized out>) at src/ffmpeg_opt.c:1064
    #8  0x080d44ed in open_files (l=0x9a2a02c, l=0x9a2a02c, open_file=0x80d1450 <open_input_file>, inout=0x8d0605e "input")
    at src/ffmpeg_opt.c:3258
    #9  ffmpeg_parse_options (argc=7, argv=0xbffff024) at src/ffmpeg_opt.c:3298
    #10 0x080c2fc9 in main (argc=7, argv=0xbffff024) at src/ffmpeg.c:4803

Conclusion

This is a heap-buffer-overflow (out-of-bound-write/read) vulnerability which is caused by an integer overflow:

@src/libavcodec/apedec.c:

1496 av_fast_malloc(&s->decoded_buffer, &s->decoded_size, 2 * FFALIGN(blockstodecode, 8) * sizeof(*s->decoded_buffer));

The allocated size of related buffer ctx->decoded[0] can be controlled by modifying input file bytes from offset 0x1c to 0x1f. Also, the values out-of-bound written into buffer ctx->decoded[0] can be somewhat controlled. This is to say, the vulnerability can cause Denial-of-Service and probably cause RCE. Besides, there are several vairants which has similar but different crash call stack due to the same root cause, which adds the possibility that this vulnerability can be exploited to achive RCE.

Status

The vulnerability has been assigned CVE-2017-11399 and the upstream has patched it.

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11399

CONFIRM:https://github.com/FFmpeg/FFmpeg/commit/ba4beaf6149f7241c8bd85fe853318c2f6837ad0