»Multiple vulnerabilities in Ogg Tremor and Vorbis
After running across a number of stack overflows in the older low-mem branch that don't longer exist in (tremor) trunk, a revisit to the codebase revealed a number of remaining vulnerabilities.
BackgroundOgg Vorbis and Tremor are libraries for decoding Ogg media files. Tremor does so without relying on floating point unit support.
DetailsBelow are some unrefined findings. Monty(@xiph.org) was kind enough to take on analysis and patching when I reported preliminary information. In addition, various Linux vendors also contributed analysis and testing results, like Tomas Hoger of Redhat. Thanks!! So, the basic findings --
Tremor -- = NULL pointer dereference + Looks like it is related to incorrectly checking for valid data after valid headers are read - Samples: 010.ogg 011.ogg * oggpack_readinit (b=0xffffcb8c, r=0x0) at bitwise.c:69: b->headptr=b->head->buffer->data+b->head->begin; = Divide by zero + The dimension of the codebook are used as the divisor without checking to see if it is greater than zero - Samples: 002.ogg * _book_maptype1_quantvals (b=0x0) at sharedbook.c:150: int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim); = Divide by zero + partitions_per_word is zero and it SIGFPEs - Samples: 014.ogg * res012.c:278:res2_inverse.c:() int partwords=(partvals+partitions_per_word-1)/partitions_per_word; = Integer overflow leading to a heap overflow + This occurs when partvals is derived from the supplied partition count and dimensions is moderately large. - No sample * res012.c:157-160 Vorbis -- = Infinite loop and/or crashing due to stack corruption + Looks to be related to the inline math functions. After the line below, b and vals are the same value. (dim==0 issue) - Samples: 002.ogg * _book_maptype1_quantvals (b=0x8065f20) at sharedbook.c:151: long vals=floor(pow((float)b->entries,1.f/b->dim)); = Additional corruption in pre-1.0 Vorbis + Tomas and Monty nailed this down to _make_decode_tree() - Samples: 003.ogg, 004.ogg, 005.ogg Vorbis and Tremor -- = Integer overflow in the computation of quantvals and of the space required for quantlist. + A codebook has 16-bit dimensions and 24-bit entries. quantvals, the size of quantlist, is calculated by mutliplying them together. This can easily overflow the unsigned 32-bit integer quantvals is stored in. In addition, on ogg_malloc() of the quantlist, quantvals is multiplied times the size of a quantlist entry (4). This is another integer overflow. If only the second case is attacked, a straight heap overflow occurs in the subsequent for loop. If the first one is attacked, then later out of bounds reads occur in decoding. Note, the map type must be 2 for this to be reachable. It's also worth noting that the range of the entries in the quantlist may be up to 4 bits + 1. - Samples: maptype2.ogg Tremor/lowmem -- Most of the findings above in Tremor along with a large number of potentially exploitable stack buffer overflows. Sample 001.ogg is good example of the codebook stack buffer overflow.All of the samples can be found here. [Please go easy on my bandwidth!]
ImpactThe impact of these vulnerabilities largely depends on the context of use. Denial of service attacks are quite simple and there is potential for successful code execution.
RemediationUpgrade to the latest patched versions supplied by your vendor.
Testing methodologyTesting was primarily done using fuzz and flayer. Initial testing of tremor was handled with a simple test harness built on the supplied example_ivorbisfile.c. Purely random data sampled from /dev/urandom was fed to the example application. With flayer, clearly blocking checks were bypassed (memcmp for OggS and the page checksum test).
With the basic checks successfully removed (without recompilation, etc), fuzz was used against an existing, valid Ogg file applying the "Mexican Wave" byte-modification algorithm.
Once the wave had reached the codebook headers, numerous crashes occurred. With samples in tow, valid checksums were inserted (by snooping the test in gdb with a debugging build). The backtraces were then followed, and the vectors of the attack isolated. Once I saw the behavior in the codebook functions, I modified libvorbis to generate codebook entries based on environment variables (getenv()). Using the modifying library, I created a number of samples with unlikely and unchecked values. In some cases, the encoder would not be able to handle these cases and modifications were made dynamically during encoding using gdb.
The results can be found here.