[UNIX] Multiple Heap Overflows in Xine-Lib



The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html

- - - - - - - - -



Multiple Heap Overflows in Xine-Lib
------------------------------------------------------------------------


SUMMARY

The xine free multimedia player suffers from a number of vulnerabilities
ranging in severity. The worst of these vulnerabilities results in
arbitrary code execution and the least, in unexpected process termination.

Five heap buffer overflows exist in parsing of real audio files, id3 tags,
qt mov files, and matroska headers which all can result in
arbitrary code execution. Three additional heap buffer overflows occur in
mng, mod, and real handling which are potentially exploitable.

Seven additional issues were identified in the input plugins as well as
the real, qt, and matroska demuxers which result in process termination or
memory corruption that may have wider implications.

DETAILS

Vulnerable Systems:
* xine-lib version 1.1.14 and prior

Immune Systems:
* xine-lib version 1.1.15

Exploitable heap buffer overflows
In demux_qt.c, function parse_moov_atom() reads in metadata atom sizes as
supplied from the user. If the size of a metadata atom, like artist, is
0xf, the resulting atom size is 0. Prior to reading in the atom string,
xine_malloc() is called with this undersized value resulting in an
allocation of 1 byte. The allocated space is then the target of a strncpy.
When called, strncpy() is supplied the atom string size minus 1. This
wraps the value to UINT_MAX making strncpy to copy until a (NUL) 0x00 byte
is seen. This results in a highly controllable heap buffer overflow.

(fixed in 1.1.15)

In demux_matroska.c, the function parse_block_group() is vulnerable to a
heap overflow through the abuse of ebml element length values. In
particular, when processing MATROSKA_ID_CL_BLOCK the element length is
passed into read_block_data(). read_block_data() treats the length as a
signed 32-bit int and passes it to alloc_block_data(). This function
performs a simple check: if the current block_data_size is less than the
supplied length, then it re/malloc()s the given length. This buffer and
the length is then passed in to the input plugin's read() function. This
opens up a few avenues of attack. The first is since the allocation is
unchecked, a NULL value may be read() over - resulting in a segmentation
fault in most cases. However, if the CL_BLOCK is processed twice, the
first can specify a valid size and provide valid data. However, a second
CL_BLOCK can give a negative size. This will cause alloc_block_data() to
not reallocate the buffer, but the input plugin will still be given the
user-supplied length for reading. This will result in a heap buffer
overflow. In particular, if the source data file ends within a reasonable
size, the heap buffer can be overwritten without writing past the
available pages to the process. The read() function will then return an
error indicating failure. If the length given was -1, then
read_block_data() will still evaluate the read() as success and continue
on as if nothing happened. However, if another negative value is used, the
process will return failure up the stack.

(probably not fixed in 1.1.15; len changed to size_t but -1 will still
match 0xffffffff when leaving read. fix not confirmed.)

In demux_real.c, real_parse_audio_specific_data() uses a user-supplied
height (codec_data_length) as the divisor when calculating frame_size. It
may be zero, resulting in a divide by zero. In addition, there is not
check for successful frame_buffer allocation which may result in NULL
dereferences later. In addition to a divide by zero, if sps is 0 and w and
h are both 65535 (they are read as 16-bit ints), then the frame_size will
overflow resulting in an underallocation. If sps is non-zero, it is also
possible to incorrectly calculate the frame_size. It appears that this is
exploitable. In demux_real_send_chunk(), if the audio type is
BUF_AUDIO_COOK, ..._ATRK, ..._28_8, or ..._SIPRO, the frame buffer will be
populated as the width and height are traversed. This allows for a direct
overflow which is somewhat controllable. In particular, the easiest way to
limit the total length is to truncate the source data after overflowing
the buffer sufficiently. However, there are other tweaks which allow fine
grain control. COOK and ATRK both use 'sps' to control the increment read
while SIPRO uses the width (w), and 28_8 uses the 'cfs' -- all of these
values user-supplied.

(malloc failure check added in 1.1.15; some changes were made but
overflows still seem likely due to sign issues with pos/fs)

In demux_realaudio.c, open_ra_file() calculates the frame size using two
(or three, depending) values with a maximum of 65535 each. When three
values are used, the frame size calculation may overflow. This allows for
a similar attack described in above in 1-C. In addition, the
xine_xmalloc() call is unchecked so even a failed allocation would slip
through and result in a crash.

(1.1.15 changes frame_size to a size_t but doesn't appear to fix the
numeric overflow)

In id3.c, id3v23_interp_frame() allocates a buffer for reading the frame
using the user-supplied size and adds 1. This allows the size to wrap to 0
creating an empty, but successful, malloc() allocation. Next, read will be
called using the original size. Depending on the plugin, this will either
read until the data ends/a segfault occurs or it will trigger the
negative-length mentioned bugs. If it is the input_file, then the buffer
can be overflowed and the amount controlled by the remaining file size.
(Note, the over-sized value is read in at 566 and bypasses the checks n
569 since the value will wrap.)

(fixed in 1.1.15)

Potentially exploitable
In demux_mng.c, mymng_process_header() accepts a width and height as
arguments. These are then multiplied by 3 for image allocation. Not only
is the integer operation unchecked, but the allocation is also unchecked
for failure. The source of the width and height was not determined, thus
the 'potential' rating.

(missing malloc failure check fixed in 1.1.15)

In demux_mod.c, open_mod_file() relies on the input plugin to supply a
filesize. This size is then used in malloc() without checking to see if
the allocation failed. With input types like input_net.c, this will result
in a 0-sized allocation, but with input_file.c a large, or invalid, file
entry would be required to cause trouble. However, filesize may also come
from plugins like input_http.c. In this case, the filesize is supplied by
the server which provides an easier attack surface. For example, if the
filesize is -1, the read() check will pass (if an 'error' occurs), and the
negative value will be passed into ModPlug_Load. However, the libmod code
was not reviewed and a large, or negative, content size may trigger the
input plugin systemic read() issues discussed below.

(missing malloc failure check fixed in 1.1.15)

In demux_real.c, real_parse_mdpr() uses a stream_name_size supplied by the
user. This size is represented as a char type. This size is then used in
an allocation where 1 is added, presumably for the NUL character. If the
char size is 255 (or -1), then when 1 is added, the value will wrap to 0.
This will result in an allocation of size 0. After allocation, a memcpy()
occurs of the user-supplied data. If char is signed (default), then this
will result in a segmentation fault as 0xff will be extended to 0xffffffff
and memcpy() will read and/or write out of bounds. This affects mime_type
and mime_type_size as well. In addition, the type_specific_data allocation
is not checked for failure not for a zero-valued size, an unexpected
process termination issue.

(fixed in 1.1.15. stream_name_size is now size_t)

Unexpected process termination and other issues
Many of the input plugins improperly handle negative-valued lengths during
read function calls. In most cases, the length is handled as an off_t.
(Even though this may be 64-bit, it is still signed and type promotion
will usually keep -1 a -1.) Depending on the read state, a check for a
preview may be done. If so, this will result in the length being used to
memcpy() data from a preview buffer. In general, this will result in a
crash. Many of the input plugins are affected: - input_file.c,
input_net.c, input_smb.c, input_http.c, ... In some cases, even a 0 size
may result in misbehaving. In input_http.c, after the preview checks, if
the supplied length (nlen) is 0, the length used (n) will become negative
after: 446: n = nlen - num_bytes; In all of these cases, buffer overflows
are completely possible as well as out of bounds reads. If the source data
is attacker controlled, like a file, http response, and so one, then it
may be possible to use these functions to aid a targeted heap buffer
overflow. 1-B is a good example where the negative value allows the
attacker to exploit allocation as opposed to just causing a crash.

(not directly addressed in 1.1.15)

In demux_qt.c, parse_reference_atom() takes a user-supplied size for a
string of an RDRF_ATOM. If the current_atom_size and string_size are both
supplied as 0xffffffff, then code will allocate a buffer of 1 (or some
value offset by the url text). This will result in an unbounded memcpy(),
most likely resulting in a process crash. (If SIGSEGV signals are trapped
with subsequent heap access, this may be exploitable.)

(not addressed in 1.1.15)

In demux_matroska.c, the handling of the MATROSKA_ID_TR_CODECPRIVATE track
entry element relies on a user-supplied length for allocation and no
failure check is present prior to use. Given that the buffer is 0, this
will most likely result in a SIGSEGV signal. However, if there is no data
to read from the file, this will result in the read() function returning
-1 (i.e., with input_file). The read return value is compared against a
64-bit cast of the element size (-1 -> -1) in ebml.c:190, but type
promotion should make the -1 values equal. ebml_read_elm_data will return
successfully, and xine-lib will continue executing. In most cases, it
appears the size and/or NULL allocation will be ignored. But in other
cases, it will be directly accessed (fourcc) or the size used in
allocation (MPEG4). The case of the MPEG4 codec, a malloc() is based on
the supplied length plus a sizeof() which will overflow. Unfortunately,
this may only corrupt the heap bookkeeping a small amount
(demux_matroska.c:1308) prior to a memcpy() which will result in a
segmentation fault.

(not directly addressed in 1.1.15)

In demux_qt.c, a compressed MOV (CMOV_ATOM) may result in an out of bounds
read by zlib during inflation. In particular, a small moov_atom_size will
underflow when avail_in is set (demux_qt.c:2191). This will allow
inflate() to read well past the available data. Given that the size of the
output buffer is also user-supplied (2192), enough space can be allocated
to allow zlib to either return with an error or cause the process to
crash.

(not addressed in 1.1.15)

In demux_qt.c, when allocating STSD_ATOM atoms, calloc() is used with a
user-supplied count. In general, this is safe, but if the count is 0,
calloc() will still return successfully (on many systems). This may result
in unexpected behavior. In this case, it may result in the pointer being
used as the media_id (with MEDIA_VIDEO) which in turn makes it into the
trak->properties. This may result in out of bounds memory accesses, heap
corruption, or worse.

(not addressed in 1.1.15)

In demux_real.c, real_parse_headers() reads a chunk size and type from the
user. If the type is PROP_TAG, MDPR_TAG, or CONT_TAG, then the chunk size
is used in an allocation. Allocation failure is unchecked and an immediate
read may result in a segmentation fault. In addition, the chunk_size is
used as the data_chunk_size. This is used to calculate the normpos which
is used to output video. Given that this wasn't analyzed further, it's
unclear if additional exploitable conditions exist.

(not addressed in 1.1.15)

In demux_real.c, real_parse_headers() uses a user-supplied length to
reindex into an allocated buffer (523, 524). The length is unchecked and
may point outside of the allocated region. This will result in an out of
bounds read which may result in a crash. In addition, the other accesses
of of type_specific_data do not ensure that it is of sufficient size. Line
512 may read past the allocated space. Line 520 may pre-index the buffer
if the specific_len is less than 5. Line 527 may also read past the end of
the buffer, and so on.

(not addressed in 1.1.15)


ADDITIONAL INFORMATION

The information has been provided by <mailto:redpig@xxxxxxxxx> Will
Drewry.
The original article can be found at:
<http://www.ocert.org/analysis/2008-008/analysis.txt>
http://www.ocert.org/analysis/2008-008/analysis.txt



========================================


This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@xxxxxxxxxxxxxx
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@xxxxxxxxxxxxxx


====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



Relevant Pages

  • Intuit Help System Protocol URL Heap Corruption and Memory Leak
    ... Intuit Help System Protocol URL Heap Corruption and Memory Leak ... URL-decoded copy in a separate heap buffer. ... One formidable complication in exploiting the overflow is that, ... Allocation of the overflowable buffer ...
    (Bugtraq)
  • [patch 1/2] x86, ptrace: support pebs in ds.c
    ... BTS and PEBS recording. ... This used to be implicit on a change of the requested buffer size. ... * guarding context and buffer memory allocation. ...
    (Linux-Kernel)
  • [patch 1/2] x86, ptrace: support pebs in ds.c
    ... BTS and PEBS recording. ... This used to be implicit on a change of the requested buffer size. ... * guarding context and buffer memory allocation. ...
    (Linux-Kernel)
  • [patch 1/1] x86, ptrace: PEBS support
    ... BTS and PEBS recording. ... * - buffer overflow handling ... * guarding context and buffer memory allocation. ...
    (Linux-Kernel)
  • Re: Proposed addition of malloc_size_np()
    ... Since malloc_sizeis defined on at least one platform to return the requested size, maybe a name like malloc_allocated_sizewould help avoid that confusion, and make it clear that the consumer is getting back a commitment and not a hint for future realloc(), etc. ... Suppose that we are about to write to a string that we know is malloced, and we want to be sure that we aren't overflowing the allocated buffer. ... We can store that information, or we could just query the size. ... However, unless there is a way of getting the size of each allocation, I don't know how much to subtract from the count for realloc/free calls. ...
    (freebsd-arch)