oss-sec mailing list archives

[CVE-2016-6671] ffmpeg buffer overflow when decoding swf


From: 连一汉 <lianyihan () 360 cn>
Date: Fri, 12 Aug 2016 10:10:10 +0000


Hi , I’m Lian ,a security researcher in Qihoo 360.

I found a vulnerability of ffmpeg .

This is a buffer overflow vulnerability when decoding swf, and has been assigned the CVE identifier CVE-2016-6671 .

Version Affected:  <=3.1.1
Fixed Version:        3.1.2

Web site:    http://ffmpeg.org/security.html

Vulnerability detail:


================== test command =======================



Ffmpeg -i poc.swf -b:v 640k -y output.ts

============== affected code and crash info =================

On libavcodec/rawdec.c :

raw_decode()
{
…
memcpy(context->palette->data, pal, avpkt->size - vid_size);                          // buffer overflow
…
}

Back trace:
        #0  0x00007f6a128955f7 in raise () from /lib64/libc.so.6
#1  0x00007f6a12896ce8 in abort () from /lib64/libc.so.6
#2  0x00000000004d0d86 in __sanitizer::Abort() ()
    at 
/tmp/llvm-3.8.0rc3.src/utils/release/final/llvm.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc:124
#3  0x00000000004beb65 in __sanitizer::Die() ()
    at 
/tmp/llvm-3.8.0rc3.src/utils/release/final/llvm.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_common.cc:147
#4  0x00000000004b8a22 in ~ScopedInErrorReport () at 
/tmp/llvm-3.8.0rc3.src/utils/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_report.cc:709
#5  0x00000000004b83d1 in ReportGenericError () at 
/tmp/llvm-3.8.0rc3.src/utils/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_report.cc:1111
#6  0x000000000049c0e2 in __interceptor_memcpy ()
   at /tmp/llvm-3.8.0rc3.src/utils/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:438
#7  0x0000000001444fdb in raw_decode (avctx=0x619000008c80, data=0x61500003c580, got_frame=0x7fff89caa048, 
avpkt=0x7fff89ca9a18)
    at libavcodec/rawdec.c:381
#8  0x00000000015e7f18 in avcodec_decode_video2 (avctx=0x619000008c80, picture=0x61500003c580, 
got_picture_ptr=0x7fff89caa048, avpkt=0x7fff89ca9ff0)
    at libavcodec/utils.c:2224
#9  0x00000000005285ee in decode_video (ist=0x61400001ba40, pkt=0x7fff89ca9ff0, got_output=0x7fff89caa048) at 
ffmpeg.c:2087
#10 0x000000000051733a in process_input_packet (ist=0x61400001ba40, pkt=0x7fff89caa888, no_eof=0) at ffmpeg.c:2340
#11 0x000000000051ec93 in process_input (file_index=0) at ffmpeg.c:4020
#12 0x0000000000514763 in transcode_step () at ffmpeg.c:4108
#13 0x000000000050d3f1 in transcode () at ffmpeg.c:4162
#14 0x000000000050c2e9 in main (argc=6, argv=0x7fff89caad18) at ffmpeg.c:4355

====================== patch ===========================

Found-by: <lianyihan () 360 cn>
Signed-off-by: Michael Niedermayer <michael () niedermayer cc>
---
libavcodec/rawdec.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c
index 765e567..f97a839 100644
--- a/libavcodec/rawdec.c
+++ b/libavcodec/rawdec.c
@@ -365,20 +365,29 @@ static int raw_decode(AVCodecContext *avctx, void *da=
ta, int *got_frame,
     if (avctx->pix_fmt =3D=3D AV_PIX_FMT_PAL8) {
         const uint8_t *pal =3D av_packet_get_side_data(avpkt, AV_PKT_DATA_=
PALETTE,
                                                      NULL);
-        if (pal) {
-            av_buffer_unref(&context->palette);
+        int ret;
+        if (!context->palette)
             context->palette =3D av_buffer_alloc(AVPALETTE_SIZE);
-            if (!context->palette) {
-                av_buffer_unref(&frame->buf[0]);
-                return AVERROR(ENOMEM);
-            }
+        if (!context->palette) {
+            av_buffer_unref(&frame->buf[0]);
+            return AVERROR(ENOMEM);
+        }
+        ret =3D av_buffer_make_writable(&context->palette);
+        if (ret < 0) {
+            av_buffer_unref(&frame->buf[0]);
+            return ret;
+        }
+
+        if (pal) {
             memcpy(context->palette->data, pal, AVPALETTE_SIZE);
             frame->palette_has_changed =3D 1;
         } else if (context->is_nut_pal8) {
             int vid_size =3D avctx->width * avctx->height;
-            if (avpkt->size - vid_size) {
+            int pal_size =3D avpkt->size - vid_size;
+
+            if (avpkt->size > vid_size && pal_size <=3D AVPALETTE_SIZE) {
                 pal =3D avpkt->data + vid_size;
-                memcpy(context->palette->data, pal, avpkt->size - vid_size=
);
+                memcpy(context->palette->data, pal, pal_size);
                 frame->palette_has_changed =3D 1;
             }
         }

Current thread: