Description of problem: Problem is triggered with fuzzed .ogg file, that was created with zzuf (http://sam.zoy.org/zzuf/). Let us see what happens: (gdb) $ gdb totem GNU gdb Red Hat Linux (6.5-15.fc6rh) Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu"...(no debugging symbols found) Using host libthread_db library "/lib64/libthread_db.so.1". (gdb) break ogg_stream_pagein Function "ogg_stream_pagein" not defined. Breakpoint 1 (ogg_stream_pagein) pending. (gdb) run lol-gstreamer.ogg [Thread debugging using libthread_db enabled] [New Thread 46912496390112 (LWP 28628)] [New Thread 1084229952 (LWP 28632)] ** (totem:28628): CRITICAL **: bacon_video_widget_can_direct_seek: assertion `bvw != NULL' failed ** (totem:28628): CRITICAL **: bacon_video_widget_can_direct_seek: assertion `bvw != NULL' failed [New Thread 1094719808 (LWP 28633)] Breakpoint 2 at 0x2aaab5a04b76: file framing.c, line 674. Pending breakpoint "ogg_stream_pagein" resolved [New Thread 1105209664 (LWP 28634)] [Switching to Thread 1105209664 (LWP 28634)] Breakpoint 2, ogg_stream_pagein (os=0xbe0218, og=0x41e01f10) at framing.c:674 674 unsigned char *header=og->header; (gdb) c Breakpoint 2, ogg_stream_pagein (os=0xbe0218, og=0x41e01f10) at framing.c:674 674 unsigned char *header=og->header; (gdb) until 736 ogg_stream_pagein (os=0xbe0218, og=0x41e01f10) at framing.c:739 739 if(continued){ (gdb) print bodysize $1 = 30 (gdb) l 734 } 735 } 736 737 /* are we a 'continued packet' page? If so, we may need to skip 738 some segments */ 739 if(continued){ 740 if(os->lacing_fill<1 || 741 os->lacing_vals[os->lacing_fill-1]==0x400){ 742 bos=0; 743 for(;segptr<segments;segptr++){ (gdb) 744 int val=header[27+segptr]; 745 body+=val; 746 bodysize-=val; 747 if(val<255){ 748 segptr++; 749 break; 750 } 751 } 752 } 753 } (gdb) 754 755 if(bodysize){ 756 _os_body_expand(os,bodysize); 757 memcpy(os->body_data+os->body_fill,body,bodysize); 758 os->body_fill+=bodysize; 759 } 760 761 { 762 int saved=-1; 763 while(segptr<segments){ (gdb) until 755 ogg_stream_pagein (os=0xbe0218, og=0x41e01f10) at framing.c:755 755 if(bodysize){ (gdb) print bodysize $2 = -57 (gdb) c Program received signal SIGSEGV, Segmentation fault. 0x00002aaab5a04f16 in ogg_stream_pagein (os=0xbe0218, og=0x41e01f10) at framing.c:757 757 memcpy(os->body_data+os->body_fill,body,bodysize); (gdb) print (size_t)bodysize $3 = 18446744073709551559 (gdb) At line 741 signed bodysize gets negative, but as memcpy on line 757 expects unsigned size_t, it tries to copy data from far beyond the buffer boundary resulting in a heap corruption and out-of-bound read that triggers a segmentation violation. I can not say whether this could be exploited, but hardly with this big bodysize. I am no libogg expert and can't say how much can the bodysize be decremented. Just in case it could be modified to some more sensible value, the heap overflow could result in arbitrary code execution. Version-Release number of selected component (if applicable): libogg-1.1.3-2 How reproducible: Allways. Steps to Reproduce: 1. Open the fuzzed file with the player that utilizes libogg. Totem could be an example. The file is attached to this report. Actual results: The player receives SIGSEGV. Expected results: We expected it to receive SIGSEGV, didn't we? :) Probably it should complain loudly instead. Additional info: Today it snowed for the first time this year in Brno.
Created attachment 146299 [details] libogg ogg_stream_pagein() heap corruption reproducer
Here's debian bug. They claim to have that fixed in gstreamer. Weird. I still believe this is an libogg bug. Adding ajackson to CC: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=407004
I'm spent quite a bit of time on this flaw, it should not be considered a security flaw. The problem here is that the memcpy causes a heap overflow, but the heap data which gets written is not controllable by an attacker. The input buffer (os->body_data+os->body_fill) is of considerably larger size than the output buffer, which means random memory is written onto the heap, causing the crash. If someone believes my analysis to be in error, please restore the Security keyword.
I came up with a similar analysis. Sent it to Lubomir but seems like he forgot to paste here. Anyway, here it is: First, the fix in gstreamer makes sense, because apparently the crash is caused by an invalid input stream to libogg. So that's one fix. The crash is another bug, in libogg. The problem is that libogg doesn't seem to handle errors gracefully. So, while we can patch this one place to bail out if bodysize becomes negative, there are probably many many other places that can cause a crash with an invalid input stream. As for exploitablity, I don't think it's an issue, because: 1) val can be at most 255, so you need quite a lot of bytes in the header to bring bodysize down to a reasonable overflow size. 2) In Fedora, our heap is not executable. 3) Before the memcpy, it does a _os_body_expand which in turn does a realloc(). So, it either crashes in realloc() failing to allocate memory, or it will allocate the buffer and killed by kernel OOM handler when copying data over. If it survives the copy and does not crash, the buffer is legitimately allocated memory. So, no overflows here.
No security impact, I do not insist on fixing, I'll leave it open though. Feel free to WONTFIX it.
On request of Behdad, I'm helping out with ogg / vorbis / theora bugs. Closing this as WONTFIX as suggested.