[Security-team] I: Ffmpeg heap buffer overflow

Grigory Batalov bga на altlinux.ru
Ср Дек 7 15:36:36 MSK 2005


On Wed, 07 Dec 2005 09:59:58 +0300
Vladimir Lettiev <crux на gorodmasterov.com> wrote:

> http://www.securityfocus.com/bid/15743
> 
> Ссылки на письмо с описанием проблемы и патчем, который есть в cvs также 
> можно найти там.
> 
> Ffmpeg для alm24 собирал Юрий Седунов. Пакет находится в секции main, а 
> значит требует обновления. Сейчас его собирали Kachalov Anton и Grigory 
> Batalov. Делаю CC на них, возможно они смогут помочь с подготовкой 
> обновления для ALM24 (да и для Sisyphus актуально).

  Вызвать обещанный segmentation fault на маленьких картинках
  мне не удалось =). Использовался PNG из письма автора:

http://mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20051130/9fd15dfe/pal8bug.png

  и следующие команды:

cp pal8bug.png pal8bug1.png
ffmpeg -f image -img png -i pal8bug%d.png -s 100x100 -y pal8bug.mpg

  Тем не менее, патч из CVS FFmpeg легко портируется:

http://www1.mplayerhq.hu/cgi-bin/cvsweb.cgi/ffmpeg/libavcodec/utils.c.diff?cvsroot=FFMpeg&r2=1.162&r1=1.161&f=u

  Результаты прилагаю. Прежде чем выпускать update, я бы ещё
  погонял ffmpeg на подручных роликах (вдруг что сломалось).

-- 
 Григорий Баталов,
 программист
 ЗАО "Ланит-Терком"
----------- следущая часть -----------
--- ffmpeg.spec.orig	2004-05-31 11:31:15 +0400
+++ ffmpeg.spec	2005-12-07 14:43:04 +0300
@@ -8,7 +8,7 @@
 
 Name: ffmpeg
 Version: 0.4.8
-%define release alt6
+%define release alt7
 
 %ifdef cvsdate
 Release: %{release}cvs%cvsdate
@@ -28,6 +28,9 @@
 Source: %name-%cvsdate.tar.bz2
 %endif
 
+# fix for heap buffer overflow (backported from FFmpeg CVS)
+Patch: ffmpeg-0.4.8-fix-overflow.patch
+
 # Automatically added by buildreq on Mon May 31 2004
 BuildRequires: XFree86-devel XFree86-libs esound freetype2-devel imlib2-devel libSDL-devel libfaac-devel libfaad-devel liblame-devel libogg-devel libvorbis-devel tetex-core zlib-devel
 
@@ -82,6 +85,7 @@
 %setup -q -n %name-%cvsdate
 %endif
 
+%patch -p0
 %__subst 's,\-lImlib2,`imlib2-config --libs`,' configure
 
 %build
@@ -135,6 +139,9 @@
 %doc doc/{TODO,*.txt,*.html}
 
 %changelog
+* Wed Dec 07 2005 Grigory Batalov <bga на altlinux.ru> 0.4.8-alt7cvs20040520
+- fix for heap buffer overflow (backported from FFmpeg CVS)
+
 * Mon May 31 2004 Yuri N. Sedunov <aris на altlinux.ru> 0.4.8-alt6cvs20040520
 - new cvs snapshot to build vlc-0.7.2
 
----------- следущая часть -----------
--- libavcodec/utils.c.orig	2005-12-07 13:41:00 +0300
+++ libavcodec/utils.c	2005-12-07 13:53:19 +0300
@@ -200,27 +200,11 @@
         buf->last_pic_num= *picture_number;
     }else{
         int h_chroma_shift, v_chroma_shift;
-        int s_align, pixel_size;
+        int s_align, pixel_size, size[3];
+        AVPicture picture;
         
         avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
         
-        switch(s->pix_fmt){
-        case PIX_FMT_RGB555:
-        case PIX_FMT_RGB565:
-        case PIX_FMT_YUV422:
-            pixel_size=2;
-            break;
-        case PIX_FMT_RGB24:
-        case PIX_FMT_BGR24:
-            pixel_size=3;
-            break;
-        case PIX_FMT_RGBA32:
-            pixel_size=4;
-            break;
-        default:
-            pixel_size=1;
-        }
-
         avcodec_align_dimensions(s, &w, &h);
 #if defined(ARCH_POWERPC) || defined(HAVE_MMI) //FIXME some cleaner check
         s_align= 16;
@@ -232,21 +216,40 @@
             w+= EDGE_WIDTH*2;
             h+= EDGE_WIDTH*2;
         }
+
+        avpicture_fill(&picture, NULL, s->pix_fmt, w, h);
+        pixel_size= picture.linesize[0]*8 / w;
+//av_log(NULL, AV_LOG_ERROR, "%d %d %d %d\n", (int)picture.data[1], w, h, s->pix_fmt);
+        assert(pixel_size>=1);
+            //FIXME next ensures that linesize= 2^x uvlinesize, thats needed because some MC code assumes it
+        if(pixel_size == 3*8)
+            w= ALIGN(w, s_align<<h_chroma_shift);
+        else
+            w= ALIGN(pixel_size*w, s_align<<(h_chroma_shift+3)) / pixel_size;
+        size[1] = avpicture_fill(&picture, NULL, s->pix_fmt, w, h);
+        size[0] = picture.linesize[0] * h;
+        size[1] -= size[0];
+        if(picture.data[2])
+            size[1]= size[2]= size[1]/2;
+        else
+            size[2]= 0;
         
         buf->last_pic_num= -256*256*256*64;
+        memset(buf->base, 0, sizeof(buf->base));
+        memset(buf->data, 0, sizeof(buf->data));
 
-        for(i=0; i<3; i++){
+        for(i=0; i<3 && size[i]; i++){
             const int h_shift= i==0 ? 0 : h_chroma_shift;
             const int v_shift= i==0 ? 0 : v_chroma_shift;
 
-            //FIXME next ensures that linesize= 2^x uvlinesize, thats needed because some MC code assumes it
-            buf->linesize[i]= ALIGN(pixel_size*w>>h_shift, s_align<<(h_chroma_shift-h_shift)); 
+            buf->linesize[i]= picture.linesize[i];
 
-            buf->base[i]= av_mallocz((buf->linesize[i]*h>>v_shift)+16); //FIXME 16
+            buf->base[i]= av_mallocz(size[i]+16); //FIXME 16
             if(buf->base[i]==NULL) return -1;
-            memset(buf->base[i], 128, buf->linesize[i]*h>>v_shift);
-        
-            if(s->flags&CODEC_FLAG_EMU_EDGE)
+            memset(buf->base[i], 128, size[i]);
+
+            // no edge if EDEG EMU or not planar YUV, we check for PAL8 redundantly to protect against a exploitable bug regression ...
+            if((s->flags&CODEC_FLAG_EMU_EDGE) || (s->pix_fmt == PIX_FMT_PAL8) || !size[2]) 
                 buf->data[i] = buf->base[i];
             else
                 buf->data[i] = buf->base[i] + ALIGN((buf->linesize[i]*EDGE_WIDTH>>v_shift) + (EDGE_WIDTH>>h_shift), s_align);


Подробная информация о списке рассылки Security-team